flush_handlers: handle a failure in a nested block with force_handlers (#81572)

Fixes #81532

ci_complete
pull/82211/head
Martin Krizek 7 months ago committed by GitHub
parent 9c09ed7392
commit a8b6ef7e7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
bugfixes:
- flush_handlers - properly handle a handler failure in a nested block when ``force_handlers`` is set (http://github.com/ansible/ansible/issues/81532)

@ -50,7 +50,7 @@ class FailedStates(IntFlag):
TASKS = 2
RESCUE = 4
ALWAYS = 8
HANDLERS = 16
HANDLERS = 16 # NOTE not in use anymore
class HostState:
@ -429,22 +429,18 @@ class PlayIterator:
state.update_handlers = False
state.cur_handlers_task = 0
if state.fail_state & FailedStates.HANDLERS == FailedStates.HANDLERS:
state.update_handlers = True
state.run_state = IteratingStates.COMPLETE
else:
while True:
try:
task = state.handlers[state.cur_handlers_task]
except IndexError:
task = None
state.run_state = state.pre_flushing_run_state
state.update_handlers = True
while True:
try:
task = state.handlers[state.cur_handlers_task]
except IndexError:
task = None
state.run_state = state.pre_flushing_run_state
state.update_handlers = True
break
else:
state.cur_handlers_task += 1
if task.is_host_notified(host):
break
else:
state.cur_handlers_task += 1
if task.is_host_notified(host):
break
elif state.run_state == IteratingStates.COMPLETE:
return (state, None)
@ -485,20 +481,16 @@ class PlayIterator:
else:
state.fail_state |= FailedStates.ALWAYS
state.run_state = IteratingStates.COMPLETE
elif state.run_state == IteratingStates.HANDLERS:
state.fail_state |= FailedStates.HANDLERS
state.update_handlers = True
if state._blocks[state.cur_block].rescue:
state.run_state = IteratingStates.RESCUE
elif state._blocks[state.cur_block].always:
state.run_state = IteratingStates.ALWAYS
else:
state.run_state = IteratingStates.COMPLETE
return state
def mark_host_failed(self, host):
s = self.get_host_state(host)
display.debug("marking host %s failed, current state: %s" % (host, s))
if s.run_state == IteratingStates.HANDLERS:
# we are failing `meta: flush_handlers`, so just reset the state to whatever
# it was before and let `_set_failed_state` figure out the next state
s.run_state = s.pre_flushing_run_state
s.update_handlers = True
s = self._set_failed_state(s)
display.debug("^ failed state is now: %s" % s)
self.set_state_for_host(host.name, s)
@ -514,8 +506,6 @@ class PlayIterator:
return True
elif state.run_state == IteratingStates.ALWAYS and self._check_failed_state(state.always_child_state):
return True
elif state.run_state == IteratingStates.HANDLERS and state.fail_state & FailedStates.HANDLERS == FailedStates.HANDLERS:
return True
elif state.fail_state != FailedStates.NONE:
if state.run_state == IteratingStates.RESCUE and state.fail_state & FailedStates.RESCUE == 0:
return False

@ -0,0 +1,19 @@
- hosts: A,B
gather_facts: false
force_handlers: true
tasks:
- block:
- command: echo
notify: h
- meta: flush_handlers
rescue:
- debug:
msg: flush_handlers_rescued
always:
- debug:
msg: flush_handlers_always
handlers:
- name: h
fail:
when: inventory_hostname == "A"

@ -206,3 +206,7 @@ ansible-playbook force_handlers_blocks_81533-1.yml -i inventory.handlers "$@" 2>
ansible-playbook force_handlers_blocks_81533-2.yml -i inventory.handlers "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'hosts_left')" = "1" ]
ansible-playbook nested_flush_handlers_failure_force.yml -i inventory.handlers "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'flush_handlers_rescued')" = "1" ]
[ "$(grep out.txt -ce 'flush_handlers_always')" = "2" ]

Loading…
Cancel
Save