Merge "Remove deprecated method registry.notify"

This commit is contained in:
Zuul 2021-09-22 19:44:47 +00:00 committed by Gerrit Code Review
commit f9b428667b
8 changed files with 81 additions and 77 deletions

View File

@ -128,6 +128,7 @@ class CallbacksManager(object):
callback_id)
del self._index[callback_id]
@db_utils.reraise_as_retryrequest
def publish(self, resource, event, trigger, payload=None):
"""Notify all subscribed callback(s) with a payload.
@ -146,30 +147,12 @@ class CallbacksManager(object):
if not isinstance(payload, events.EventPayload):
raise exceptions.Invalid(element='event payload',
value=type(payload))
return self.notify(resource, event, trigger, payload=payload)
# NOTE(boden): We plan to deprecate the usage of this method and **kwargs
# as the payload in Queens, but no warning here to avoid log flooding
@db_utils.reraise_as_retryrequest
def notify(self, resource, event, trigger, **kwargs):
"""Notify all subscribed callback(s).
Dispatch the resource's event to the subscribed callbacks.
:param resource: The resource for the event.
:param event: The event.
:param trigger: The trigger. A reference to the sender of the event.
:param kwargs: (deprecated) Unstructured key/value pairs to invoke
the callback with. Using event objects with publish() is preferred.
:raises CallbackFailure: CallbackFailure is raised if the underlying
callback has errors.
"""
errors = self._notify_loop(resource, event, trigger, **kwargs)
errors = self._notify_loop(resource, event, trigger, payload)
if errors:
if event.startswith(events.BEFORE):
abort_event = event.replace(
events.BEFORE, events.ABORT)
self._notify_loop(resource, abort_event, trigger, **kwargs)
self._notify_loop(resource, abort_event, trigger, payload)
raise exceptions.CallbackFailure(errors=errors)
@ -181,7 +164,7 @@ class CallbacksManager(object):
self._callbacks = collections.defaultdict(dict)
self._index = collections.defaultdict(dict)
def _notify_loop(self, resource, event, trigger, **kwargs):
def _notify_loop(self, resource, event, trigger, payload):
"""The notification loop."""
errors = []
# NOTE(yamahata): Since callback may unsubscribe it,
@ -189,12 +172,12 @@ class CallbacksManager(object):
callbacks = list(itertools.chain(
*[pri_callbacks.items() for (priority, pri_callbacks)
in self._callbacks[resource].get(event, [])]))
LOG.debug("Notify callbacks %s for %s, %s",
LOG.debug("Publish callbacks %s for %s, %s",
[c[0] for c in callbacks], resource, event)
# TODO(armax): consider using a GreenPile
for callback_id, callback in callbacks:
try:
callback(resource, event, trigger, **kwargs)
callback(resource, event, trigger, payload=payload)
except Exception as e:
abortable_event = (
event.startswith(events.BEFORE) or

View File

@ -50,12 +50,6 @@ def unsubscribe_all(callback):
_get_callback_manager().unsubscribe_all(callback)
# NOTE(boden): This method is deprecated in favor of publish() and will be
# removed in Queens, but not deprecation message to reduce log flooding
def notify(resource, event, trigger, **kwargs):
_get_callback_manager().notify(resource, event, trigger, **kwargs)
def publish(resource, event, trigger, payload=None):
_get_callback_manager().publish(resource, event, trigger, payload=payload)

View File

@ -73,6 +73,7 @@ class CallBacksManagerTestCase(base.BaseTestCase):
def setUp(self):
super(CallBacksManagerTestCase, self).setUp()
self.manager = manager.CallbacksManager()
self.event_payload = events.EventPayload(object())
callback_1.counter = 0
callback_2.counter = 0
callback_3.counter = 0
@ -124,7 +125,8 @@ class CallBacksManagerTestCase(base.BaseTestCase):
self.manager.subscribe(unsub, resources.PORT,
events.BEFORE_CREATE)
self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
self.manager.publish(resources.PORT, events.BEFORE_CREATE, mock.ANY,
payload=self.event_payload)
self.assertNotIn(unsub, self.manager._index)
def test_unsubscribe(self):
@ -199,58 +201,70 @@ class CallBacksManagerTestCase(base.BaseTestCase):
self.manager._callbacks[resources.PORT][events.BEFORE_CREATE])
self.assertNotIn(callback_id_1, self.manager._index)
def test_notify_none(self):
self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
def test_publish_none(self):
self.manager.publish(resources.PORT, events.BEFORE_CREATE, mock.ANY,
payload=self.event_payload)
self.assertEqual(0, callback_1.counter)
self.assertEqual(0, callback_2.counter)
def test_feebly_referenced_callback(self):
self.manager.subscribe(lambda *x, **y: None, resources.PORT,
events.BEFORE_CREATE)
self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
self.manager.publish(resources.PORT, events.BEFORE_CREATE, mock.ANY,
payload=self.event_payload)
def test_notify_with_exception(self):
def test_publish_with_exception(self):
with mock.patch.object(self.manager, '_notify_loop') as n:
n.return_value = ['error']
self.assertRaises(exceptions.CallbackFailure,
self.manager.notify,
mock.ANY, events.BEFORE_CREATE, mock.ANY)
self.manager.publish,
mock.ANY, events.BEFORE_CREATE, mock.ANY,
payload=self.event_payload)
expected_calls = [
mock.call(mock.ANY, 'before_create', mock.ANY),
mock.call(mock.ANY, 'abort_create', mock.ANY)
mock.call(mock.ANY, 'before_create', mock.ANY,
self.event_payload),
mock.call(mock.ANY, 'abort_create', mock.ANY,
self.event_payload)
]
n.assert_has_calls(expected_calls)
def test_notify_with_precommit_exception(self):
def test_publish_with_precommit_exception(self):
with mock.patch.object(self.manager, '_notify_loop') as n:
n.return_value = ['error']
self.assertRaises(exceptions.CallbackFailure,
self.manager.notify,
mock.ANY, events.PRECOMMIT_UPDATE, mock.ANY)
self.manager.publish,
mock.ANY, events.PRECOMMIT_UPDATE, mock.ANY,
payload=self.event_payload)
expected_calls = [
mock.call(mock.ANY, 'precommit_update', mock.ANY),
mock.call(mock.ANY, 'precommit_update', mock.ANY,
self.event_payload),
]
n.assert_has_calls(expected_calls)
def test_notify_handle_exception(self):
def test_publish_handle_exception(self):
self.manager.subscribe(
callback_raise, resources.PORT, events.BEFORE_CREATE)
e = self.assertRaises(exceptions.CallbackFailure, self.manager.notify,
resources.PORT, events.BEFORE_CREATE, self)
e = self.assertRaises(exceptions.CallbackFailure, self.manager.publish,
resources.PORT, events.BEFORE_CREATE, self,
payload=self.event_payload)
self.assertIsInstance(e.errors[0], exceptions.NotificationError)
def test_notify_handle_retriable_exception(self):
def test_publish_handle_retriable_exception(self):
self.manager.subscribe(
callback_raise_retriable, resources.PORT, events.BEFORE_CREATE)
self.assertRaises(db_exc.RetryRequest, self.manager.notify,
resources.PORT, events.BEFORE_CREATE, self)
self.assertRaises(db_exc.RetryRequest, self.manager.publish,
resources.PORT, events.BEFORE_CREATE, self,
payload=self.event_payload)
def test_notify_called_once_with_no_failures(self):
def test_publish_called_once_with_no_failures(self):
with mock.patch.object(self.manager, '_notify_loop') as n:
n.return_value = False
self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
self.manager.publish(resources.PORT, events.BEFORE_CREATE,
mock.ANY,
payload=self.event_payload)
n.assert_called_once_with(
resources.PORT, events.BEFORE_CREATE, mock.ANY)
resources.PORT, events.BEFORE_CREATE, mock.ANY,
self.event_payload)
def test__notify_loop_single_event(self):
self.manager.subscribe(
@ -258,7 +272,8 @@ class CallBacksManagerTestCase(base.BaseTestCase):
self.manager.subscribe(
callback_2, resources.PORT, events.BEFORE_CREATE)
self.manager._notify_loop(
resources.PORT, events.BEFORE_CREATE, mock.ANY)
resources.PORT, events.BEFORE_CREATE, mock.ANY,
payload=mock.ANY)
self.assertEqual(1, callback_1.counter)
self.assertEqual(1, callback_2.counter)
@ -270,9 +285,11 @@ class CallBacksManagerTestCase(base.BaseTestCase):
self.manager.subscribe(
callback_2, resources.PORT, events.BEFORE_CREATE)
self.manager._notify_loop(
resources.PORT, events.BEFORE_CREATE, mock.ANY)
resources.PORT, events.BEFORE_CREATE, mock.ANY,
payload=mock.ANY)
self.manager._notify_loop(
resources.ROUTER, events.BEFORE_DELETE, mock.ANY)
resources.ROUTER, events.BEFORE_DELETE, mock.ANY,
payload=mock.ANY)
self.assertEqual(2, callback_1.counter)
self.assertEqual(1, callback_2.counter)
@ -320,7 +337,8 @@ class CallBacksManagerTestCase(base.BaseTestCase):
self.assertEqual(
3, len(self.manager._callbacks['my-resource']['my-event']))
self.manager.unsubscribe(callback_3, 'my-resource', 'my-event')
self.manager.notify('my-resource', 'my-event', mock.ANY)
self.manager.publish('my-resource', 'my-event', mock.ANY,
payload=self.event_payload)
# callback_3 should be deleted and not executed
self.assertEqual(
2, len(self.manager._callbacks['my-resource']['my-event']))
@ -340,9 +358,10 @@ class CallBacksManagerTestCase(base.BaseTestCase):
self.manager.subscribe(
callback_raise, resources.PORT, events.PRECOMMIT_CREATE)
self.manager._notify_loop(
resources.PORT, events.BEFORE_CREATE, mock.ANY)
resources.PORT, events.BEFORE_CREATE, mock.ANY, payload=mock.ANY)
self.manager._notify_loop(
resources.PORT, events.PRECOMMIT_CREATE, mock.ANY)
resources.PORT, events.PRECOMMIT_CREATE, mock.ANY,
payload=mock.ANY)
self.assertFalse(_logger.exception.call_count)
self.assertTrue(_logger.debug.call_count)
@ -357,7 +376,8 @@ class CallBacksManagerTestCase(base.BaseTestCase):
# ensure idempotency remains for a single object
self.manager.subscribe(
o.callback, resources.PORT, events.BEFORE_CREATE)
self.manager.notify(resources.PORT, events.BEFORE_CREATE, mock.ANY)
self.manager.publish(resources.PORT, events.BEFORE_CREATE, mock.ANY,
payload=events.EventPayload(object()))
self.assertEqual(1, a.counter)
self.assertEqual(1, b.counter)
self.assertEqual(1, c.counter)
@ -384,6 +404,5 @@ class CallBacksManagerTestCase(base.BaseTestCase):
notify_payload.append(payload)
self.manager.subscribe(_memo, 'x', 'y')
payload = events.EventPayload(object())
self.manager.publish('x', 'y', self, payload=payload)
self.assertEqual(payload, notify_payload[0])
self.manager.publish('x', 'y', self, payload=self.event_payload)
self.assertEqual(self.event_payload, notify_payload[0])

View File

@ -74,19 +74,26 @@ class CallBacksManagerTestCase(base.BaseTestCase):
def test_decorated_inst_method_receives(self):
i1 = ObjectWithDecoratedCallback()
registry.notify(resources.PORT, events.BEFORE_CREATE, self)
event_payload = events.EventPayload(mock.ANY)
registry.publish(resources.PORT, events.BEFORE_CREATE, self,
payload=event_payload)
self.assertEqual(0, i1.counter)
registry.notify(resources.PORT, events.AFTER_CREATE, self)
registry.publish(resources.PORT, events.AFTER_CREATE, self,
payload=event_payload)
self.assertEqual(1, i1.counter)
registry.notify(resources.PORT, events.AFTER_UPDATE, self)
registry.publish(resources.PORT, events.AFTER_UPDATE, self,
payload=event_payload)
self.assertEqual(2, i1.counter)
registry.notify(resources.NETWORK, events.AFTER_UPDATE, self)
registry.publish(resources.NETWORK, events.AFTER_UPDATE, self,
payload=event_payload)
self.assertEqual(2, i1.counter)
registry.notify(resources.NETWORK, events.AFTER_DELETE, self)
registry.publish(resources.NETWORK, events.AFTER_DELETE, self,
payload=event_payload)
self.assertEqual(3, i1.counter)
i2 = ObjectWithDecoratedCallback()
self.assertEqual(0, i2.counter)
registry.notify(resources.NETWORK, events.AFTER_DELETE, self)
registry.publish(resources.NETWORK, events.AFTER_DELETE, self,
payload=event_payload)
self.assertEqual(4, i1.counter)
self.assertEqual(1, i2.counter)
@ -148,11 +155,6 @@ class TestCallbackRegistryDispatching(base.BaseTestCase):
self.callback_manager.unsubscribe_all.assert_called_with(
my_callback)
def test_notify(self):
registry.notify('my-resource', 'my-event', mock.ANY)
self.callback_manager.notify.assert_called_with(
'my-resource', 'my-event', mock.ANY)
def test_clear(self):
registry.clear()
self.callback_manager.clear.assert_called_with()

View File

@ -50,8 +50,8 @@ class CallbackRegistryFixtureTestCase(base.BaseTestCase):
callback_manager=self.manager))
def test_fixture(self):
registry.notify('a', 'b', self)
self.assertTrue(self.manager.notify.called)
registry.publish('a', 'b', self, payload=mock.ANY)
self.assertTrue(self.manager.publish.called)
class SqlFixtureTestCase(base.BaseTestCase):

View File

@ -57,8 +57,9 @@ class TestBaseWorker(base.BaseTestCase):
def test_start_callback_event(self):
base_worker = _BaseWorker()
base_worker.start()
self._reg.notify.assert_called_once_with(
resources.PROCESS, events.AFTER_INIT, base_worker.start)
self._reg.publish.assert_called_once_with(
resources.PROCESS, events.AFTER_INIT, base_worker.start,
payload=mock.ANY)
# Forked workers, should call setproctitle

View File

@ -108,4 +108,4 @@ class BaseWorker(service.ServiceBase):
desc = desc or self.desc
self.setproctitle(name, desc)
if self.worker_process_count > 0:
registry.notify(resources.PROCESS, events.AFTER_INIT, self.start)
registry.publish(resources.PROCESS, events.AFTER_INIT, self.start)

View File

@ -0,0 +1,5 @@
---
other:
- The deprecated method neutron_lib.callbacks.registry.notify()`` and
``neutron_lib.callbacks.manager.CallbacksManager.notify()`` has been
removed in favor of their ``publish()`` counterparts