From 3e2ce2d0737122d14827605c67fe3c18eb9bc12e Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Thu, 26 Oct 2023 22:10:58 +0200 Subject: [PATCH] [stable-2.15] run_once: unnotify hosts on handlers that are not run (#81667) (#81919) Fixes #81666 (cherry picked from commit 2d5861c) --- changelogs/fragments/81666-handlers-run_once.yml | 2 ++ lib/ansible/playbook/handler.py | 3 +++ lib/ansible/plugins/strategy/__init__.py | 7 ------- lib/ansible/plugins/strategy/free.py | 2 ++ lib/ansible/plugins/strategy/linear.py | 6 ++++++ test/integration/targets/handlers/runme.sh | 3 +++ test/integration/targets/handlers/test_run_once.yml | 10 ++++++++++ 7 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/81666-handlers-run_once.yml create mode 100644 test/integration/targets/handlers/test_run_once.yml diff --git a/changelogs/fragments/81666-handlers-run_once.yml b/changelogs/fragments/81666-handlers-run_once.yml new file mode 100644 index 00000000000..e5cac9e2161 --- /dev/null +++ b/changelogs/fragments/81666-handlers-run_once.yml @@ -0,0 +1,2 @@ +bugfixes: + - Fix ``run_once`` being incorrectly interpreted on handlers (https://github.com/ansible/ansible/issues/81666) diff --git a/lib/ansible/playbook/handler.py b/lib/ansible/playbook/handler.py index 68970b4f1f0..2f2839813a7 100644 --- a/lib/ansible/playbook/handler.py +++ b/lib/ansible/playbook/handler.py @@ -53,6 +53,9 @@ class Handler(Task): def remove_host(self, host): self.notified_hosts = [h for h in self.notified_hosts if h != host] + def clear_hosts(self): + self.notified_hosts = [] + def is_host_notified(self, host): return host in self.notified_hosts diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index 426b44364f5..0302e1e4c9f 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -803,10 +803,6 @@ class StrategyBase: ret_results.append(task_result) - if isinstance(original_task, Handler): - for handler in (h for b in iterator._play.handlers for h in b.block if h._uuid == original_task._uuid): - handler.remove_host(original_host) - if one_pass or max_passes is not None and (cur_pass + 1) >= max_passes: break @@ -1094,9 +1090,6 @@ class StrategyBase: header = skip_reason if skipped else msg display.vv(f"META: {header}") - if isinstance(task, Handler): - task.remove_host(target_host) - res = TaskResult(target_host, task, result) if skipped: self._tqm.send_callback('v2_runner_on_skipped', res) diff --git a/lib/ansible/plugins/strategy/free.py b/lib/ansible/plugins/strategy/free.py index 6d1aa651d8b..f3bc3af8040 100644 --- a/lib/ansible/plugins/strategy/free.py +++ b/lib/ansible/plugins/strategy/free.py @@ -146,6 +146,8 @@ class StrategyModule(StrategyBase): # advance the host, mark the host blocked, and queue it self._blocked_hosts[host_name] = True iterator.set_state_for_host(host.name, state) + if isinstance(task, Handler): + task.remove_host(host) try: action = action_loader.get(task.action, class_only=True, collection_list=task.collections) diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py index 6a76fe57f2b..9746fcd20b8 100644 --- a/lib/ansible/plugins/strategy/linear.py +++ b/lib/ansible/plugins/strategy/linear.py @@ -242,6 +242,12 @@ class StrategyModule(StrategyBase): self._queue_task(host, task, task_vars, play_context) del task_vars + if isinstance(task, Handler): + if run_once: + task.clear_hosts() + else: + task.remove_host(host) + # if we're bypassing the host loop, break out now if run_once: break diff --git a/test/integration/targets/handlers/runme.sh b/test/integration/targets/handlers/runme.sh index 9b17dc7bbf3..757200de385 100755 --- a/test/integration/targets/handlers/runme.sh +++ b/test/integration/targets/handlers/runme.sh @@ -195,3 +195,6 @@ ansible localhost -m include_role -a "name=r1-dep_chain-vars" "$@" ansible-playbook test_include_tasks_in_include_role.yml "$@" 2>&1 | tee out.txt [ "$(grep out.txt -ce 'handler ran')" = "1" ] + +ansible-playbook test_run_once.yml -i inventory.handlers "$@" 2>&1 | tee out.txt +[ "$(grep out.txt -ce 'handler ran once')" = "1" ] diff --git a/test/integration/targets/handlers/test_run_once.yml b/test/integration/targets/handlers/test_run_once.yml new file mode 100644 index 00000000000..5418b46a6ff --- /dev/null +++ b/test/integration/targets/handlers/test_run_once.yml @@ -0,0 +1,10 @@ +- hosts: A,B,C + gather_facts: false + tasks: + - command: echo + notify: handler + handlers: + - name: handler + run_once: true + debug: + msg: handler ran once