Source code for validations_libs.callback_plugins.vf_validation_output

# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pprint

from ansible import constants as C
from ansible.plugins.callback import CallbackBase


FAILURE_TEMPLATE = """\
Task '{}' failed:
Host: {}
Message: {}
"""

WARNING_TEMPLATE = """\
Task '{}' succeeded, but had some warnings:
Host: {}
Warnings: {}
"""

DEBUG_TEMPLATE = """\
Task: Debug
Host: {}
{}
"""


[docs]def indent(text): '''Indent the given text by four spaces.''' return ''.join(' {}\n'.format(line) for line in text.splitlines())
# TODO(shadower): test with async settings
[docs]class CallbackModule(CallbackBase): CALLBACK_VERSION = 2.0 CALLBACK_TYPE = 'stdout' CALLBACK_NAME = 'validation_output' def __init__(self, display=None): super(CallbackModule, self).__init__(display)
[docs] def print_failure_message(self, host_name, task_name, results, abridged_result): '''Print a human-readable error info from Ansible result dictionary.''' def is_script(results): return ('rc' in results and 'invocation' in results and 'script' in results._task_fields['action'] and '_raw_params' in results._task_fields['args']) display_full_results = False if 'rc' in results and 'cmd' in results: command = results['cmd'] # The command can be either a list or a string. # Concat if it's a list: if type(command) == list: command = " ".join(results['cmd']) message = "Command `{}` exited with code: {}".format( command, results['rc']) # There may be an optional message attached to the command. # Display it: if 'msg' in results: message = message + ": " + results['msg'] elif is_script(results): script_name = results['invocation']['module_args']['_raw_params'] message = "Script `{}` exited with code: {}".format( script_name, results['rc']) elif 'msg' in results: message = results['msg'] else: message = "Unknown error" display_full_results = True self._display.display( FAILURE_TEMPLATE.format(task_name, host_name, message), color=C.COLOR_ERROR) stdout = results.get('module_stdout', results.get('stdout', '')) if stdout: print('stdout:') self._display.display(indent(stdout), color=C.COLOR_ERROR) stderr = results.get('module_stderr', results.get('stderr', '')) if stderr: print('stderr:') self._display.display(indent(stderr), color=C.COLOR_ERROR) if display_full_results: print( "Could not get an error message. Here is the Ansible output:") pprint.pprint(abridged_result, indent=4) warnings = results.get('warnings', []) if warnings: print("Warnings:") for warning in warnings: self._display.display("* %s " % warning, color=C.COLOR_WARN) print("")
[docs] def v2_playbook_on_play_start(self, play): pass # No need to notify that a play started
[docs] def v2_playbook_on_task_start(self, task, is_conditional): pass # No need to notify that a task started
[docs] def v2_runner_on_ok(self, result, **kwargs): host_name = result._host task_name = result._task.get_name() task_fields = result._task_fields results = result._result # A dict of the module name etc. self._dump_results(results) warnings = results.get('warnings', []) # Print only tasks that produced some warnings: if warnings: for warning in warnings: warn_msg = "{}\n".format(warning) self._display.display(WARNING_TEMPLATE.format(task_name, host_name, warn_msg), color=C.COLOR_WARN) if 'debug' in task_fields['action']: output = "" if 'var' in task_fields['args']: variable = task_fields['args']['var'] value = results[variable] output = "{}: {}".format(variable, str(value)) elif 'msg' in task_fields['args']: output = "Message: {}".format( task_fields['args']['msg']) self._display.display(DEBUG_TEMPLATE.format(host_name, output), color=C.COLOR_OK)
[docs] def v2_runner_on_failed(self, result, **kwargs): host_name = result._host task_name = result._task.get_name() result_dict = result._result # A dict of the module name etc. abridged_result = self._dump_results(result_dict) if 'results' in result_dict: # The task is a list of items under `results` for item in result_dict['results']: if item.get('failed', False): self.print_failure_message(host_name, task_name, item, item) else: # The task is a "normal" module invocation self.print_failure_message(host_name, task_name, result_dict, abridged_result)
[docs] def v2_runner_on_skipped(self, result, **kwargs): pass # No need to print skipped tasks
[docs] def v2_runner_on_unreachable(self, result, **kwargs): host_name = result._host task_name = result._task.get_name() results = {'msg': 'The host is unreachable.'} self.print_failure_message(host_name, task_name, results, results)
[docs] def v2_playbook_on_stats(self, stats): def failed(host): _failures = stats.summarize(host).get('failures', 0) > 0 _unreachable = stats.summarize(host).get('unreachable', 0) > 0 return (_failures or _unreachable) hosts = sorted(stats.processed.keys()) failed_hosts = [host for host in hosts if failed(host)] if hosts: if failed_hosts: if len(failed_hosts) == len(hosts): print("Failure! The validation failed for all hosts:") for failed_host in failed_hosts: self._display.display("* %s" % failed_host, color=C.COLOR_ERROR) else: print("Failure! The validation failed for hosts:") for failed_host in failed_hosts: self._display.display("* %s" % failed_host, color=C.COLOR_ERROR) print("and passed for hosts:") for host in [h for h in hosts if h not in failed_hosts]: self._display.display("* %s" % host, color=C.COLOR_OK) else: print("Success! The validation passed for all hosts:") for host in hosts: self._display.display("* %s" % host, color=C.COLOR_OK) else: print("Warning! The validation did not run on any host.")