fix minor issues with debug and item labels (#41331)

* fix minor issues with debug and item labels

 - no more `item=None`, we always have a label now
 - debug should only show expected information, either msg= or the var in var=
 - also fixed method name, deprecated misleading _get_item
pull/41819/head
Brian Coca 7 years ago committed by GitHub
parent 929ac6155c
commit 27c43daab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -278,14 +278,19 @@ class TaskExecutor:
label = None label = None
loop_pause = 0 loop_pause = 0
templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars) templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
# FIXME: move this to the object itself to allow post_validate to take care of templating (loop_control.post_validate)
if self._task.loop_control: if self._task.loop_control:
# FIXME: move this to the object itself to allow post_validate to take care of templating
loop_var = templar.template(self._task.loop_control.loop_var) loop_var = templar.template(self._task.loop_control.loop_var)
index_var = templar.template(self._task.loop_control.index_var) index_var = templar.template(self._task.loop_control.index_var)
loop_pause = templar.template(self._task.loop_control.pause) loop_pause = templar.template(self._task.loop_control.pause)
# the these may be 'None', so we still need to default to something useful
# this is tempalted below after an item is assigned # This may be 'None',so it is tempalted below after we ensure a value and an item is assigned
label = (self._task.loop_control.label or ('{{' + loop_var + '}}')) label = self._task.loop_control.label
# ensure we always have a label
if label is None:
label = '{{' + loop_var + '}}'
if loop_var in task_vars: if loop_var in task_vars:
display.warning(u"The loop variable '%s' is already in use. " display.warning(u"The loop variable '%s' is already in use. "
@ -339,8 +344,8 @@ class TaskExecutor:
res['_ansible_item_result'] = True res['_ansible_item_result'] = True
res['_ansible_ignore_errors'] = task_fields.get('ignore_errors') res['_ansible_ignore_errors'] = task_fields.get('ignore_errors')
if label is not None: # gets templated here unlike rest of loop_control fields, depends on loop_var above
res['_ansible_item_label'] = templar.template(label, cache=False) res['_ansible_item_label'] = templar.template(label, cache=False)
self._rslt_q.put( self._rslt_q.put(
TaskResult( TaskResult(

@ -21,9 +21,12 @@ __metaclass__ = type
import difflib import difflib
import json import json
import os
import sys import sys
import warnings import warnings
from copy import deepcopy from copy import deepcopy
from collections import MutableMapping
from ansible import constants as C from ansible import constants as C
from ansible.parsing.ajson import AnsibleJSONEncoder from ansible.parsing.ajson import AnsibleJSONEncoder
@ -78,7 +81,7 @@ class CallbackBase(AnsiblePlugin):
if options is not None: if options is not None:
self.set_options(options) self.set_options(options)
self._hide_in_debug = ('changed', 'failed', 'skipped', 'invocation') self._hide_in_debug = ('changed', 'failed', 'skipped', 'invocation', 'skip_reason')
''' helper for callbacks, so they don't all have to include deepcopy ''' ''' helper for callbacks, so they don't all have to include deepcopy '''
_copy_result = deepcopy _copy_result = deepcopy
@ -172,7 +175,7 @@ class CallbackBase(AnsiblePlugin):
if 'before' in diff and 'after' in diff: if 'before' in diff and 'after' in diff:
# format complex structures into 'files' # format complex structures into 'files'
for x in ['before', 'after']: for x in ['before', 'after']:
if isinstance(diff[x], dict): if isinstance(diff[x], MutableMapping):
diff[x] = json.dumps(diff[x], sort_keys=True, indent=4, separators=(',', ': ')) + '\n' diff[x] = json.dumps(diff[x], sort_keys=True, indent=4, separators=(',', ': ')) + '\n'
if 'before_header' in diff: if 'before_header' in diff:
before_header = "before: %s" % diff['before_header'] before_header = "before: %s" % diff['before_header']
@ -221,27 +224,38 @@ class CallbackBase(AnsiblePlugin):
ret.append(">> the files are different, but the diff library cannot compare unicode strings\n\n") ret.append(">> the files are different, but the diff library cannot compare unicode strings\n\n")
return u''.join(ret) return u''.join(ret)
def _get_item(self, result): def _get_item_label(self, result):
''' retrieves the value to be displayed as a label for an item entry from a result object'''
if result.get('_ansible_no_log', False): if result.get('_ansible_no_log', False):
item = "(censored due to no_log)" item = "(censored due to no_log)"
elif result.get('_ansible_item_label', False):
item = result.get('_ansible_item_label')
else: else:
item = result.get('item', None) item = result.get('_ansible_item_label', result.get('item'))
return item return item
def _get_item(self, result):
''' here for backwards compat, really should have always been named: _get_item_label'''
cback = getattr(self, 'NAME', os.path.basename(__file__))
self._display.deprecated("The %s callback plugin should be updated to use the _get_item_label method instead" % cback, version="2.11")
return self._get_item_label(result)
def _process_items(self, result): def _process_items(self, result):
# just remove them as now they get handled by individual callbacks # just remove them as now they get handled by individual callbacks
del result._result['results'] del result._result['results']
def _clean_results(self, result, task_name): def _clean_results(self, result, task_name):
''' removes data from results for display ''' ''' removes data from results for display '''
# mostly controls that debug only outputs what it was meant to
if task_name in ['debug']: if task_name in ['debug']:
for hideme in self._hide_in_debug: if 'msg' in result:
result.pop(hideme, None) # msg should be alone
if 'msg' in result: for key in list(result.keys()):
result.pop('item', None) if key != 'msg' and not key.startswith('_'):
result.pop(key)
else:
# 'var' value as field, so eliminate others and what is left should be varname
for hidme in self._hide_in_debug:
result.pop(hidme, None)
def set_play_context(self, play_context): def set_play_context(self, play_context):
pass pass
@ -324,7 +338,7 @@ class CallbackBase(AnsiblePlugin):
def v2_runner_on_skipped(self, result): def v2_runner_on_skipped(self, result):
if C.DISPLAY_SKIPPED_HOSTS: if C.DISPLAY_SKIPPED_HOSTS:
host = result._host.get_name() host = result._host.get_name()
self.runner_on_skipped(host, self._get_item(getattr(result._result, 'results', {}))) self.runner_on_skipped(host, self._get_item_label(getattr(result._result, 'results', {})))
def v2_runner_on_unreachable(self, result): def v2_runner_on_unreachable(self, result):
host = result._host.get_name() host = result._host.get_name()

@ -205,7 +205,7 @@ class CallbackModule(CallbackBase):
else: else:
msg += ": [%s]" % result._host.get_name() msg += ": [%s]" % result._host.get_name()
msg += " => (item=%s)" % (self._get_item(result._result),) msg += " => (item=%s)" % (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:
msg += " => %s" % self._dump_results(result._result) msg += " => %s" % self._dump_results(result._result)
@ -224,12 +224,12 @@ class CallbackModule(CallbackBase):
msg += "[%s]" % (result._host.get_name()) msg += "[%s]" % (result._host.get_name())
self._handle_warnings(result._result) self._handle_warnings(result._result)
self._display.display(msg + " (item=%s) => %s" % (self._get_item(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('show_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(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:
msg += " => %s" % self._dump_results(result._result) msg += " => %s" % self._dump_results(result._result)
self._display.display(msg, color=C.COLOR_SKIP) self._display.display(msg, color=C.COLOR_SKIP)

@ -51,6 +51,7 @@ class TestCallback(unittest.TestCase):
class TestCallbackResults(unittest.TestCase): class TestCallbackResults(unittest.TestCase):
def test_get_item(self): def test_get_item(self):
cb = CallbackBase() cb = CallbackBase()
results = {'item': 'some_item'} results = {'item': 'some_item'}
@ -67,6 +68,22 @@ class TestCallbackResults(unittest.TestCase):
res = cb._get_item(results) res = cb._get_item(results)
self.assertEquals(res, "some_item") self.assertEquals(res, "some_item")
def test_get_item_label(self):
cb = CallbackBase()
results = {'item': 'some_item'}
res = cb._get_item_label(results)
self.assertEquals(res, 'some_item')
def test_get_item_label_no_log(self):
cb = CallbackBase()
results = {'item': 'some_item', '_ansible_no_log': True}
res = cb._get_item_label(results)
self.assertEquals(res, "(censored due to no_log)")
results = {'item': 'some_item', '_ansible_no_log': False}
res = cb._get_item_label(results)
self.assertEquals(res, "some_item")
def test_clean_results_debug_task(self): def test_clean_results_debug_task(self):
cb = CallbackBase() cb = CallbackBase()
result = {'item': 'some_item', result = {'item': 'some_item',

Loading…
Cancel
Save