diff --git a/changelogs/fragments/85475-fix-flush_handlers-play-tags.yml b/changelogs/fragments/85475-fix-flush_handlers-play-tags.yml new file mode 100644 index 00000000000..b4994345a4a --- /dev/null +++ b/changelogs/fragments/85475-fix-flush_handlers-play-tags.yml @@ -0,0 +1,2 @@ +bugfixes: + - Fix issue where play tags prevented executing notified handlers (https://github.com/ansible/ansible/issues/85475) diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py index a47bdc31e45..37d4fa7ebe8 100644 --- a/lib/ansible/playbook/block.py +++ b/lib/ansible/playbook/block.py @@ -17,7 +17,6 @@ from __future__ import annotations -import ansible.constants as C from ansible.errors import AnsibleParserError from ansible.module_utils.common.sentinel import Sentinel from ansible.playbook.attribute import NonInheritableFieldAttribute @@ -376,8 +375,7 @@ class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatab filtered_block = evaluate_block(task) if filtered_block.has_tasks(): tmp_list.append(filtered_block) - elif ((task.action in C._ACTION_META and task.implicit) or - task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars)): + elif task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars): tmp_list.append(task) return tmp_list diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index 461a0a39258..c0bfcd6debf 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -307,19 +307,9 @@ class Play(Base, Taggable, CollectionSearch): t.args['_raw_params'] = 'flush_handlers' t.implicit = True t.set_loader(self._loader) + t.tags = ['always'] - if self.tags: - # Avoid calling flush_handlers in case the whole play is skipped on tags, - # this could be performance improvement since calling flush_handlers on - # large inventories could be expensive even if no hosts are notified - # since we call flush_handlers per host. - # Block.filter_tagged_tasks ignores evaluating tags on implicit meta - # tasks so we need to explicitly call Task.evaluate_tags here. - t.tags = self.tags - if t.evaluate_tags(self.only_tags, self.skip_tags, all_vars=self.vars): - flush_block.block = [t] - else: - flush_block.block = [t] + flush_block.block = [t] # NOTE keep flush_handlers tasks even if a section has no regular tasks, # there may be notified handlers from the previous section diff --git a/test/integration/targets/handlers/runme.sh b/test/integration/targets/handlers/runme.sh index 648eb87bb91..51097192aeb 100755 --- a/test/integration/targets/handlers/runme.sh +++ b/test/integration/targets/handlers/runme.sh @@ -229,6 +229,13 @@ ansible-playbook handler_notify_earlier_handler.yml "$@" 2>&1 | tee out.txt ANSIBLE_DEBUG=1 ansible-playbook tagged_play.yml --skip-tags the_whole_play "$@" 2>&1 | tee out.txt [ "$(grep out.txt -ce 'META: triggered running handlers')" = "0" ] +[ "$(grep out.txt -ce 'No handler notifications for')" = "0" ] [ "$(grep out.txt -ce 'handler_ran')" = "0" ] +[ "$(grep out.txt -ce 'handler1_ran')" = "0" ] ansible-playbook rescue_flush_handlers.yml "$@" + +ANSIBLE_DEBUG=1 ansible-playbook tagged_play.yml --tags task_tag "$@" 2>&1 | tee out.txt +[ "$(grep out.txt -ce 'META: triggered running handlers')" = "1" ] +[ "$(grep out.txt -ce 'handler_ran')" = "0" ] +[ "$(grep out.txt -ce 'handler1_ran')" = "1" ] diff --git a/test/integration/targets/handlers/tagged_play.yml b/test/integration/targets/handlers/tagged_play.yml index e96348dcd12..8c209faaef1 100644 --- a/test/integration/targets/handlers/tagged_play.yml +++ b/test/integration/targets/handlers/tagged_play.yml @@ -2,9 +2,19 @@ gather_facts: false tags: the_whole_play tasks: - - command: echo + - debug: + changed_when: true notify: h + + - debug: + changed_when: true + notify: h1 + tags: task_tag handlers: - name: h debug: msg: handler_ran + + - name: h1 + debug: + msg: handler1_ran