Fix rescuing tasks failed by any_errors_fatal

Fixes #84117
Fixes #84120
pull/84133/head
Martin Krizek 1 month ago
parent 42e2f09b97
commit 8d981766a2

@ -0,0 +1,3 @@
bugfixes:
- Fix an issue where rescued hosts were excluded from subsequent plays when ``any_errors_fatal`` was set (https://github.com/ansible/ansible/issues/84117)
- Fix an issue where ``ansible_failed_task`` and ``ansible_failed_result`` were not available for hosts failed by ``any_errors_fatal`` (https://github.com/ansible/ansible/issues/84120)

@ -602,6 +602,7 @@ class StrategyBase:
# if we're iterating on the rescue portion of a block then # if we're iterating on the rescue portion of a block then
# we save the failed task in a special var for use # we save the failed task in a special var for use
# within the rescue/always # within the rescue/always
# FIXME this code is copied in the linear strategy, see the any_errors_fatal implementation there
if iterator.is_any_block_rescuing(state_when_failed): if iterator.is_any_block_rescuing(state_when_failed):
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)

@ -38,6 +38,7 @@ from ansible.plugins.loader import action_loader
from ansible.plugins.strategy import StrategyBase from ansible.plugins.strategy import StrategyBase
from ansible.template import Templar from ansible.template import Templar
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.unsafe_proxy import wrap_var
display = Display() display = Display()
@ -311,17 +312,39 @@ class StrategyModule(StrategyBase):
display.debug("checking for any_errors_fatal") display.debug("checking for any_errors_fatal")
failed_hosts = [] failed_hosts = []
unreachable_hosts = [] unreachable_hosts = []
successful_host_results = {}
for res in results: for res in results:
if res.is_failed(): if res.is_failed():
failed_hosts.append(res._host.name) failed_hosts.append(res._host.name)
elif res.is_unreachable(): elif res.is_unreachable():
unreachable_hosts.append(res._host.name) unreachable_hosts.append(res._host.name)
else:
successful_host_results[res._host.name] = res
if any_errors_fatal and (failed_hosts or unreachable_hosts): if any_errors_fatal and (failed_hosts or unreachable_hosts):
for host in hosts_left: for host in hosts_left:
if host.name not in failed_hosts: if host.name not in failed_hosts:
self._tqm._failed_hosts[host.name] = True state_when_failed = iterator.get_state_for_host(host.name)
iterator.mark_host_failed(host) iterator.mark_host_failed(host)
# FIXME this is a copy of the code from StrategyBase._process_pending_results() to handle rescued tasks
# since any_errors_fatal is implemented here after the results processing is done we need to do the same.
# Would it make sense to move any_errors_fatal functionality to StrategyBase._process_pending_results()
# and guard it with something like strategy.supports_any_errors_fatal when it is implemented?
if iterator.is_any_block_rescuing(state_when_failed):
self._tqm._stats.increment('rescued', host.name)
iterator._play._removed_hosts.remove(host.name)
r = successful_host_results[host.name]._result.copy()
r["failed"] = True
self._variable_manager.set_nonpersistent_facts(
host.name,
{
"ansible_failed_task": wrap_var(successful_host_results[host.name]._task.serialize()),
"ansible_failed_result": r,
},
)
else:
self._tqm._failed_hosts[host.name] = True
self._tqm._stats.increment('failures', host.name)
display.debug("done checking for any_errors_fatal") display.debug("done checking for any_errors_fatal")
display.debug("checking for max_fail_percentage") display.debug("checking for max_fail_percentage")

@ -0,0 +1,16 @@
- hosts: testhost,testhost2
gather_facts: false
any_errors_fatal: true
tasks:
- block:
- fail:
when: inventory_hostname == "testhost2"
rescue:
- assert:
that:
- ansible_failed_result.failed
- assert:
that:
- '"testhost" in play_hosts'
- '"testhost2" in play_hosts'

@ -47,3 +47,5 @@ ansible-playbook -i inventory "$@" 80981.yml | tee out.txt
[ "$(grep -c 'SHOULD NOT HAPPEN' out.txt)" -eq 0 ] [ "$(grep -c 'SHOULD NOT HAPPEN' out.txt)" -eq 0 ]
[ "$(grep -c 'rescuedd' out.txt)" -eq 2 ] [ "$(grep -c 'rescuedd' out.txt)" -eq 2 ]
[ "$(grep -c 'recovered' out.txt)" -eq 2 ] [ "$(grep -c 'recovered' out.txt)" -eq 2 ]
ansible-playbook -i inventory "$@" 84117.yml

Loading…
Cancel
Save