Fix the way handlers are compiled and found/notified
* Instead of rebuilding the handler list all over the place, we now compile the handlers at the point the play is post-validated so that the view of the play in the PlayIterator contains the definitive list * Assign the dep_chain to the handlers as they're compiling, just as we do for regular tasks * Clean up the logic used to find a given handler, which is greatly simplified by the above changes Fixes #15418
This commit is contained in:
parent
729686a434
commit
930d090507
4 changed files with 32 additions and 29 deletions
|
@ -122,10 +122,6 @@ class TaskQueueManager:
|
|||
inventory hostnames for those hosts triggering the handler.
|
||||
'''
|
||||
|
||||
handlers = play.handlers
|
||||
for role in play.roles:
|
||||
handlers.extend(role.get_handler_blocks())
|
||||
|
||||
# Zero the dictionary first by removing any entries there.
|
||||
# Proxied dicts don't support iteritems, so we have to use keys()
|
||||
self._notified_handlers.clear()
|
||||
|
@ -141,7 +137,7 @@ class TaskQueueManager:
|
|||
return temp_list
|
||||
|
||||
handler_list = []
|
||||
for handler_block in handlers:
|
||||
for handler_block in play.handlers:
|
||||
handler_list.extend(_process_block(handler_block))
|
||||
|
||||
# then initialize it with the given handler list
|
||||
|
@ -220,6 +216,7 @@ class TaskQueueManager:
|
|||
|
||||
new_play = play.copy()
|
||||
new_play.post_validate(templar)
|
||||
new_play.handlers = new_play.compile_roles_handlers() + new_play.handlers
|
||||
|
||||
self.hostvars = HostVars(
|
||||
inventory=self._inventory,
|
||||
|
|
|
@ -265,7 +265,7 @@ class Play(Base, Taggable, Become):
|
|||
|
||||
if len(self.roles) > 0:
|
||||
for r in self.roles:
|
||||
block_list.extend(r.get_handler_blocks())
|
||||
block_list.extend(r.get_handler_blocks(play=self))
|
||||
|
||||
return block_list
|
||||
|
||||
|
|
|
@ -301,12 +301,24 @@ class Role(Base, Become, Conditional, Taggable):
|
|||
def get_task_blocks(self):
|
||||
return self._task_blocks[:]
|
||||
|
||||
def get_handler_blocks(self):
|
||||
def get_handler_blocks(self, play, dep_chain=None):
|
||||
block_list = []
|
||||
|
||||
# update the dependency chain here
|
||||
if dep_chain is None:
|
||||
dep_chain = []
|
||||
new_dep_chain = dep_chain + [self]
|
||||
|
||||
for dep in self.get_direct_dependencies():
|
||||
dep_blocks = dep.get_handler_blocks()
|
||||
dep_blocks = dep.get_handler_blocks(play=play, dep_chain=new_dep_chain)
|
||||
block_list.extend(dep_blocks)
|
||||
block_list.extend(self._handler_blocks)
|
||||
|
||||
for task_block in self._handler_blocks:
|
||||
new_task_block = task_block.copy()
|
||||
new_task_block._dep_chain = new_dep_chain
|
||||
new_task_block._play = play
|
||||
block_list.append(new_task_block)
|
||||
|
||||
return block_list
|
||||
|
||||
def has_run(self, host):
|
||||
|
|
|
@ -349,33 +349,27 @@ class StrategyBase:
|
|||
# dependency chain of the current task (if it's from a role), otherwise
|
||||
# we just look through the list of handlers in the current play/all
|
||||
# roles and use the first one that matches the notify name
|
||||
target_handler = None
|
||||
if original_task._role:
|
||||
target_handler = search_handler_blocks(handler_name, original_task._role.get_handler_blocks())
|
||||
if target_handler is None:
|
||||
target_handler = search_handler_blocks(handler_name, iterator._play.handlers)
|
||||
if target_handler is None:
|
||||
if handler_name in self._listening_handlers:
|
||||
for listening_handler_name in self._listening_handlers[handler_name]:
|
||||
listening_handler = None
|
||||
if original_task._role:
|
||||
listening_handler = search_handler_blocks(listening_handler_name, original_task._role.get_handler_blocks())
|
||||
if listening_handler is None:
|
||||
listening_handler = search_handler_blocks(listening_handler_name, iterator._play.handlers)
|
||||
if listening_handler is None:
|
||||
raise AnsibleError("The requested handler listener '%s' was not found in any of the known handlers" % listening_handler_name)
|
||||
if handler_name in self._listening_handlers:
|
||||
for listening_handler_name in self._listening_handlers[handler_name]:
|
||||
listening_handler = search_handler_blocks(listening_handler_name, iterator._play.handlers)
|
||||
if listening_handler is None:
|
||||
raise AnsibleError("The requested handler listener '%s' was not found in any of the known handlers" % listening_handler_name)
|
||||
|
||||
if original_host not in self._notified_handlers[listening_handler]:
|
||||
self._notified_handlers[listening_handler].append(original_host)
|
||||
display.vv("NOTIFIED HANDLER %s" % (listening_handler_name,))
|
||||
else:
|
||||
raise AnsibleError("The requested handler '%s' was found in neither the main handlers list nor the listening handlers list" % handler_name)
|
||||
if original_host not in self._notified_handlers[listening_handler]:
|
||||
self._notified_handlers[listening_handler].append(original_host)
|
||||
display.vv("NOTIFIED HANDLER %s" % (listening_handler_name,))
|
||||
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 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)
|
||||
|
||||
elif result[0] == 'register_host_var':
|
||||
# essentially the same as 'set_host_var' below, however we
|
||||
|
|
Loading…
Reference in a new issue