diff --git a/changelogs/fragments/78612-rescue-block-ansible_play_hosts.yml b/changelogs/fragments/78612-rescue-block-ansible_play_hosts.yml new file mode 100644 index 00000000000..3e200231479 --- /dev/null +++ b/changelogs/fragments/78612-rescue-block-ansible_play_hosts.yml @@ -0,0 +1,2 @@ +bugfixes: + - "Fix an issue where ``ansible_play_hosts`` and ``ansible_play_batch`` were not properly updated when a failure occured in an explicit block inside the rescue section (https://github.com/ansible/ansible/issues/78612)" diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py index ed5b99dea63..a60848a521a 100644 --- a/lib/ansible/executor/play_iterator.py +++ b/lib/ansible/executor/play_iterator.py @@ -366,9 +366,6 @@ class PlayIterator: elif state.run_state == IteratingStates.RESCUE: # The process here is identical to IteratingStates.TASKS, except instead # we move into the always portion of the block. - if host.name in self._play._removed_hosts: - self._play._removed_hosts.remove(host.name) - if state.rescue_child_state: (state.rescue_child_state, task) = self._get_next_task_from_state(state.rescue_child_state, host=host) if self._check_failed_state(state.rescue_child_state): diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index 9ce32fc51c8..c3c1a390ea0 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -575,6 +575,7 @@ class StrategyBase: 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) + iterator._play._removed_hosts.remove(original_host.name) self._variable_manager.set_nonpersistent_facts( original_host.name, dict( diff --git a/test/integration/targets/blocks/78612.yml b/test/integration/targets/blocks/78612.yml new file mode 100644 index 00000000000..38efc6bb857 --- /dev/null +++ b/test/integration/targets/blocks/78612.yml @@ -0,0 +1,16 @@ +- hosts: all + gather_facts: false + tasks: + - block: + - fail: + when: inventory_hostname == 'host1' + rescue: + - block: + - fail: + when: inventory_hostname == 'host1' + + - assert: + that: + - "'host1' not in ansible_play_hosts" + - "'host1' not in ansible_play_batch" + success_msg: PASSED diff --git a/test/integration/targets/blocks/runme.sh b/test/integration/targets/blocks/runme.sh index 9b6c08ecece..4c345df1a99 100755 --- a/test/integration/targets/blocks/runme.sh +++ b/test/integration/targets/blocks/runme.sh @@ -118,3 +118,9 @@ set -e cat 72781.out [ "$(grep -c 'SHOULD NOT HAPPEN' 72781.out)" -eq 0 ] rm -f 72781.out + +set +e +ansible-playbook -i host1,host2 -vv 78612.yml | tee 78612.out +set -e +[ "$(grep -c 'PASSED' 78612.out)" -eq 1 ] +rm -f 78612.out