summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2016-04-20 09:06:53 -0400
committerJames Cammarata <jimi@sngx.net>2016-06-14 21:43:33 -0500
commit269240db146c4d71086e9db6d698f359864012cf (patch)
tree007f2dcddb3d48c3fc55b7f2fcd4d6dfa771bebb
parente3b3ba2d39286863767e865b55f66627c0099980 (diff)
downloadansible-issue_15084_and_proposal_handler_pub_sub.tar.gz
Fixes ansible/proposals#8
-rw-r--r--lib/ansible/executor/play_iterator.py3
-rw-r--r--lib/ansible/executor/task_queue_manager.py9
-rw-r--r--lib/ansible/playbook/handler.py4
-rw-r--r--lib/ansible/plugins/strategy/__init__.py43
-rw-r--r--test/units/plugins/strategies/test_strategy_base.py14
5 files changed, 51 insertions, 22 deletions
diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py
index 72742c1a34..4ccc709e66 100644
--- a/lib/ansible/executor/play_iterator.py
+++ b/lib/ansible/executor/play_iterator.py
@@ -212,9 +212,6 @@ class PlayIterator:
# plays won't try to advance)
play_context.start_at_task = None
- # Extend the play handlers list to include the handlers defined in roles
- self._play.handlers.extend(play.compile_roles_handlers())
-
def get_host_state(self, host):
# Since we're using the PlayIterator to carry forward failed hosts,
# in the event that a previous host was not in the current inventory
diff --git a/lib/ansible/executor/task_queue_manager.py b/lib/ansible/executor/task_queue_manager.py
index 651ee20d89..10f3b50d4b 100644
--- a/lib/ansible/executor/task_queue_manager.py
+++ b/lib/ansible/executor/task_queue_manager.py
@@ -93,6 +93,7 @@ class TaskQueueManager:
# this dictionary is used to keep track of notified handlers
self._notified_handlers = dict()
+ self._listening_handlers = dict()
# dictionaries to keep track of failed/unreachable hosts
self._failed_hosts = dict()
@@ -128,6 +129,7 @@ class TaskQueueManager:
# 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()
+ self._listening_handlers.clear()
def _process_block(b):
temp_list = []
@@ -146,6 +148,10 @@ class TaskQueueManager:
for handler in handler_list:
if handler not in self._notified_handlers:
self._notified_handlers[handler] = []
+ if handler.listen:
+ if handler.listen not in self._listening_handlers:
+ self._listening_handlers[handler.listen] = []
+ self._listening_handlers[handler.listen].append(handler.get_name())
def load_callbacks(self):
'''
@@ -303,9 +309,6 @@ class TaskQueueManager:
def get_loader(self):
return self._loader
- def get_notified_handlers(self):
- return self._notified_handlers
-
def get_workers(self):
return self._workers[:]
diff --git a/lib/ansible/playbook/handler.py b/lib/ansible/playbook/handler.py
index c8c1572e48..a611b72259 100644
--- a/lib/ansible/playbook/handler.py
+++ b/lib/ansible/playbook/handler.py
@@ -20,11 +20,13 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleError
-#from ansible.inventory.host import Host
+from ansible.playbook.attribute import FieldAttribute
from ansible.playbook.task import Task
class Handler(Task):
+ _listen = FieldAttribute(isa='list')
+
def __init__(self, block=None, role=None, task_include=None):
self._flagged_hosts = []
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index 41af1efdf8..68451810d9 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -100,7 +100,8 @@ class StrategyBase:
self._tqm = tqm
self._inventory = tqm.get_inventory()
self._workers = tqm.get_workers()
- self._notified_handlers = tqm.get_notified_handlers()
+ self._notified_handlers = tqm._notified_handlers
+ self._listening_handlers = tqm._listening_handlers
self._variable_manager = tqm.get_variable_manager()
self._loader = tqm.get_loader()
self._final_q = tqm._final_q
@@ -319,7 +320,7 @@ class StrategyBase:
original_host = get_original_host(task_result._host)
original_task = iterator.get_original_task(original_host, task_result._task)
- def search_handler_blocks(handler_blocks):
+ def search_handler_blocks(handler_name, handler_blocks):
for handler_block in handler_blocks:
for handler_task in handler_block.block:
handler_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, task=handler_task)
@@ -350,20 +351,34 @@ class StrategyBase:
# roles and use the first one that matches the notify name
target_handler = None
if original_task._role:
- target_handler = search_handler_blocks(original_task._role.get_handler_blocks())
+ target_handler = search_handler_blocks(handler_name, original_task._role.get_handler_blocks())
if target_handler is None:
- target_handler = search_handler_blocks(iterator._play.handlers)
+ 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)
-
- # FIXME: this should be an error now in 2.1+
- if target_handler not in self._notified_handlers:
- self._notified_handlers[target_handler] = []
-
- 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,))
+ 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 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)
+ else:
+ print("target handler: %s" % target_handler)
+ 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:
+ print("notified handlers is: %s" % self._notified_handlers)
elif result[0] == 'register_host_var':
# essentially the same as 'set_host_var' below, however we
diff --git a/test/units/plugins/strategies/test_strategy_base.py b/test/units/plugins/strategies/test_strategy_base.py
index 132f3eb847..e079fa8d48 100644
--- a/test/units/plugins/strategies/test_strategy_base.py
+++ b/test/units/plugins/strategies/test_strategy_base.py
@@ -45,12 +45,16 @@ class TestStrategyBase(unittest.TestCase):
mock_tqm = MagicMock(TaskQueueManager)
mock_tqm._final_q = MagicMock()
mock_tqm._options = MagicMock()
+ mock_tqm._notified_handlers = {}
+ mock_tqm._listening_handlers = {}
strategy_base = StrategyBase(tqm=mock_tqm)
def test_strategy_base_run(self):
mock_tqm = MagicMock(TaskQueueManager)
mock_tqm._final_q = MagicMock()
mock_tqm._stats = MagicMock()
+ mock_tqm._notified_handlers = {}
+ mock_tqm._listening_handlers = {}
mock_tqm.send_callback.return_value = None
mock_iterator = MagicMock()
@@ -62,6 +66,8 @@ class TestStrategyBase(unittest.TestCase):
mock_tqm._failed_hosts = dict()
mock_tqm._unreachable_hosts = dict()
mock_tqm._options = MagicMock()
+ mock_tqm._notified_handlers = {}
+ mock_tqm._listening_handlers = {}
strategy_base = StrategyBase(tqm=mock_tqm)
mock_host = MagicMock()
@@ -89,6 +95,8 @@ class TestStrategyBase(unittest.TestCase):
mock_tqm = MagicMock()
mock_tqm._final_q = MagicMock()
+ mock_tqm._notified_handlers = {}
+ mock_tqm._listening_handlers = {}
mock_tqm.get_inventory.return_value = mock_inventory
mock_play = MagicMock()
@@ -153,6 +161,8 @@ class TestStrategyBase(unittest.TestCase):
mock_tqm._failed_hosts = dict()
mock_tqm._unreachable_hosts = dict()
mock_tqm.send_callback.return_value = None
+ mock_tqm._notified_handlers = {}
+ mock_tqm._listening_handlers = {}
queue_items = []
def _queue_empty(*args, **kwargs):
@@ -197,6 +207,7 @@ class TestStrategyBase(unittest.TestCase):
mock_play.handlers = [mock_handler_block]
mock_tqm._notified_handlers = {mock_handler_task: []}
+ mock_tqm._listening_handlers = {}
mock_group = MagicMock()
mock_group.add_host.return_value = None
@@ -225,7 +236,6 @@ class TestStrategyBase(unittest.TestCase):
strategy_base._inventory = mock_inventory
strategy_base._variable_manager = mock_var_mgr
strategy_base._blocked_hosts = dict()
- strategy_base._notified_handlers = dict()
results = strategy_base._wait_on_pending_results(iterator=mock_iterator)
self.assertEqual(len(results), 0)
@@ -322,6 +332,8 @@ class TestStrategyBase(unittest.TestCase):
mock_tqm = MagicMock()
mock_tqm._final_q = MagicMock()
+ mock_tqm._notified_handlers = {}
+ mock_tqm._listening_handlers = {}
strategy_base = StrategyBase(tqm=mock_tqm)
strategy_base._loader = fake_loader