|
@@ -1,21 +1,48 @@
|
|
-# -*- coding: utf-8 -*-
|
|
|
|
|
|
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
|
|
|
+# (c) 2017 Ansible Project
|
|
|
|
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
|
|
|
|
+# Make coding more python3-ish
|
|
from __future__ import (absolute_import, division, print_function)
|
|
from __future__ import (absolute_import, division, print_function)
|
|
__metaclass__ = type
|
|
__metaclass__ = type
|
|
|
|
|
|
-import sys
|
|
|
|
-from collections import OrderedDict
|
|
|
|
|
|
+DOCUMENTATION = '''
|
|
|
|
+ callback: condensed
|
|
|
|
+ callback_type: stdout
|
|
|
|
+ requirements:
|
|
|
|
+ - set as main display callback
|
|
|
|
+ short_description: Ansible screen output that ignores skipped status
|
|
|
|
+ version_added: "2.0"
|
|
|
|
+ deprecated:
|
|
|
|
+ why: The 'default' callback plugin now supports this functionality
|
|
|
|
+ removed_in: '2.11'
|
|
|
|
+ alternative: "'default' callback plugin with 'display_skipped_hosts = no' option"
|
|
|
|
+ extends_documentation_fragment:
|
|
|
|
+ - default_callback
|
|
|
|
+ description:
|
|
|
|
+ - This callback does the same as the default except it does not output skipped host/task/item status
|
|
|
|
+'''
|
|
|
|
|
|
from ansible.plugins.callback.default import CallbackModule as CallbackModule_default
|
|
from ansible.plugins.callback.default import CallbackModule as CallbackModule_default
|
|
-from ansible import constants as C
|
|
|
|
-from ansible.utils.color import stringc, hostcolor, colorize
|
|
|
|
-from ansible.module_utils._text import to_bytes, to_text
|
|
|
|
|
|
+from ansible.playbook.task_include import TaskInclude
|
|
from ansible.utils.display import Display
|
|
from ansible.utils.display import Display
|
|
|
|
+from ansible import constants as C
|
|
|
|
+
|
|
|
|
+class CondensedDisplay(Display):
|
|
|
|
|
|
-try:
|
|
|
|
- from __main__ import display as global_display
|
|
|
|
-except ImportError:
|
|
|
|
- global_display = Display()
|
|
|
|
|
|
+ def banner(self, msg, color=None, cows=True):
|
|
|
|
+ '''
|
|
|
|
+ Prints a header-looking line with cowsay or stars with length depending on terminal width (3 minimum)
|
|
|
|
+ '''
|
|
|
|
+ if self.b_cowsay and cows:
|
|
|
|
+ try:
|
|
|
|
+ self.banner_cowsay(msg)
|
|
|
|
+ return
|
|
|
|
+ except OSError:
|
|
|
|
+ self.warning("somebody cleverly deleted cowsay or something during the PB run. heh.")
|
|
|
|
+
|
|
|
|
+ msg = msg.strip()
|
|
|
|
+ self.display(u"%s" % (msg), color=color)
|
|
|
|
|
|
class CallbackModule(CallbackModule_default):
|
|
class CallbackModule(CallbackModule_default):
|
|
|
|
|
|
@@ -28,93 +55,44 @@ class CallbackModule(CallbackModule_default):
|
|
CALLBACK_TYPE = 'stdout'
|
|
CALLBACK_TYPE = 'stdout'
|
|
CALLBACK_NAME = 'condensed'
|
|
CALLBACK_NAME = 'condensed'
|
|
|
|
|
|
- _progress = OrderedDict()
|
|
|
|
-
|
|
|
|
- class CallbackDisplay(Display):
|
|
|
|
-
|
|
|
|
- def banner(self, msg, color=None, cows=False, newline=True):
|
|
|
|
- msg = msg.strip()
|
|
|
|
- if newline:
|
|
|
|
- msg = u"\n" + msg
|
|
|
|
- self.display(u"%s" % (msg), color=color)
|
|
|
|
-
|
|
|
|
- def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False):
|
|
|
|
- if color:
|
|
|
|
- msg = stringc(msg, color)
|
|
|
|
- msg2 = to_bytes(msg, encoding=self._output_encoding(stderr=stderr))
|
|
|
|
- if sys.version_info >= (3,):
|
|
|
|
- msg2 = to_text(msg2, self._output_encoding(stderr=stderr), errors='replace')
|
|
|
|
- if not stderr:
|
|
|
|
- fileobj = sys.stdout
|
|
|
|
- else:
|
|
|
|
- fileobj = sys.stderr
|
|
|
|
- fileobj.write(msg2)
|
|
|
|
- try:
|
|
|
|
- fileobj.flush()
|
|
|
|
- except IOError as e:
|
|
|
|
- if e.errno != errno.EPIPE:
|
|
|
|
- raise
|
|
|
|
-
|
|
|
|
- def clear_line(self):
|
|
|
|
- sys.stdout.write("\r" + " " * self.columns + "\r")
|
|
|
|
- sys.stdout.flush()
|
|
|
|
-
|
|
|
|
def __init__(self):
|
|
def __init__(self):
|
|
- self.super_ref = super(CallbackModule, self)
|
|
|
|
- self.super_ref.__init__()
|
|
|
|
- self._display = self.CallbackDisplay(verbosity=global_display.verbosity)
|
|
|
|
-
|
|
|
|
- def v2_runner_on_skipped(self, result):
|
|
|
|
- pass
|
|
|
|
-
|
|
|
|
- def v2_runner_item_on_skipped(self, result):
|
|
|
|
- pass
|
|
|
|
-
|
|
|
|
- def _print_task_banner(self, task):
|
|
|
|
-
|
|
|
|
- newline = True
|
|
|
|
- while self._progress != {}:
|
|
|
|
- last = self._progress.keys()[-1]
|
|
|
|
- if self._progress[last] == None:
|
|
|
|
- del self._progress[last]
|
|
|
|
- self._display.clear_line()
|
|
|
|
- newline = False
|
|
|
|
- else:
|
|
|
|
- break
|
|
|
|
-
|
|
|
|
- self._progress[task._uuid] = None
|
|
|
|
- args = ''
|
|
|
|
- if not task.no_log and C.DISPLAY_ARGS_TO_STDOUT:
|
|
|
|
- args = u', '.join(u'%s=%s' % a for a in task.args.items())
|
|
|
|
- args = u' %s' % args
|
|
|
|
-
|
|
|
|
- if task.action in ['include_tasks']:
|
|
|
|
- self._display.banner(u"INCLUDE TASKS", newline=newline)
|
|
|
|
- else:
|
|
|
|
- self._display.banner(u"TASK [%s%s]" % (task.get_name().strip(), args), newline=newline)
|
|
|
|
- if self._display.verbosity >= 2:
|
|
|
|
- path = task.get_path()
|
|
|
|
- if path:
|
|
|
|
- self._display.display(u"task path: %s" % path, color=C.COLOR_DEBUG)
|
|
|
|
|
|
+ super(CallbackModule, self).__init__()
|
|
|
|
+ self._display = CondensedDisplay()
|
|
|
|
|
|
- self._last_task_banner = task._uuid
|
|
|
|
|
|
+ def v2_playbook_on_include(self, included_file):
|
|
|
|
+ basedir = included_file._task._loader.get_basedir()
|
|
|
|
+ hosts = ", ".join([h.name for h in included_file._hosts])
|
|
|
|
+ filepath = included_file._filename.replace(basedir, '').strip('/')
|
|
|
|
+ msg = ' %s => %s' % (hosts, filepath)
|
|
|
|
+ self._display.display('INCLUDE TASKS')
|
|
|
|
+ self._display.display(msg, color=C.COLOR_SKIP)
|
|
|
|
|
|
def v2_runner_on_ok(self, result):
|
|
def v2_runner_on_ok(self, result):
|
|
- self._progress[result._task._uuid] = True
|
|
|
|
-
|
|
|
|
- if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
|
|
|
- self._print_task_banner(result._task)
|
|
|
|
|
|
|
|
- self._clean_results(result._result, result._task.action)
|
|
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
- self._clean_results(result._result, result._task.action)
|
|
|
|
|
|
|
|
- msg = u'\n %s' % (result._host.get_name())
|
|
|
|
- if result._task.action in ('include', 'include_role'):
|
|
|
|
|
|
+ if isinstance(result._task, TaskInclude):
|
|
return
|
|
return
|
|
elif result._result.get('changed', False):
|
|
elif result._result.get('changed', False):
|
|
|
|
+ if self._last_task_banner != result._task._uuid:
|
|
|
|
+ self._print_task_banner(result._task)
|
|
|
|
+
|
|
|
|
+ if delegated_vars:
|
|
|
|
+ msg = " %s -> %s" % (result._host.get_name(), delegated_vars['ansible_host'])
|
|
|
|
+ else:
|
|
|
|
+ msg = " %s" % result._host.get_name()
|
|
color = C.COLOR_CHANGED
|
|
color = C.COLOR_CHANGED
|
|
else:
|
|
else:
|
|
|
|
+ if not self.display_ok_hosts:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ if self._last_task_banner != result._task._uuid:
|
|
|
|
+ self._print_task_banner(result._task)
|
|
|
|
+
|
|
|
|
+ if delegated_vars:
|
|
|
|
+ msg = " %s -> %s" % (result._host.get_name(), delegated_vars['ansible_host'])
|
|
|
|
+ else:
|
|
|
|
+ msg = " %s" % result._host.get_name()
|
|
color = C.COLOR_OK
|
|
color = C.COLOR_OK
|
|
|
|
|
|
self._handle_warnings(result._result)
|
|
self._handle_warnings(result._result)
|
|
@@ -122,62 +100,45 @@ class CallbackModule(CallbackModule_default):
|
|
if result._task.loop and 'results' in result._result:
|
|
if result._task.loop and 'results' in result._result:
|
|
self._process_items(result)
|
|
self._process_items(result)
|
|
else:
|
|
else:
|
|
- if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and not '_ansible_verbose_override' in result._result:
|
|
|
|
- msg += " => %s" % (self._dump_results(result._result),)
|
|
|
|
|
|
+ self._clean_results(result._result, result._task.action)
|
|
|
|
+
|
|
|
|
+ #if self._run_is_verbose(result):
|
|
|
|
+ # msg += " => %s" % (self._dump_results(result._result),)
|
|
self._display.display(msg, color=color)
|
|
self._display.display(msg, color=color)
|
|
|
|
|
|
def v2_runner_item_on_ok(self, result):
|
|
def v2_runner_item_on_ok(self, result):
|
|
|
|
+
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
- msg = "\n "
|
|
|
|
- if result._task.action in ('include', 'include_role'):
|
|
|
|
|
|
+ self._clean_results(result._result, result._task.action)
|
|
|
|
+ if isinstance(result._task, TaskInclude):
|
|
return
|
|
return
|
|
elif result._result.get('changed', False):
|
|
elif result._result.get('changed', False):
|
|
|
|
+ if self._last_task_banner != result._task._uuid:
|
|
|
|
+ self._print_task_banner(result._task)
|
|
|
|
+
|
|
color = C.COLOR_CHANGED
|
|
color = C.COLOR_CHANGED
|
|
else:
|
|
else:
|
|
|
|
+ if not self.display_ok_hosts:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ if self._last_task_banner != result._task._uuid:
|
|
|
|
+ self._print_task_banner(result._task)
|
|
|
|
+
|
|
color = C.COLOR_OK
|
|
color = C.COLOR_OK
|
|
|
|
|
|
if delegated_vars:
|
|
if delegated_vars:
|
|
- msg += "[%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
|
|
|
|
|
|
+ msg = " %s -> %s" % (result._host.get_name(), delegated_vars['ansible_host'])
|
|
else:
|
|
else:
|
|
- msg += "%s" % result._host.get_name()
|
|
|
|
|
|
+ msg = " %s" % result._host.get_name()
|
|
|
|
|
|
msg += " => (item=%s)" % (self._get_item_label(result._result),)
|
|
msg += " => (item=%s)" % (self._get_item_label(result._result),)
|
|
|
|
|
|
- if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and not '_ansible_verbose_override' in result._result:
|
|
|
|
- msg += " => %s" % self._dump_results(result._result)
|
|
|
|
|
|
+ #if self._run_is_verbose(result):
|
|
|
|
+ # msg += " => %s" % self._dump_results(result._result)
|
|
self._display.display(msg, color=color)
|
|
self._display.display(msg, color=color)
|
|
|
|
|
|
|
|
+ def v2_runner_on_skipped(self, result):
|
|
|
|
+ pass
|
|
|
|
|
|
- def v2_on_file_diff(self, result):
|
|
|
|
- if result._task.loop and 'results' in result._result:
|
|
|
|
- for res in result._result['results']:
|
|
|
|
- if 'diff' in res and res['diff'] and res.get('changed', False):
|
|
|
|
- diff = self._get_diff(res['diff'])
|
|
|
|
- if diff:
|
|
|
|
- self._display.display(u"\n" + diff.strip())
|
|
|
|
- elif 'diff' in result._result and result._result['diff'] and result._result.get('changed', False):
|
|
|
|
- diff = self._get_diff(result._result['diff'])
|
|
|
|
- if diff:
|
|
|
|
- self._display.display(u"\n" + diff.strip())
|
|
|
|
-
|
|
|
|
- def v2_playbook_on_include(self, included_file):
|
|
|
|
- self._display.clear_line()
|
|
|
|
- basedir = included_file._task._loader.get_basedir()
|
|
|
|
- for h in included_file._hosts:
|
|
|
|
- msg = " %s => %s" % (h, included_file._filename.replace(basedir, '').strip('/'))
|
|
|
|
- self._display.display(msg, color=C.COLOR_SKIP)
|
|
|
|
-
|
|
|
|
- def v2_playbook_on_stats(self, stats):
|
|
|
|
- self._display.clear_line()
|
|
|
|
- self._display.display("PLAY RECAP\n")
|
|
|
|
- hosts = sorted(stats.processed.keys())
|
|
|
|
- for h in hosts:
|
|
|
|
- t = stats.summarize(h)
|
|
|
|
- self._display.display(u"%s : %s %s %s %s\n" % (
|
|
|
|
- hostcolor(h, t),
|
|
|
|
- colorize(u'ok', t['ok'], C.COLOR_OK),
|
|
|
|
- colorize(u'changed', t['changed'], C.COLOR_CHANGED),
|
|
|
|
- colorize(u'unreachable', t['unreachable'], C.COLOR_UNREACHABLE),
|
|
|
|
- colorize(u'failed', t['failures'], C.COLOR_ERROR)),
|
|
|
|
- screen_only=True
|
|
|
|
- )
|
|
|
|
|
|
+ def v2_runner_item_on_skipped(self, result):
|
|
|
|
+ pass
|