mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Merge various stdout callback plugins into 'default' (#41058)
This allows mixing and matching of stdout callback features
This commit is contained in:
parent
0b2ec9b11c
commit
9c5d40ff15
8 changed files with 84 additions and 30 deletions
10
changelogs/fragments/callback_plugin_merge.yml
Normal file
10
changelogs/fragments/callback_plugin_merge.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
deprecated_features:
|
||||||
|
- The `skippy`, `full_skip`, `actionable`, and `stderr` callback plugins have
|
||||||
|
been deprecated in favor of config options that influence the behavior of the
|
||||||
|
`default` callback plugin (https://github.com/ansible/ansible/pull/41058)
|
||||||
|
minor_changes:
|
||||||
|
- New config options `display_ok_hosts` and `display_failed_stderr` (along with
|
||||||
|
the existing `display_skipped_hosts` option) allow more fine-grained control
|
||||||
|
over the way that ansible displays output from a playbook
|
||||||
|
(https://github.com/ansible/ansible/pull/41058)
|
|
@ -134,7 +134,7 @@ class CallbackBase(AnsiblePlugin):
|
||||||
self._display.deprecated(**warning)
|
self._display.deprecated(**warning)
|
||||||
del res['deprecations']
|
del res['deprecations']
|
||||||
|
|
||||||
def _handle_exception(self, result):
|
def _handle_exception(self, result, use_stderr=False):
|
||||||
|
|
||||||
if 'exception' in result:
|
if 'exception' in result:
|
||||||
msg = "An exception occurred during task execution. "
|
msg = "An exception occurred during task execution. "
|
||||||
|
@ -146,7 +146,7 @@ class CallbackBase(AnsiblePlugin):
|
||||||
msg = "The full traceback is:\n" + result['exception']
|
msg = "The full traceback is:\n" + result['exception']
|
||||||
del result['exception']
|
del result['exception']
|
||||||
|
|
||||||
self._display.display(msg, color=C.COLOR_ERROR)
|
self._display.display(msg, color=C.COLOR_ERROR, stderr=use_stderr)
|
||||||
|
|
||||||
def _get_diff(self, difflist):
|
def _get_diff(self, difflist):
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ DOCUMENTATION = '''
|
||||||
- Use this callback when you dont care about OK nor Skipped.
|
- Use this callback when you dont care about OK nor Skipped.
|
||||||
- This callback suppresses any non Failed or Changed status.
|
- This callback suppresses any non Failed or Changed status.
|
||||||
version_added: "2.1"
|
version_added: "2.1"
|
||||||
|
deprecated:
|
||||||
|
why: The 'default' callback plugin now supports this functionality
|
||||||
|
removed_in: '2.11'
|
||||||
|
alternative: "'default' callback plugin with 'display_skipped_hosts = no' and 'display_ok_hosts = no' options"
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- default_callback
|
- default_callback
|
||||||
requirements:
|
requirements:
|
||||||
|
|
|
@ -39,6 +39,7 @@ class CallbackModule(CallbackBase):
|
||||||
|
|
||||||
self._play = None
|
self._play = None
|
||||||
self._last_task_banner = None
|
self._last_task_banner = None
|
||||||
|
self._last_task_name = None
|
||||||
super(CallbackModule, self).__init__()
|
super(CallbackModule, self).__init__()
|
||||||
|
|
||||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||||
|
@ -46,10 +47,12 @@ class CallbackModule(CallbackBase):
|
||||||
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)
|
self._clean_results(result._result, result._task.action)
|
||||||
|
|
||||||
if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
if self._last_task_banner != result._task._uuid:
|
||||||
self._print_task_banner(result._task)
|
self._print_task_banner(result._task)
|
||||||
|
|
||||||
self._handle_exception(result._result)
|
use_stderr = self._plugin_options.get('display_failed_stderr', False)
|
||||||
|
|
||||||
|
self._handle_exception(result._result, use_stderr=use_stderr)
|
||||||
self._handle_warnings(result._result)
|
self._handle_warnings(result._result)
|
||||||
|
|
||||||
if result._task.loop and 'results' in result._result:
|
if result._task.loop and 'results' in result._result:
|
||||||
|
@ -58,18 +61,22 @@ class CallbackModule(CallbackBase):
|
||||||
else:
|
else:
|
||||||
if delegated_vars:
|
if delegated_vars:
|
||||||
self._display.display("fatal: [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'],
|
self._display.display("fatal: [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'],
|
||||||
self._dump_results(result._result)), color=C.COLOR_ERROR)
|
self._dump_results(result._result)),
|
||||||
|
color=C.COLOR_ERROR, stderr=use_stderr)
|
||||||
else:
|
else:
|
||||||
self._display.display("fatal: [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)), color=C.COLOR_ERROR)
|
self._display.display("fatal: [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)),
|
||||||
|
color=C.COLOR_ERROR, stderr=use_stderr)
|
||||||
|
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
self._display.display("...ignoring", color=C.COLOR_SKIP)
|
self._display.display("...ignoring", color=C.COLOR_SKIP)
|
||||||
|
|
||||||
def v2_runner_on_ok(self, result):
|
def v2_runner_on_ok(self, result):
|
||||||
|
if not self._plugin_options.get('display_ok_hosts'):
|
||||||
|
return
|
||||||
|
|
||||||
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
||||||
|
|
||||||
if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
if self._last_task_banner != result._task._uuid:
|
||||||
self._print_task_banner(result._task)
|
self._print_task_banner(result._task)
|
||||||
|
|
||||||
if isinstance(result._task, TaskInclude):
|
if isinstance(result._task, TaskInclude):
|
||||||
|
@ -99,11 +106,11 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display(msg, color=color)
|
self._display.display(msg, color=color)
|
||||||
|
|
||||||
def v2_runner_on_skipped(self, result):
|
def v2_runner_on_skipped(self, result):
|
||||||
if self._plugin_options.get('show_skipped_hosts', C.DISPLAY_SKIPPED_HOSTS): # fallback on constants for inherited plugins missing docs
|
if self._plugin_options.get('display_skipped_hosts', C.DISPLAY_SKIPPED_HOSTS): # fallback on constants for inherited plugins missing docs
|
||||||
|
|
||||||
self._clean_results(result._result, result._task.action)
|
self._clean_results(result._result, result._task.action)
|
||||||
|
|
||||||
if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
if self._last_task_banner != result._task._uuid:
|
||||||
self._print_task_banner(result._task)
|
self._print_task_banner(result._task)
|
||||||
|
|
||||||
if result._task.loop and 'results' in result._result:
|
if result._task.loop and 'results' in result._result:
|
||||||
|
@ -115,7 +122,7 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display(msg, color=C.COLOR_SKIP)
|
self._display.display(msg, color=C.COLOR_SKIP)
|
||||||
|
|
||||||
def v2_runner_on_unreachable(self, result):
|
def v2_runner_on_unreachable(self, result):
|
||||||
if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
if self._last_task_banner != result._task._uuid:
|
||||||
self._print_task_banner(result._task)
|
self._print_task_banner(result._task)
|
||||||
|
|
||||||
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
||||||
|
@ -133,9 +140,14 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.banner("NO MORE HOSTS LEFT")
|
self._display.banner("NO MORE HOSTS LEFT")
|
||||||
|
|
||||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
def v2_playbook_on_task_start(self, task, is_conditional):
|
||||||
|
# Preserve task name, as all vars may not be available for templating
|
||||||
|
# when we need it later
|
||||||
if self._play.strategy != 'free':
|
if self._play.strategy != 'free':
|
||||||
self._print_task_banner(task)
|
self._last_task_name = task.get_name().strip()
|
||||||
|
|
||||||
|
# Display the task banner immediately if we're not doing any filtering based on task result
|
||||||
|
if self._plugin_options.get('display_skipped_hosts') and self._plugin_options.get('display_ok_hosts'):
|
||||||
|
self._print_task_banner(task)
|
||||||
|
|
||||||
def _print_task_banner(self, task):
|
def _print_task_banner(self, task):
|
||||||
# args can be specified as no_log in several places: in the task or in
|
# args can be specified as no_log in several places: in the task or in
|
||||||
|
@ -151,7 +163,12 @@ class CallbackModule(CallbackBase):
|
||||||
args = u', '.join(u'%s=%s' % a for a in task.args.items())
|
args = u', '.join(u'%s=%s' % a for a in task.args.items())
|
||||||
args = u' %s' % args
|
args = u' %s' % args
|
||||||
|
|
||||||
self._display.banner(u"TASK [%s%s]" % (task.get_name().strip(), args))
|
# Use cached task name
|
||||||
|
task_name = self._last_task_name
|
||||||
|
if task_name is None:
|
||||||
|
task_name = task.get_name().strip()
|
||||||
|
|
||||||
|
self._display.banner(u"TASK [%s%s]" % (task_name, args))
|
||||||
if self._display.verbosity >= 2:
|
if self._display.verbosity >= 2:
|
||||||
path = task.get_path()
|
path = task.get_path()
|
||||||
if path:
|
if path:
|
||||||
|
@ -189,6 +206,9 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display(diff)
|
self._display.display(diff)
|
||||||
|
|
||||||
def v2_runner_item_on_ok(self, result):
|
def v2_runner_item_on_ok(self, result):
|
||||||
|
if not self._plugin_options.get('display_ok_hosts'):
|
||||||
|
return
|
||||||
|
|
||||||
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)
|
self._clean_results(result._result, result._task.action)
|
||||||
if isinstance(result._task, TaskInclude):
|
if isinstance(result._task, TaskInclude):
|
||||||
|
@ -227,7 +247,7 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display(msg + " (item=%s) => %s" % (self._get_item_label(result._result), self._dump_results(result._result)), color=C.COLOR_ERROR)
|
self._display.display(msg + " (item=%s) => %s" % (self._get_item_label(result._result), self._dump_results(result._result)), color=C.COLOR_ERROR)
|
||||||
|
|
||||||
def v2_runner_item_on_skipped(self, result):
|
def v2_runner_item_on_skipped(self, result):
|
||||||
if self._plugin_options.get('show_skipped_hosts', C.DISPLAY_SKIPPED_HOSTS): # fallback on constants for inherited plugins missing docs
|
if self._plugin_options.get('display_skipped_hosts', C.DISPLAY_SKIPPED_HOSTS): # fallback on constants for inherited plugins missing docs
|
||||||
self._clean_results(result._result, result._task.action)
|
self._clean_results(result._result, result._task.action)
|
||||||
msg = "skipping: [%s] => (item=%s) " % (result._host.get_name(), self._get_item_label(result._result))
|
msg = "skipping: [%s] => (item=%s) " % (result._host.get_name(), self._get_item_label(result._result))
|
||||||
if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result:
|
if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result:
|
||||||
|
|
|
@ -13,6 +13,10 @@ DOCUMENTATION = '''
|
||||||
description:
|
description:
|
||||||
- Use this plugin when you dont care about any output for tasks that were completly skipped
|
- Use this plugin when you dont care about any output for tasks that were completly skipped
|
||||||
version_added: "2.4"
|
version_added: "2.4"
|
||||||
|
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:
|
extends_documentation_fragment:
|
||||||
- default_callback
|
- default_callback
|
||||||
requirements:
|
requirements:
|
||||||
|
|
|
@ -13,6 +13,10 @@ DOCUMENTATION = '''
|
||||||
- set as main display callback
|
- set as main display callback
|
||||||
short_description: Ansible screen output that ignores skipped status
|
short_description: Ansible screen output that ignores skipped status
|
||||||
version_added: "2.0"
|
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:
|
extends_documentation_fragment:
|
||||||
- default_callback
|
- default_callback
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -13,6 +13,10 @@ DOCUMENTATION = '''
|
||||||
- set as main display callback
|
- set as main display callback
|
||||||
short_description: Splits output, sending failed tasks to stderr
|
short_description: Splits output, sending failed tasks to stderr
|
||||||
version_added: "2.4"
|
version_added: "2.4"
|
||||||
|
deprecated:
|
||||||
|
why: The 'default' callback plugin now supports this functionality
|
||||||
|
removed_in: '2.11'
|
||||||
|
alternative: "'default' callback plugin with 'display_failed_stderr = yes' option"
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- default_callback
|
- default_callback
|
||||||
description:
|
description:
|
||||||
|
@ -48,7 +52,7 @@ class CallbackModule(CallbackModule_default):
|
||||||
if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
|
||||||
self._print_task_banner(result._task)
|
self._print_task_banner(result._task)
|
||||||
|
|
||||||
self._handle_exception(result._result, errors_to_stderr=True)
|
self._handle_exception(result._result, use_stderr=True)
|
||||||
self._handle_warnings(result._result)
|
self._handle_warnings(result._result)
|
||||||
|
|
||||||
if result._task.loop and 'results' in result._result:
|
if result._task.loop and 'results' in result._result:
|
||||||
|
@ -65,17 +69,3 @@ class CallbackModule(CallbackModule_default):
|
||||||
|
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
self._display.display("...ignoring", color=C.COLOR_SKIP)
|
self._display.display("...ignoring", color=C.COLOR_SKIP)
|
||||||
|
|
||||||
def _handle_exception(self, result, errors_to_stderr=False):
|
|
||||||
|
|
||||||
if 'exception' in result:
|
|
||||||
msg = "An exception occurred during task execution. "
|
|
||||||
if self._display.verbosity < 3:
|
|
||||||
# extract just the actual error message from the exception text
|
|
||||||
error = result['exception'].strip().split('\n')[-1]
|
|
||||||
msg += "To see the full traceback, use -vvv. The error was: %s" % error
|
|
||||||
else:
|
|
||||||
msg = "The full traceback is:\n" + result['exception']
|
|
||||||
del result['exception']
|
|
||||||
|
|
||||||
self._display.display(msg, color=C.COLOR_ERROR, stderr=errors_to_stderr)
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ class ModuleDocFragment(object):
|
||||||
|
|
||||||
DOCUMENTATION = """
|
DOCUMENTATION = """
|
||||||
options:
|
options:
|
||||||
show_skipped_hosts:
|
display_skipped_hosts:
|
||||||
name: Show skipped hosts
|
name: Show skipped hosts
|
||||||
description: "Toggle to control displaying skipped task/host results in a task"
|
description: "Toggle to control displaying skipped task/host results in a task"
|
||||||
default: True
|
default: True
|
||||||
|
@ -16,6 +16,28 @@ class ModuleDocFragment(object):
|
||||||
- key: display_skipped_hosts
|
- key: display_skipped_hosts
|
||||||
section: defaults
|
section: defaults
|
||||||
type: boolean
|
type: boolean
|
||||||
|
display_ok_hosts:
|
||||||
|
name: Show 'ok' hosts
|
||||||
|
description: "Toggle to control displaying 'ok' task/host results in a task"
|
||||||
|
default: True
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_DISPLAY_OK_HOSTS
|
||||||
|
ini:
|
||||||
|
- key: display_ok_hosts
|
||||||
|
section: defaults
|
||||||
|
type: boolean
|
||||||
|
version_added: '2.7'
|
||||||
|
display_failed_stderr:
|
||||||
|
name: Use STDERR for failed tasks
|
||||||
|
description: "Toggle to control whether failed tasks are displayed to STDERR (vs. STDOUT)"
|
||||||
|
default: False
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_DISPLAY_FAILED_STDERR
|
||||||
|
ini:
|
||||||
|
- key: display_failed_stderr
|
||||||
|
section: defaults
|
||||||
|
type: boolean
|
||||||
|
version_added: '2.7'
|
||||||
show_custom_stats:
|
show_custom_stats:
|
||||||
name: Show custom stats
|
name: Show custom stats
|
||||||
description: 'This adds the custom stats set via the set_stats plugin to the play recap'
|
description: 'This adds the custom stats set via the set_stats plugin to the play recap'
|
||||||
|
|
Loading…
Reference in a new issue