From 6d1c0bdfb6d94e063f0c9154bbc20e99afedcd6d Mon Sep 17 00:00:00 2001 From: Chris Ladd Date: Tue, 25 Aug 2020 09:58:38 -0700 Subject: [PATCH] INTERNAL: Foundational plumbing for future Ansible modules --- common/src/stack/ansible/Makefile | 10 ++++ common/src/stack/ansible/etc/ansible.cfg | 2 + .../ansible/plugins/module_utils/stacki.py | 50 +++++++++++++++++++ .../ansible/plugins/modules/.placeholder | 0 .../test-suites/integration/tests/conftest.py | 21 ++++++++ 5 files changed, 83 insertions(+) create mode 100644 common/src/stack/ansible/plugins/module_utils/stacki.py create mode 100644 common/src/stack/ansible/plugins/modules/.placeholder diff --git a/common/src/stack/ansible/Makefile b/common/src/stack/ansible/Makefile index 21f39eeb9..fee2d220e 100644 --- a/common/src/stack/ansible/Makefile +++ b/common/src/stack/ansible/Makefile @@ -23,4 +23,14 @@ install:: mkdir -p $(ROOT)/opt/stack/ansible/plugins/callback $(INSTALL) -m0644 plugins/callback/failure_report.py $(ROOT)/opt/stack/ansible/plugins/callback/ + # Install the module_utils plugin + mkdir -p $(ROOT)/opt/stack/ansible/plugins/module_utils + $(INSTALL) -m0644 plugins/module_utils/stacki.py $(ROOT)/opt/stack/ansible/plugins/module_utils/ + + # Install the modules + mkdir -p $(ROOT)/opt/stack/ansible/plugins/modules +ifneq ($(wildcard plugins/modules/*.py),) + $(INSTALL) -m0644 plugins/modules/*.py $(ROOT)/opt/stack/ansible/plugins/modules/ +endif + clean:: diff --git a/common/src/stack/ansible/etc/ansible.cfg b/common/src/stack/ansible/etc/ansible.cfg index 4fd306a56..760398bcd 100644 --- a/common/src/stack/ansible/etc/ansible.cfg +++ b/common/src/stack/ansible/etc/ansible.cfg @@ -2,6 +2,8 @@ nocows = True inventory_plugins = /opt/stack/ansible/plugins/inventory:~/.ansible/plugins/inventory:/usr/share/ansible/plugins/inventory callback_plugins = /opt/stack/ansible/plugins/callback:~/.ansible/plugins/callback:/usr/share/ansible/plugins/callback +library = /opt/stack/ansible/plugins/modules:~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules +module_utils = /opt/stack/ansible/plugins/module_utils:~/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils inventory = @stacki callback_whitelist = failure_report diff --git a/common/src/stack/ansible/plugins/module_utils/stacki.py b/common/src/stack/ansible/plugins/module_utils/stacki.py new file mode 100644 index 000000000..86d82f45e --- /dev/null +++ b/common/src/stack/ansible/plugins/module_utils/stacki.py @@ -0,0 +1,50 @@ +# @copyright@ +# Copyright (c) 2006 - 2020 Teradata +# All rights reserved. Stacki(r) v5.x stacki.com +# https://github.com/Teradata/stacki/blob/master/LICENSE.txt +# @copyright@ + +import json +import subprocess + + +class StackCommandError(Exception): + """Exception raised for errors running a stack command.""" + + def __init__(self, message): + self.message = message + + +def run_stack_command(command, args=None): + """Runs a stack command, returning StackCommandError if there is an error.""" + + # Create our command to run + command_args = ["/opt/stack/bin/stack"] + command_args.extend(command.replace(".", " ").split()) + if args: + command_args.extend(args) + command_args.append("output-format=json") + + try: + # Run the command, throwing a CalledProcessError if something goes wrong + result = subprocess.run( + command_args, capture_output=True, text=True, check=True + ) + except subprocess.CalledProcessError as e: + # Get the first line of the stderr + if e.stderr: + message = e.stderr.splitlines()[0] + else: + message = "error - unknown" + + # Raise an exception for the caller + raise StackCommandError(message) + + # Return the result as a dict + try: + data = json.loads(result.stdout) + except json.JSONDecodeError: + # Something invalid was returned, likely an empty string + data = [] + + return data diff --git a/common/src/stack/ansible/plugins/modules/.placeholder b/common/src/stack/ansible/plugins/modules/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/test-framework/test-suites/integration/tests/conftest.py b/test-framework/test-suites/integration/tests/conftest.py index e8e8db1c2..9df323b00 100644 --- a/test-framework/test-suites/integration/tests/conftest.py +++ b/test-framework/test-suites/integration/tests/conftest.py @@ -3,6 +3,7 @@ import json import os from pathlib import Path +import re import random import shutil import subprocess @@ -324,3 +325,23 @@ def _inner(path): return os.path.join("/export/test-suites/integration/files", path) return _inner + +@pytest.fixture +def run_ansible_module(host): + def _inner(module, **kwargs): + command = f"ansible localhost -o -m {module}" + if kwargs: + command += ' -a "' + command += " ".join(f"{k}={v}" for k,v in kwargs.items()) + command += '"' + + result = host.run(command) + + match = re.match(r"localhost \| (.*?) => (.*)$", result.stdout, flags=re.DOTALL) + if match: + result.status = match.group(1) + result.data = json.loads(match.group(2)) + + return result + + return _inner