Add tripleo dense formatting
This callback prints out a compact format that is generally in the following format: <UUID> | <state> | <task name> | <host|host ->delegated host> | [ <additional data> | ... ] <UUID>: 36 char Task UUID but may be omitted and would be 36 spaces. <state>: One of [TASK|CHANGED|START|OK|FATAL|WAITING|SKIPPED|INCLUDED|HANDLER]. This is a 10 character right aligned string. <task name>: free form task name text or a file name in the case of INCLUDED <host|host -> delgated host>: Will be one of: <hostname> <hostname> -> <delgated hostname> After the host is may be any number of additional data fields delimited by | and will contain a key=<data> format. Examples being: item={'cinder': {'project': 'service'}} result={"changed": true, "path": "/tmp/ansible.briga_ee", "state": "absent"} Warnings and deprecation sdo not have a task name or UUID so they generally formatted as: <blank> | WARNING | <warning text> <blank> | DEPRECATED | <warning text> Change-Id: Ifc18b7204aa47617d1b3277de2d8a781f0c9ea13
This commit is contained in:
parent
e3e80b8d43
commit
0a6a9f265f
|
@ -0,0 +1,288 @@
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from ansible import constants as C
|
||||||
|
from ansible.playbook.task_include import TaskInclude
|
||||||
|
from ansible.plugins.callback.default import CallbackModule as DefaultCallback
|
||||||
|
|
||||||
|
|
||||||
|
class CallbackModule(DefaultCallback):
|
||||||
|
|
||||||
|
def _output(self, msg, color):
|
||||||
|
if isinstance(msg, list):
|
||||||
|
output = ' | '.join(msg)
|
||||||
|
else:
|
||||||
|
output = msg
|
||||||
|
self._display.display(output, color=color)
|
||||||
|
|
||||||
|
def _get_host(self, result):
|
||||||
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
||||||
|
if (getattr(result, '_host', False)
|
||||||
|
and getattr(result._host, 'get_name', False)):
|
||||||
|
msg = '%s' % result._host.get_name()
|
||||||
|
elif (getattr(result, '_host', False)
|
||||||
|
and getattr(result._host, 'name', False)):
|
||||||
|
msg = '%s' % result._host.name
|
||||||
|
else:
|
||||||
|
msg = 'UNKNOWN'
|
||||||
|
if delegated_vars:
|
||||||
|
msg += ' -> %s' % delegated_vars['ansible_host']
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def _get_task_name(self, item=None):
|
||||||
|
name = ''
|
||||||
|
if item and getattr(item, 'name', False):
|
||||||
|
# item is a task
|
||||||
|
name = item.name
|
||||||
|
elif item and getattr(item, 'task_name', False):
|
||||||
|
name = item.task_name
|
||||||
|
elif item and getattr(item, '_task', False):
|
||||||
|
name = item._task.name
|
||||||
|
return name
|
||||||
|
|
||||||
|
def _get_uuid(self, item=None):
|
||||||
|
uuid = ''
|
||||||
|
|
||||||
|
if item and getattr(item, '_uuid', False):
|
||||||
|
# item is a task
|
||||||
|
uuid = item._uuid
|
||||||
|
elif item and getattr(item, '_task', False):
|
||||||
|
# item is a result (may not have a _task tho)
|
||||||
|
if getattr(item._task, '_uuid', False):
|
||||||
|
uuid = item._task._uuid
|
||||||
|
return '{:36}'.format(uuid)
|
||||||
|
|
||||||
|
def _get_state(self, state):
|
||||||
|
return '{:>10}'.format(state)
|
||||||
|
|
||||||
|
# TODO(mwhahaha): can this work for fatal/skipped/etc?
|
||||||
|
def _get_item_line(self, result, item=False):
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result)
|
||||||
|
]
|
||||||
|
host_str = self._get_host(result=result)
|
||||||
|
|
||||||
|
if (getattr(result, '_result', False)
|
||||||
|
and result._result.get('changed', False)):
|
||||||
|
line.append(self._get_state('CHANGED')),
|
||||||
|
line.append(self._get_task_name(result))
|
||||||
|
line.append(host_str)
|
||||||
|
color = C.COLOR_CHANGED
|
||||||
|
else:
|
||||||
|
if not self.display_ok_hosts:
|
||||||
|
return
|
||||||
|
line.append(self._get_state('OK'))
|
||||||
|
line.append(self._get_task_name(result))
|
||||||
|
line.append(host_str)
|
||||||
|
color = C.COLOR_OK
|
||||||
|
if item:
|
||||||
|
item_result = self._get_item_label(result._result)
|
||||||
|
# don't display if None
|
||||||
|
if item_result:
|
||||||
|
line.append('item=%s' % item_result)
|
||||||
|
return (line, color)
|
||||||
|
|
||||||
|
def _handle_warnings(self, result):
|
||||||
|
if not C.ACTION_WARNINGS:
|
||||||
|
return
|
||||||
|
if result.get('warnings', False):
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state('WARNING')
|
||||||
|
]
|
||||||
|
color = C.COLOR_WARN
|
||||||
|
for warn in result['warnings']:
|
||||||
|
msg = line + [warn]
|
||||||
|
self._output(msg, color)
|
||||||
|
del result['warnings']
|
||||||
|
if result.get('deprecations', False):
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state('DEPRECATED')
|
||||||
|
]
|
||||||
|
color = C.COLOR_DEPRECATE
|
||||||
|
# TODO(mwhahaha): handle deps correctly as they are a dict
|
||||||
|
for dep in result['deprecations']:
|
||||||
|
msg = line + [dep['msg']]
|
||||||
|
self._output(msg, color)
|
||||||
|
del result['deprecations']
|
||||||
|
|
||||||
|
def _task_line(self, task, state, color=None):
|
||||||
|
if not task.name:
|
||||||
|
return
|
||||||
|
line = [
|
||||||
|
self._get_uuid(task),
|
||||||
|
self._get_state(state),
|
||||||
|
self._get_task_name(task)
|
||||||
|
]
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_playbook_on_task_start(self, task, is_conditional):
|
||||||
|
self._task_line(task, 'TASK')
|
||||||
|
|
||||||
|
def v2_playbook_on_handler_task_start(self, task):
|
||||||
|
self._task_line(task, 'HANDLER')
|
||||||
|
|
||||||
|
def v2_playbook_on_cleanup_task_start(self, task):
|
||||||
|
self._task_line(task, 'CLEANUP')
|
||||||
|
|
||||||
|
# TODO(mwhahaha): Push fix into default for broken version of this
|
||||||
|
# function because get_option doesn't work when k is not in _plugin_options
|
||||||
|
def v2_runner_on_start(self, host, task):
|
||||||
|
if ('show_per_host_start' in self._plugin_options
|
||||||
|
and self.get_options('show_per_host_start')):
|
||||||
|
color = C.COLOR_HIGHLIGHT
|
||||||
|
line = [
|
||||||
|
self._get_uuid(task),
|
||||||
|
self._get_state('START'),
|
||||||
|
self._get_task_name(task=task),
|
||||||
|
host.name
|
||||||
|
]
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_runner_item_on_ok(self, result):
|
||||||
|
if isinstance(result._task, TaskInclude):
|
||||||
|
return
|
||||||
|
(line, color) = self._get_item_line(result, item=True)
|
||||||
|
self._handle_warnings(result._result)
|
||||||
|
if result._task.loop and 'results' in result._result:
|
||||||
|
self._process_items(result)
|
||||||
|
else:
|
||||||
|
if self._run_is_verbose(result):
|
||||||
|
line.append('result=%s' % self._dump_results(result._result))
|
||||||
|
self._display.display(' | '.join(line), color=color)
|
||||||
|
|
||||||
|
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||||
|
self._clean_results(result._result, result._task.action)
|
||||||
|
# TODO(mwhahaha): implement this one
|
||||||
|
self._handle_exception(result._result)
|
||||||
|
self._handle_warnings(result._result)
|
||||||
|
if result._task.loop and 'results' in result._result:
|
||||||
|
self._process_items(result)
|
||||||
|
else:
|
||||||
|
if ignore_errors:
|
||||||
|
status = 'IGNORED'
|
||||||
|
color = C.COLOR_SKIP
|
||||||
|
else:
|
||||||
|
status = 'FATAL'
|
||||||
|
color = C.COLOR_ERROR
|
||||||
|
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state(status),
|
||||||
|
self._get_task_name(result),
|
||||||
|
self._get_host(result=result)
|
||||||
|
]
|
||||||
|
item_result = self._get_item_label(result._result)
|
||||||
|
# don't display if None
|
||||||
|
if item_result:
|
||||||
|
line.append('item=%s' % item_result)
|
||||||
|
line.append('error=%s' % self._dump_results(result._result))
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_runner_item_on_failed(self, result):
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state('FATAL'),
|
||||||
|
self._get_task_name(result),
|
||||||
|
self._get_host(result=result)
|
||||||
|
]
|
||||||
|
color = C.COLOR_ERROR
|
||||||
|
item_result = self._get_item_label(result._result)
|
||||||
|
# don't display if None
|
||||||
|
if item_result:
|
||||||
|
line.append('item=%s' % item_result)
|
||||||
|
line.append('error=%s' % self._dump_results(result._result))
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_runner_on_ok(self, result):
|
||||||
|
if isinstance(result._task, TaskInclude):
|
||||||
|
return
|
||||||
|
(line, color) = self._get_item_line(result)
|
||||||
|
self._handle_warnings(result._result)
|
||||||
|
if result._task.loop and 'results' in result._result:
|
||||||
|
self._process_items(result)
|
||||||
|
else:
|
||||||
|
if self._run_is_verbose(result):
|
||||||
|
line.append('result=%s' % self._dump_results(result._result))
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_runner_item_on_skipped(self, result):
|
||||||
|
if not C.DISPLAY_SKIPPED_HOSTS:
|
||||||
|
return
|
||||||
|
self._clean_results(result._result, result._task.action)
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state('SKIPPED'),
|
||||||
|
self._get_task_name(result),
|
||||||
|
self._get_host(result=result)
|
||||||
|
]
|
||||||
|
color = C.COLOR_SKIP
|
||||||
|
item_result = self._get_item_label(result._result)
|
||||||
|
# don't display if None
|
||||||
|
if item_result:
|
||||||
|
line.append('item=%s' % item_result)
|
||||||
|
if self._run_is_verbose(result):
|
||||||
|
line.append('result=%s' % self._dump_results(result._result))
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_runner_on_skipped(self, result):
|
||||||
|
# TODO(mwhahaha): this is broken?
|
||||||
|
# if self.display_skipped_hosts:
|
||||||
|
self._clean_results(result._result, result._task.action)
|
||||||
|
if result._task.loop and 'results' in result._result:
|
||||||
|
self._process_items(result)
|
||||||
|
else:
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state('SKIPPED'),
|
||||||
|
self._get_task_name(result),
|
||||||
|
self._get_host(result=result)
|
||||||
|
]
|
||||||
|
color = C.COLOR_SKIP
|
||||||
|
item_result = self._get_item_label(result._result)
|
||||||
|
# don't display if None
|
||||||
|
if item_result:
|
||||||
|
line.append('item=%s' % item_result)
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_playbook_on_include(self, included_file):
|
||||||
|
color = C.COLOR_SKIP
|
||||||
|
# included files don't have tasks so lets generate one for the file
|
||||||
|
# for consistency. Should this be optional?
|
||||||
|
file_id = str(uuid.uuid4())
|
||||||
|
for host in included_file._hosts:
|
||||||
|
line = [
|
||||||
|
file_id,
|
||||||
|
self._get_state('INCLUDED'),
|
||||||
|
included_file._filename,
|
||||||
|
host.name
|
||||||
|
]
|
||||||
|
self._output(line, color)
|
||||||
|
|
||||||
|
def v2_runner_retry(self, result):
|
||||||
|
retry_count = result._result['retries'] - result._result['attempts']
|
||||||
|
# NOTE(mwhahaha): action is async_status we know we're waiting vs a
|
||||||
|
# failure that is being retried. We can adjust state & color.
|
||||||
|
# We use getattr because ansible will stop using this if we try and
|
||||||
|
# access an undefined thing, so let's be careful.
|
||||||
|
if (getattr(result, '_task', False)
|
||||||
|
and (getattr(result._task, 'action', False)
|
||||||
|
in ['async_status'])):
|
||||||
|
state = 'WAITING'
|
||||||
|
else:
|
||||||
|
state = 'RETRY'
|
||||||
|
color = C.COLOR_DEBUG
|
||||||
|
host_str = self._get_host(result=result)
|
||||||
|
line = [
|
||||||
|
self._get_uuid(result),
|
||||||
|
self._get_state(state),
|
||||||
|
self._get_task_name(result),
|
||||||
|
host_str,
|
||||||
|
'%d retries left' % retry_count
|
||||||
|
]
|
||||||
|
if self._run_is_verbose(result, verbosity=2):
|
||||||
|
line.append("result=%s" % self._dump_results(result._result))
|
||||||
|
self._output(line, color)
|
Loading…
Reference in New Issue