From f722d41eab009c2b75a66baadd043782168cea74 Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Mon, 15 Aug 2016 13:45:02 -0500 Subject: [PATCH] Allow notifies to be sent to the top level includes when they were static Since we introduced static includes in 2.1, this broke the functionality where a notify could be sent to a named include statement, triggering all handlers contained within the include. This patch fixes that by adding a search through the parents of a handler for any TaskIncludes which match. Fixes #15915 --- lib/ansible/plugins/strategy/__init__.py | 38 +++++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index d47826cfd8..5b3c461092 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -39,6 +39,7 @@ from ansible.inventory.group import Group from ansible.module_utils.facts import Facts from ansible.playbook.helpers import load_list_of_blocks from ansible.playbook.included_file import IncludedFile +from ansible.playbook.task_include import TaskInclude from ansible.plugins import action_loader, connection_loader, filter_loader, lookup_loader, module_loader, test_loader from ansible.template import Templar from ansible.utils.unicode import to_unicode @@ -255,6 +256,25 @@ class StrategyBase: continue return None + def parent_handler_match(target_handler, handler_name): + if target_handler: + if isinstance(target_handler, TaskInclude): + try: + handler_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, task=target_handler) + templar = Templar(loader=self._loader, variables=handler_vars) + target_handler_name = templar.template(target_handler.name) + if target_handler_name == handler_name: + return True + else: + target_handler_name = templar.template(target_handler.get_name()) + if target_handler_name == handler_name: + return True + except (UndefinedError, AnsibleUndefinedVariable) as e: + pass + return parent_handler_match(target_handler._parent, handler_name) + else: + return False + passes = 0 while not self._tqm._terminated: try: @@ -367,15 +387,25 @@ class StrategyBase: else: target_handler = search_handler_blocks(handler_name, iterator._play.handlers) - if target_handler is None: - raise AnsibleError("The requested handler '%s' was not found in any of the known handlers" % handler_name) - if target_handler in self._notified_handlers: + if target_handler is not None: if original_host not in self._notified_handlers[target_handler]: self._notified_handlers[target_handler].append(original_host) # FIXME: should this be a callback? display.vv("NOTIFIED HANDLER %s" % (handler_name,)) else: - raise AnsibleError("The requested handler '%s' was found in neither the main handlers list nor the listening handlers list" % handler_name) + # As there may be more than one handler with the notified name as the + # parent, so we just keep track of whether or not we found one at all + found = False + for target_handler in self._notified_handlers: + if parent_handler_match(target_handler, handler_name): + self._notified_handlers[target_handler].append(original_host) + display.vv("NOTIFIED HANDLER %s" % (target_handler.get_name(),)) + found = True + + # and if none were found, then we raise an error + if not found: + raise AnsibleError("The requested handler '%s' was found in neither the main handlers list nor the listening handlers list" % handler_name) + if 'add_host' in result_item: # this task added a new host (add_host module)