From: Ricardo Dias Date: Wed, 21 Mar 2018 14:44:22 +0000 (+0000) Subject: mgr/dashboard: implemented NotificationQueue listener removal X-Git-Tag: v13.1.0~469^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ce8c489db87f0aa1620e13569d4b6edd0d5ac620;p=ceph.git mgr/dashboard: implemented NotificationQueue listener removal Signed-off-by: Ricardo Dias --- diff --git a/src/pybind/mgr/dashboard/tests/test_notification.py b/src/pybind/mgr/dashboard/tests/test_notification.py index b421e1eb2126..a25a381d3a33 100644 --- a/src/pybind/mgr/dashboard/tests/test_notification.py +++ b/src/pybind/mgr/dashboard/tests/test_notification.py @@ -12,10 +12,6 @@ from ..tools import NotificationQueue class Listener(object): # pylint: disable=too-many-instance-attributes def __init__(self): - NotificationQueue.register(self.log_type1, 'type1', priority=90) - NotificationQueue.register(self.log_type2, 'type2') - NotificationQueue.register(self.log_type1_3, ['type1', 'type3']) - NotificationQueue.register(self.log_all, priority=50) self.type1 = [] self.type1_ts = [] self.type2 = [] @@ -25,6 +21,12 @@ class Listener(object): self.all = [] self.all_ts = [] + def register(self): + NotificationQueue.register(self.log_type1, 'type1', priority=90) + NotificationQueue.register(self.log_type2, 'type2') + NotificationQueue.register(self.log_type1_3, ['type1', 'type3']) + NotificationQueue.register(self.log_all, priority=50) + # these should be ignored by the queue NotificationQueue.register(self.log_type1, 'type1') NotificationQueue.register(self.log_type1_3, ['type1', 'type3']) @@ -55,6 +57,10 @@ class Listener(object): self.type1_3_ts = [] self.all = [] self.all_ts = [] + NotificationQueue.deregister(self.log_type1, 'type1') + NotificationQueue.deregister(self.log_type2, 'type2') + NotificationQueue.deregister(self.log_type1_3, ['type1', 'type3']) + NotificationQueue.deregister(self.log_all) class NotificationQueueTest(unittest.TestCase): @@ -63,6 +69,9 @@ class NotificationQueueTest(unittest.TestCase): cls.listener = Listener() def setUp(self): + self.listener.register() + + def tearDown(self): self.listener.clear() def test_invalid_register(self): @@ -111,3 +120,19 @@ class NotificationQueueTest(unittest.TestCase): self.assertEqual(len(self.listener.type2), 200) self.assertEqual(len(self.listener.type1_3), 400) self.assertEqual(len(self.listener.all), 600) + + def test_deregister(self): + NotificationQueue.start_queue() + NotificationQueue.new_notification('type1', 1) + NotificationQueue.new_notification('type3', 3) + NotificationQueue.stop() + self.assertEqual(self.listener.type1, [1]) + self.assertEqual(self.listener.type1_3, [1, 3]) + + NotificationQueue.start_queue() + NotificationQueue.deregister(self.listener.log_type1_3, ['type1']) + NotificationQueue.new_notification('type1', 4) + NotificationQueue.new_notification('type3', 5) + NotificationQueue.stop() + self.assertEqual(self.listener.type1, [1, 4]) + self.assertEqual(self.listener.type1_3, [1, 3, 5]) diff --git a/src/pybind/mgr/dashboard/tools.py b/src/pybind/mgr/dashboard/tools.py index 73fa4788fd6a..1f0293a82117 100644 --- a/src/pybind/mgr/dashboard/tools.py +++ b/src/pybind/mgr/dashboard/tools.py @@ -632,18 +632,47 @@ class NotificationQueue(threading.Thread): """ with cls._lock: if not n_types: - if not cls._registered_handler(func, cls._ALL_TYPES_): - cls._listeners[cls._ALL_TYPES_].add((priority, func)) - return - if isinstance(n_types, str): - if not cls._registered_handler(func, n_types): - cls._listeners[n_types].add((priority, func)) - elif isinstance(n_types, list): - for typ in n_types: - if not cls._registered_handler(func, typ): - cls._listeners[typ].add((priority, func)) - else: + n_types = [cls._ALL_TYPES_] + elif isinstance(n_types, str): + n_types = [n_types] + elif not isinstance(n_types, list): + raise Exception("n_types param is neither a string nor a list") + for ev_type in n_types: + if not cls._registered_handler(func, ev_type): + cls._listeners[ev_type].add((priority, func)) + logger.debug("NQ: function %s was registered for events of" + " type %s", func, ev_type) + + @classmethod + def deregister(cls, func, n_types=None): + """Removes the listener function from this notification queue + + If the second parameter `n_types` is ommitted, the function is removed + from all event types, otherwise the function is removed only for the + specified event types. + + Args: + func (function): python function + n_types (str|list): the single event type, or a list of event types + """ + with cls._lock: + if not n_types: + n_types = list(cls._listeners.keys()) + elif isinstance(n_types, str): + n_types = [n_types] + elif not isinstance(n_types, list): raise Exception("n_types param is neither a string nor a list") + for ev_type in n_types: + listeners = cls._listeners[ev_type] + toRemove = None + for pr, fn in listeners: + if fn == func: + toRemove = (pr, fn) + break + if toRemove: + listeners.discard(toRemove) + logger.debug("NQ: function %s was deregistered for events " + "of type %s", func, ev_type) @classmethod def new_notification(cls, notify_type, notify_value):