From 0cba3b7504c1aabe0fc3773e3ff3ac024edeb308 Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Tue, 15 Aug 2023 15:03:56 +0200 Subject: [PATCH] Last handler with same name wins for listen too (#81358) Fixes #49371 Fixes #81013 --- .../81013-handlers-listen-last-defined-only.yml | 2 ++ lib/ansible/plugins/strategy/__init__.py | 11 +++++++++-- .../test_listen_role_dedup_global/handlers/main.yml | 4 ++++ .../roles/test_listen_role_dedup_role1/meta/main.yml | 2 ++ .../roles/test_listen_role_dedup_role1/tasks/main.yml | 3 +++ .../roles/test_listen_role_dedup_role2/meta/main.yml | 2 ++ .../roles/test_listen_role_dedup_role2/tasks/main.yml | 3 +++ test/integration/targets/handlers/runme.sh | 3 +++ .../targets/handlers/test_listen_role_dedup.yml | 5 +++++ 9 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/81013-handlers-listen-last-defined-only.yml create mode 100644 test/integration/targets/handlers/roles/test_listen_role_dedup_global/handlers/main.yml create mode 100644 test/integration/targets/handlers/roles/test_listen_role_dedup_role1/meta/main.yml create mode 100644 test/integration/targets/handlers/roles/test_listen_role_dedup_role1/tasks/main.yml create mode 100644 test/integration/targets/handlers/roles/test_listen_role_dedup_role2/meta/main.yml create mode 100644 test/integration/targets/handlers/roles/test_listen_role_dedup_role2/tasks/main.yml create mode 100644 test/integration/targets/handlers/test_listen_role_dedup.yml diff --git a/changelogs/fragments/81013-handlers-listen-last-defined-only.yml b/changelogs/fragments/81013-handlers-listen-last-defined-only.yml new file mode 100644 index 00000000000..a9493e704cc --- /dev/null +++ b/changelogs/fragments/81013-handlers-listen-last-defined-only.yml @@ -0,0 +1,2 @@ +bugfixes: + - handlers - the ``listen`` keyword can affect only one handler with the same name, the last one defined as it is a case with the ``notify`` keyword (https://github.com/ansible/ansible/issues/81013) diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index e709c4053e4..e90b54065da 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -509,8 +509,11 @@ class StrategyBase: def search_handlers_by_notification(self, notification: str, iterator: PlayIterator) -> t.Generator[Handler, None, None]: templar = Templar(None) + handlers = [h for b in reversed(iterator._play.handlers) for h in b.block] # iterate in reversed order since last handler loaded with the same name wins - for handler in (h for b in reversed(iterator._play.handlers) for h in b.block if h.name): + for handler in handlers: + if not handler.name: + continue if not handler.cached_name: if templar.is_template(handler.name): templar.available_variables = self._variable_manager.get_vars( @@ -548,7 +551,8 @@ class StrategyBase: break templar.available_variables = {} - for handler in (h for b in iterator._play.handlers for h in b.block): + seen = [] + for handler in handlers: if listeners := handler.listen: if notification in handler.get_validated_value( 'listen', @@ -556,6 +560,9 @@ class StrategyBase: listeners, templar, ): + if handler.name and handler.name in seen: + continue + seen.append(handler.name) yield handler @debug_closure diff --git a/test/integration/targets/handlers/roles/test_listen_role_dedup_global/handlers/main.yml b/test/integration/targets/handlers/roles/test_listen_role_dedup_global/handlers/main.yml new file mode 100644 index 00000000000..6ce84e44922 --- /dev/null +++ b/test/integration/targets/handlers/roles/test_listen_role_dedup_global/handlers/main.yml @@ -0,0 +1,4 @@ +- name: role_handler + debug: + msg: "a handler from a role" + listen: role_handler diff --git a/test/integration/targets/handlers/roles/test_listen_role_dedup_role1/meta/main.yml b/test/integration/targets/handlers/roles/test_listen_role_dedup_role1/meta/main.yml new file mode 100644 index 00000000000..b6a70c22524 --- /dev/null +++ b/test/integration/targets/handlers/roles/test_listen_role_dedup_role1/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - test_listen_role_dedup_global diff --git a/test/integration/targets/handlers/roles/test_listen_role_dedup_role1/tasks/main.yml b/test/integration/targets/handlers/roles/test_listen_role_dedup_role1/tasks/main.yml new file mode 100644 index 00000000000..42911e565fe --- /dev/null +++ b/test/integration/targets/handlers/roles/test_listen_role_dedup_role1/tasks/main.yml @@ -0,0 +1,3 @@ +- name: a task from role1 + command: echo + notify: role_handler diff --git a/test/integration/targets/handlers/roles/test_listen_role_dedup_role2/meta/main.yml b/test/integration/targets/handlers/roles/test_listen_role_dedup_role2/meta/main.yml new file mode 100644 index 00000000000..b6a70c22524 --- /dev/null +++ b/test/integration/targets/handlers/roles/test_listen_role_dedup_role2/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - test_listen_role_dedup_global diff --git a/test/integration/targets/handlers/roles/test_listen_role_dedup_role2/tasks/main.yml b/test/integration/targets/handlers/roles/test_listen_role_dedup_role2/tasks/main.yml new file mode 100644 index 00000000000..3d5e5446963 --- /dev/null +++ b/test/integration/targets/handlers/roles/test_listen_role_dedup_role2/tasks/main.yml @@ -0,0 +1,3 @@ +- name: a task from role2 + command: echo + notify: role_handler diff --git a/test/integration/targets/handlers/runme.sh b/test/integration/targets/handlers/runme.sh index 7cbabec2fd3..83e3d4c0de5 100755 --- a/test/integration/targets/handlers/runme.sh +++ b/test/integration/targets/handlers/runme.sh @@ -187,3 +187,6 @@ grep out.txt -e "ERROR! Using a block as a handler is not supported." ansible-playbook test_include_role_handler_once.yml -i inventory.handlers "$@" 2>&1 | tee out.txt [ "$(grep out.txt -ce 'handler ran')" = "1" ] + +ansible-playbook test_listen_role_dedup.yml "$@" 2>&1 | tee out.txt +[ "$(grep out.txt -ce 'a handler from a role')" = "1" ] diff --git a/test/integration/targets/handlers/test_listen_role_dedup.yml b/test/integration/targets/handlers/test_listen_role_dedup.yml new file mode 100644 index 00000000000..508eaf5699b --- /dev/null +++ b/test/integration/targets/handlers/test_listen_role_dedup.yml @@ -0,0 +1,5 @@ +- hosts: localhost + gather_facts: false + roles: + - test_listen_role_dedup_role1 + - test_listen_role_dedup_role2