issue callbacks per item and retry fails

- now workers passes queue to task_executor so it can send back events per item and on retry attempt
- updated result class to pass along events to strategy
- base strategy updated to forward new events to callback
- callbacks now remove 'items' on final result but process them directly when invoked per item
- new callback method to deal with retry attempt messages (also now obeys nolog)
- updated tests to match new signature of task_executor

fixes #14558
fixes #14072
This commit is contained in:
James Cammarata 2016-02-23 15:07:06 -05:00
parent 6eb4633b07
commit e02b98274b
7 changed files with 74 additions and 45 deletions

View file

@ -30,6 +30,7 @@ from ansible.compat.six import iteritems, string_types
from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleConnectionFailure
from ansible.executor.task_result import TaskResult
from ansible.playbook.conditional import Conditional
from ansible.playbook.task import Task
from ansible.template import Templar
@ -60,7 +61,7 @@ class TaskExecutor:
# the module
SQUASH_ACTIONS = frozenset(C.DEFAULT_SQUASH_ACTIONS)
def __init__(self, host, task, job_vars, play_context, new_stdin, loader, shared_loader_obj):
def __init__(self, host, task, job_vars, play_context, new_stdin, loader, shared_loader_obj, rslt_q):
self._host = host
self._task = task
self._job_vars = job_vars
@ -69,6 +70,7 @@ class TaskExecutor:
self._loader = loader
self._shared_loader_obj = shared_loader_obj
self._connection = None
self._rslt_q = rslt_q
def run(self):
'''
@ -242,7 +244,9 @@ class TaskExecutor:
# now update the result with the item info, and append the result
# to the list of results
res['item'] = item
#TODO: send item results to callback here, instead of all at the end
res['_ansible_item_result'] = True
self._rslt_q.put(TaskResult(self._host, self._task, res), block=False)
results.append(res)
return results
@ -416,6 +420,9 @@ class TaskExecutor:
return dict(unreachable=True, msg=to_unicode(e))
display.debug("handler run complete")
# preserve no log
result["_ansible_no_log"] = self._play_context.no_log
# update the local copy of vars with the registered value, if specified,
# or any facts which may have been generated by the module execution
if self._task.register:
@ -465,16 +472,18 @@ class TaskExecutor:
_evaluate_failed_when_result(result)
if attempt < retries - 1:
if retries > 1:
result['attempts'] = attempt + 1
cond = Conditional(loader=self._loader)
cond.when = [ self._task.until ]
if cond.evaluate_conditional(templar, vars_copy):
break
# no conditional check, or it failed, so sleep for the specified time
display.display("FAILED - RETRYING: %s (%d retries left). Result was: %s" % (self._task, retries-(attempt+1), result), color=C.COLOR_DEBUG)
time.sleep(delay)
else:
# no conditional check, or it failed, so sleep for the specified time
result['attempts'] = attempt + 1
result['retries'] = retries
result['_ansible_retry'] = True
display.debug('Retrying task, attempt %d of %d' % (attempt + 1, retries))
self._rslt_q.put(TaskResult(self._host, self._task, result), block=False)
time.sleep(delay)
else:
if retries > 1:
# we ran out of attempts, so mark the result as failed
@ -506,9 +515,6 @@ class TaskExecutor:
for k in ('ansible_host', ):
result["_ansible_delegated_vars"][k] = delegated_vars.get(k)
# preserve no_log setting
result["_ansible_no_log"] = self._play_context.no_log
# and return
display.debug("attempt loop complete, returning result")
return result