diff --git a/etc/ansible-deploy.yaml b/etc/ansible-deploy.yaml index 6643467d..e9e38443 100644 --- a/etc/ansible-deploy.yaml +++ b/etc/ansible-deploy.yaml @@ -1,4 +1,7 @@ --- +callback_settings: + def_stdout_plugin: "yaml" + global_paths: work_dir: "/tmp" database_subdir: "databases" diff --git a/source/main.py b/source/main.py index f3385d15..79b837f9 100644 --- a/source/main.py +++ b/source/main.py @@ -77,7 +77,8 @@ def main(options: dict): runner.setup_ansible(selected_items["commit"], configuration.conf_dir) if options["lock"]: lock.lock_inventory(lockpath) - sequence_record_dict = runner.run_playitem(config, options, inv_file, lockpath, + sequence_record_dict = runner.run_playitem(configuration.conf["callback_settings"], + config, options, inv_file, lockpath, db_writer) if options["lock"]: lock.unlock_inventory(lockpath) diff --git a/source/modules/globalvars.py b/source/modules/globalvars.py index d2c1170b..d48e7250 100644 --- a/source/modules/globalvars.py +++ b/source/modules/globalvars.py @@ -12,3 +12,4 @@ } ANSIBLE_DEFAULT_CALLBACK_PLUGIN_PATH = '~/.ansible/plugins/callback:/usr/share/ansible/plugins/' \ 'callback' +SUPPORTED_STDOUT_CALLBACK_PLUGINS = ["json", "null", "yaml"] diff --git a/source/modules/misc/arguments.py b/source/modules/misc/arguments.py index f75db3c9..b6a788f5 100644 --- a/source/modules/misc/arguments.py +++ b/source/modules/misc/arguments.py @@ -1,6 +1,6 @@ """Module designed to handle all arguments""" from argparse import ArgumentParser, Namespace -from typing import Tuple +from typing import Optional, Tuple import os import sys import pkg_resources @@ -54,6 +54,9 @@ def create_parser() -> ArgumentParser: help='Print original messages to main log file.') parser.add_argument("--runner-raw-output", default=False, action="store_true", help='Print original messages in real time during runner execution.') + parser.add_argument("--runner-stdout", nargs=1, default=[None], metavar='STDOUT_PLUGIN', + help= + 'Provide name of runner stdout callback plugin you would like to use.') parser.add_argument("--self-setup", nargs=1, default=[None], metavar="LOCAL_SETUP_PATH", help='Setup repo outside of workdir in requested path. This option' ' applies only to infrastructures with allow_user_checkout enabled' @@ -129,6 +132,8 @@ def validate_rest_arguments(self, arguments: Namespace, print_end: str, print_fa options["no_color"] = arguments.no_color options["raw_output"] = arguments.runner_raw_output options["runner_raw_file"] = arguments.runner_raw_file + options["runner_stdout"] = self.validate_ansible_stdout_callback(arguments.runner_stdout, + print_fail, print_end) options["self_setup"] = os.path.abspath(arguments.self_setup[0]) if arguments.self_setup[0]\ else None options["stage"] = arguments.stage[0] @@ -136,3 +141,18 @@ def validate_rest_arguments(self, arguments: Namespace, print_end: str, print_fa options["task"] = arguments.task[0] return options + + @staticmethod + def validate_ansible_stdout_callback(stdout_plugin: str, print_fail: str, print_end: str + ) -> Optional[str]: + """Validate whether plugin (specified via --runner-stdout option) is supported""" + try: + lplugin = stdout_plugin[0].lower() + if lplugin in globalvars.SUPPORTED_STDOUT_CALLBACK_PLUGINS: + return lplugin + + print(f"{print_fail}[CRITICAL]: Unsupported runner stdout callback plugin!" + f"{print_end}") + sys.exit(57) + except AttributeError: + return None diff --git a/source/modules/runners/run.py b/source/modules/runners/run.py index bdd2c4fd..aaf86e91 100644 --- a/source/modules/runners/run.py +++ b/source/modules/runners/run.py @@ -119,7 +119,8 @@ def get_playitems(self, config: dict, options: dict): # TODO add check if everything was skipped return playitems - def run_playitem(self, config: dict, options: dict, inventory: str, lockpath: str, db_writer): + def run_playitem(self, callback_settings: dict, config: dict, options: dict, inventory: str, + lockpath: str, db_writer): """ Function implementing actual execution of runner [ansible-playbook or py.test] """ @@ -138,7 +139,8 @@ def run_playitem(self, config: dict, options: dict, inventory: str, lockpath: st for playitem in playitems: run_logger = self.set_runner_logging( options, playitem["name"], os.path.basename(inventory)) - command, command_env = self.construct_command(playitem, inventory, config, options) + command = self.construct_command(playitem, inventory, config, options) + command_env = self.construct_env(options, callback_settings) self.logger.debug("Running '%s'.", command) try: with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -209,7 +211,6 @@ def construct_command(self, playitem: str, inventory: str, config: dict, options command.append("--hosts=ansible://all") command.append("--junit-xml=junit_"+options['task']+'.xml') command.append("./"+playitem["file"]) - command_env = os.environ else: command = ["ansible-playbook", "-v", "-i", inventory, playitem["file"]] if options["limit"]: @@ -223,13 +224,20 @@ def construct_command(self, playitem: str, inventory: str, config: dict, options command.append(",".join(skip_tags)) if options["check_mode"]: command.append("-C") - command_env=dict(os.environ, ANSIBLE_STDOUT_CALLBACK="yaml", ANSIBLE_NOCOWS="1", - ANSIBLE_LOAD_CALLBACK_PLUGINS="1", LOG_PLAYS_PATH=self.log_path, - ANSIBLE_CALLBACKS_ENABLED="log_plays_adjusted,sqlite_deployer", - ANSIBLE_CALLBACK_PLUGINS=self.append_to_ansible_callbacks_path(), - SQLITE_PATH=self.db_path, SEQUENCE_ID=self.sequence_id) - return command, command_env + return command + + def construct_env(self, options: dict, callback_settings: dict) -> dict: + """Create final ansible environment from available variables""" + ansible_stdout_callback = options["runner_stdout"] if options["runner_stdout"]\ + else callback_settings["def_stdout_plugin"] + return dict( + os.environ, ANSIBLE_CALLBACKS_ENABLED="log_plays_adjusted,sqlite_deployer", + ANSIBLE_CALLBACK_PLUGINS=self.append_to_ansible_callbacks_path(), + ANSIBLE_LOAD_CALLBACK_PLUGINS="1", ANSIBLE_NOCOWS="1", LOG_PLAYS_PATH=self.log_path, + ANSIBLE_STDOUT_CALLBACK=ansible_stdout_callback, SQLITE_PATH=self.db_path, + SEQUENCE_ID=self.sequence_id + ) @staticmethod def append_to_ansible_callbacks_path():