Ensure end_play ends play, not batch (#74332)

* Ensure end_play ends play, not batch

Fixes #73971

ci_complete

* Preserve result

* Move AnsibleEndPlay to TQM

* Add tests

* Add changelog

* Explaining comment

* Fix changelog name

* ci_complete
This commit is contained in:
Martin Krizek 2021-06-03 09:26:22 +02:00 committed by GitHub
parent fe20546d36
commit e201b542be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 41 additions and 2 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- Ensure end_play ends play, not batch (https://github.com/ansible/ansible/issues/73971)

View file

@ -216,6 +216,8 @@ class PlayIterator:
# plays won't try to advance) # plays won't try to advance)
play_context.start_at_task = None play_context.start_at_task = None
self.end_play = False
def get_host_state(self, host): def get_host_state(self, host):
# Since we're using the PlayIterator to carry forward failed hosts, # Since we're using the PlayIterator to carry forward failed hosts,
# in the event that a previous host was not in the current inventory # in the event that a previous host was not in the current inventory

View file

@ -23,7 +23,7 @@ import os
from ansible import constants as C from ansible import constants as C
from ansible import context from ansible import context
from ansible.executor.task_queue_manager import TaskQueueManager from ansible.executor.task_queue_manager import TaskQueueManager, AnsibleEndPlay
from ansible.module_utils._text import to_text from ansible.module_utils._text import to_text
from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.parsing.convert_bool import boolean
from ansible.plugins.loader import become_loader, connection_loader, shell_loader from ansible.plugins.loader import become_loader, connection_loader, shell_loader
@ -186,7 +186,12 @@ class PlaybookExecutor:
# restrict the inventory to the hosts in the serialized batch # restrict the inventory to the hosts in the serialized batch
self._inventory.restrict_to_hosts(batch) self._inventory.restrict_to_hosts(batch)
# and run it... # and run it...
result = self._tqm.run(play=play) try:
result = self._tqm.run(play=play)
except AnsibleEndPlay as e:
result = e.result
break_play = True
break
# break the play if the result equals the special return code # break the play if the result equals the special return code
if result & self._tqm.RUN_FAILED_BREAK_PLAY != 0: if result & self._tqm.RUN_FAILED_BREAK_PLAY != 0:

View file

@ -81,6 +81,11 @@ class FinalQueue(multiprocessing.queues.Queue):
) )
class AnsibleEndPlay(Exception):
def __init__(self, result):
self.result = result
class TaskQueueManager: class TaskQueueManager:
''' '''
@ -323,6 +328,9 @@ class TaskQueueManager:
for host_name in iterator.get_failed_hosts(): for host_name in iterator.get_failed_hosts():
self._failed_hosts[host_name] = True self._failed_hosts[host_name] = True
if iterator.end_play:
raise AnsibleEndPlay(play_return)
return play_return return play_return
def cleanup(self): def cleanup(self):

View file

@ -1161,6 +1161,9 @@ class StrategyBase:
for host in self._inventory.get_hosts(iterator._play.hosts): for host in self._inventory.get_hosts(iterator._play.hosts):
if host.name not in self._tqm._unreachable_hosts: if host.name not in self._tqm._unreachable_hosts:
iterator._host_states[host.name].run_state = iterator.ITERATING_COMPLETE iterator._host_states[host.name].run_state = iterator.ITERATING_COMPLETE
# end_play is used in PlaybookExecutor/TQM to indicate that
# the whole play is supposed to be ended as opposed to just a batch
iterator.end_play = True
msg = "ending play" msg = "ending play"
else: else:
skipped = True skipped = True

View file

@ -49,4 +49,10 @@ for test_strategy in linear free; do
grep -q "META: ending play" <<< "$out" grep -q "META: ending play" <<< "$out"
grep -qv 'Failed to end using end_play' <<< "$out" grep -qv 'Failed to end using end_play' <<< "$out"
out="$(ansible-playbook test_end_play_serial_one.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")"
[ "$(grep -c "Testing end_play on host" <<< "$out" )" -eq 1 ]
grep -q "META: ending play" <<< "$out"
grep -qv 'Failed to end using end_play' <<< "$out"
done done

View file

@ -0,0 +1,13 @@
- name: Testing end_play with serial 1 and strategy {{ test_strategy | default('linear') }}
hosts: testhost:testhost2
gather_facts: no
serial: 1
strategy: "{{ test_strategy | default('linear') }}"
tasks:
- debug:
msg: "Testing end_play on host {{ inventory_hostname }}"
- meta: end_play
- fail:
msg: 'Failed to end using end_play'