mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-01-11 07:05:27 +01:00
Fix json callback for non-lockstep strategy plugins such as free. Fixes #65931
This commit is contained in:
parent
6b347f3725
commit
23d3703a84
2 changed files with 50 additions and 7 deletions
|
|
@ -0,0 +1,4 @@
|
|||
bugfixes:
|
||||
- json callback - Fix host result to task references in the resultant JSON
|
||||
output for non-lockstep strategy plugins such as free
|
||||
(https://github.com/ansible/ansible/issues/65931)
|
||||
|
|
@ -25,6 +25,11 @@ DOCUMENTATION = '''
|
|||
- key: show_custom_stats
|
||||
section: defaults
|
||||
type: bool
|
||||
notes:
|
||||
- When using a strategy such as free, host_pinned, or a custom strategy, host results will
|
||||
be added to new task results in ``.plays[].tasks[]``. As such, there will exist duplicate
|
||||
task objects indicated by duplicate task IDs at ``.plays[].tasks[].task.id``, each with an
|
||||
individual host result for the task.
|
||||
'''
|
||||
|
||||
import datetime
|
||||
|
|
@ -33,10 +38,14 @@ import json
|
|||
from functools import partial
|
||||
|
||||
from ansible.inventory.host import Host
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
|
||||
LOCKSTEP_CALLBACKS = frozenset(('linear', 'debug'))
|
||||
|
||||
|
||||
def current_time():
|
||||
return '%sZ' % datetime.datetime.utcnow().isoformat()
|
||||
|
||||
|
|
@ -49,12 +58,15 @@ class CallbackModule(CallbackBase):
|
|||
def __init__(self, display=None):
|
||||
super(CallbackModule, self).__init__(display)
|
||||
self.results = []
|
||||
self._task_map = {}
|
||||
self._is_lockstep = False
|
||||
|
||||
def _new_play(self, play):
|
||||
self._is_lockstep = play.strategy in LOCKSTEP_CALLBACKS
|
||||
return {
|
||||
'play': {
|
||||
'name': play.get_name(),
|
||||
'id': str(play._uuid),
|
||||
'id': to_text(play._uuid),
|
||||
'duration': {
|
||||
'start': current_time()
|
||||
}
|
||||
|
|
@ -66,7 +78,7 @@ class CallbackModule(CallbackBase):
|
|||
return {
|
||||
'task': {
|
||||
'name': task.get_name(),
|
||||
'id': str(task._uuid),
|
||||
'id': to_text(task._uuid),
|
||||
'duration': {
|
||||
'start': current_time()
|
||||
}
|
||||
|
|
@ -74,13 +86,32 @@ class CallbackModule(CallbackBase):
|
|||
'hosts': {}
|
||||
}
|
||||
|
||||
def _find_result_task(self, host, task):
|
||||
key = (host.get_name(), task._uuid)
|
||||
return self._task_map.get(
|
||||
key,
|
||||
self.results[-1]['tasks'][-1]
|
||||
)
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
self.results.append(self._new_play(play))
|
||||
|
||||
def v2_runner_on_start(self, host, task):
|
||||
if self._is_lockstep:
|
||||
return
|
||||
key = (host.get_name(), task._uuid)
|
||||
task_result = self._new_task(task)
|
||||
self._task_map[key] = task_result
|
||||
self.results[-1]['tasks'].append(task_result)
|
||||
|
||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
||||
if not self._is_lockstep:
|
||||
return
|
||||
self.results[-1]['tasks'].append(self._new_task(task))
|
||||
|
||||
def v2_playbook_on_handler_task_start(self, task):
|
||||
if not self._is_lockstep:
|
||||
return
|
||||
self.results[-1]['tasks'].append(self._new_task(task))
|
||||
|
||||
def _convert_host_to_name(self, key):
|
||||
|
|
@ -118,14 +149,22 @@ class CallbackModule(CallbackBase):
|
|||
"""This function is used as a partial to add failed/skipped info in a single method"""
|
||||
host = result._host
|
||||
task = result._task
|
||||
task_result = result._result.copy()
|
||||
task_result.update(on_info)
|
||||
task_result['action'] = task.action
|
||||
self.results[-1]['tasks'][-1]['hosts'][host.name] = task_result
|
||||
|
||||
result_copy = result._result.copy()
|
||||
result_copy.update(on_info)
|
||||
result_copy['action'] = task.action
|
||||
|
||||
task_result = self._find_result_task(host, task)
|
||||
|
||||
task_result['hosts'][host.name] = result_copy
|
||||
end_time = current_time()
|
||||
self.results[-1]['tasks'][-1]['task']['duration']['end'] = end_time
|
||||
task_result['task']['duration']['end'] = end_time
|
||||
self.results[-1]['play']['duration']['end'] = end_time
|
||||
|
||||
if not self._is_lockstep:
|
||||
key = (host.get_name(), task._uuid)
|
||||
del self._task_map[key]
|
||||
|
||||
def __getattribute__(self, name):
|
||||
"""Return ``_record_task_result`` partial with a dict containing skipped/failed if necessary"""
|
||||
if name not in ('v2_runner_on_ok', 'v2_runner_on_failed', 'v2_runner_on_unreachable', 'v2_runner_on_skipped'):
|
||||
|
|
|
|||
Loading…
Reference in a new issue