Propagate ansible_failed_task to an outer rescue (#78676)

Fixes #43191
Fixes #72638
Fixes #78042

Co-authored-by: Sandra McCann <samccann@redhat.com>
pull/78720/head
Martin Krizek 2 years ago committed by GitHub
parent 848143640b
commit fd19ff2310
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
bugfixes:
- Propagate ``ansible_failed_task`` and ``ansible_failed_result`` to an outer rescue (https://github.com/ansible/ansible/issues/43191)

@ -177,6 +177,10 @@ ansible_failed_task
ansible_failed_result ansible_failed_result
The captured return result of the failed task that triggered the rescue. This would equate to having used this var in the ``register`` keyword. The captured return result of the failed task that triggered the rescue. This would equate to having used this var in the ``register`` keyword.
.. note::
In ``ansible-core`` 2.14 or later, both variables are propagated from an inner block to an outer ``rescue`` portion of a block.
.. seealso:: .. seealso::
:ref:`playbooks_intro` :ref:`playbooks_intro`

@ -571,10 +571,14 @@ class PlayIterator:
Given the current HostState state, determines if the current block, or any child blocks, Given the current HostState state, determines if the current block, or any child blocks,
are in rescue mode. are in rescue mode.
''' '''
if state.run_state == IteratingStates.RESCUE: if state.get_current_block().rescue:
return True return True
if state.tasks_child_state is not None: if state.tasks_child_state is not None:
return self.is_any_block_rescuing(state.tasks_child_state) return self.is_any_block_rescuing(state.tasks_child_state)
if state.rescue_child_state is not None:
return self.is_any_block_rescuing(state.rescue_child_state)
if state.always_child_state is not None:
return self.is_any_block_rescuing(state.always_child_state)
return False return False
def get_original_task(self, host, task): def get_original_task(self, host, task):

@ -560,20 +560,15 @@ class StrategyBase:
else: else:
iterator.mark_host_failed(original_host) iterator.mark_host_failed(original_host)
# grab the current state and if we're iterating on the rescue portion
# of a block then we save the failed task in a special var for use
# within the rescue/always
state, _ = iterator.get_next_task_for_host(original_host, peek=True) state, _ = iterator.get_next_task_for_host(original_host, peek=True)
if iterator.is_failed(original_host) and state and state.run_state == IteratingStates.COMPLETE: if iterator.is_failed(original_host) and state and state.run_state == IteratingStates.COMPLETE:
self._tqm._failed_hosts[original_host.name] = True self._tqm._failed_hosts[original_host.name] = True
# Use of get_active_state() here helps detect proper state if, say, we are in a rescue # if we're iterating on the rescue portion of a block then
# block from an included file (include_tasks). In a non-included rescue case, a rescue # we save the failed task in a special var for use
# that starts with a new 'block' will have an active state of IteratingStates.TASKS, so we also # within the rescue/always
# check the current state block tree to see if any blocks are rescuing. if iterator.is_any_block_rescuing(state):
if state and (iterator.get_active_state(state).run_state == IteratingStates.RESCUE or
iterator.is_any_block_rescuing(state)):
self._tqm._stats.increment('rescued', original_host.name) self._tqm._stats.increment('rescued', original_host.name)
iterator._play._removed_hosts.remove(original_host.name) iterator._play._removed_hosts.remove(original_host.name)
self._variable_manager.set_nonpersistent_facts( self._variable_manager.set_nonpersistent_facts(

@ -0,0 +1,17 @@
- hosts: localhost
gather_facts: false
tasks:
- block:
- block:
- name: EXPECTED FAILURE
fail:
always:
- block:
- debug:
always:
- debug:
rescue:
- assert:
that:
- ansible_failed_task is defined
- ansible_failed_result is defined

@ -0,0 +1,18 @@
- hosts: localhost
gather_facts: false
tasks:
- block:
- block:
- name: EXPECTED FAILURE
fail:
always:
- block:
- block:
- debug:
rescue:
- block:
- block:
- assert:
that:
- ansible_failed_task is defined
- ansible_failed_result is defined

@ -124,3 +124,6 @@ ansible-playbook -i host1,host2 -vv 78612.yml | tee 78612.out
set -e set -e
[ "$(grep -c 'PASSED' 78612.out)" -eq 1 ] [ "$(grep -c 'PASSED' 78612.out)" -eq 1 ]
rm -f 78612.out rm -f 78612.out
ansible-playbook -vv 43191.yml
ansible-playbook -vv 43191-2.yml

Loading…
Cancel
Save