use callback payloads for REQUEST/RESPONSE events
This patch switches callbacks over to the payload object style events [1] for BEFORE_RESPONSE and AFTER_REQUEST based notifications. To do so an APIEventPayload object is used with the publish() method to pass along the API related data. In addition a few UTs are updated to work with the changes. NeutronLibImpact [1] https://docs.openstack.org/neutron-lib/latest/contributor/callbacks.html#event-payloads Change-Id: Ibd8559e0db9dcc995abf8937a0cb764b21a18531
This commit is contained in:
parent
2bfc219e88
commit
3f1a9846d2
@ -261,19 +261,18 @@ class DhcpAgentNotifyAPI(object):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _send_dhcp_notification(self, resource, event, trigger, context=None,
|
||||
data=None, method_name=None, collection=None,
|
||||
action='', **kwargs):
|
||||
action = action.split('_')[0]
|
||||
def _send_dhcp_notification(self, resource, event, trigger, payload=None):
|
||||
action = payload.action.split('_')[0]
|
||||
if (resource in self.uses_native_notifications and
|
||||
self.uses_native_notifications[resource][action]):
|
||||
return
|
||||
if collection and collection in data:
|
||||
for body in data[collection]:
|
||||
data = payload.latest_state
|
||||
if payload.collection_name and payload.collection_name in data:
|
||||
for body in data[payload.collection_name]:
|
||||
item = {resource: body}
|
||||
self.notify(context, item, method_name)
|
||||
self.notify(payload.context, item, payload.method_name)
|
||||
else:
|
||||
self.notify(context, data, method_name)
|
||||
self.notify(payload.context, data, payload.method_name)
|
||||
|
||||
def notify(self, context, data, method_name):
|
||||
# data is {'key' : 'value'} with only one key
|
||||
|
@ -486,11 +486,12 @@ class Controller(object):
|
||||
self._notifier.info(request.context,
|
||||
notifier_method,
|
||||
create_result)
|
||||
registry.notify(self._resource, events.BEFORE_RESPONSE, self,
|
||||
context=request.context, data=create_result,
|
||||
method_name=notifier_method,
|
||||
collection=self._collection,
|
||||
action=action, original={})
|
||||
registry.publish(self._resource, events.BEFORE_RESPONSE, self,
|
||||
payload=events.APIEventPayload(
|
||||
request.context, notifier_method, action,
|
||||
request_body=body,
|
||||
states=({}, create_result,),
|
||||
collection_name=self._collection))
|
||||
return create_result
|
||||
|
||||
def do_create(body, bulk=False, emulated=False):
|
||||
@ -586,10 +587,12 @@ class Controller(object):
|
||||
self._notifier.info(request.context,
|
||||
notifier_method,
|
||||
notifier_payload)
|
||||
registry.notify(self._resource, events.BEFORE_RESPONSE, self,
|
||||
context=request.context, data=result,
|
||||
method_name=notifier_method, action=action,
|
||||
original={})
|
||||
|
||||
registry.publish(self._resource, events.BEFORE_RESPONSE, self,
|
||||
payload=events.APIEventPayload(
|
||||
request.context, notifier_method, action,
|
||||
states=({}, obj, result,),
|
||||
collection_name=self._collection))
|
||||
|
||||
def update(self, request, id, body=None, **kwargs):
|
||||
"""Updates the specified entity's attributes."""
|
||||
@ -660,10 +663,12 @@ class Controller(object):
|
||||
result = {self._resource: self._view(request.context, obj)}
|
||||
notifier_method = self._resource + '.update.end'
|
||||
self._notifier.info(request.context, notifier_method, result)
|
||||
registry.notify(self._resource, events.BEFORE_RESPONSE, self,
|
||||
context=request.context, data=result,
|
||||
method_name=notifier_method, action=action,
|
||||
original=orig_object_copy)
|
||||
registry.publish(self._resource, events.BEFORE_RESPONSE, self,
|
||||
payload=events.APIEventPayload(
|
||||
request.context, notifier_method, action,
|
||||
request_body=body,
|
||||
states=(orig_object_copy, result,),
|
||||
collection_name=self._collection))
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
|
@ -96,10 +96,9 @@ class Notifier(object):
|
||||
|
||||
@registry.receives(resources.PORT, [events.BEFORE_RESPONSE])
|
||||
@registry.receives(resources.FLOATING_IP, [events.BEFORE_RESPONSE])
|
||||
def _send_nova_notification(self, resource, event, trigger,
|
||||
action=None, original=None, data=None,
|
||||
**kwargs):
|
||||
self.send_network_change(action, original, data)
|
||||
def _send_nova_notification(self, resource, event, trigger, payload=None):
|
||||
self.send_network_change(payload.action, payload.states[0],
|
||||
payload.latest_state)
|
||||
|
||||
def send_network_change(self, action, original_obj,
|
||||
returned_obj):
|
||||
|
@ -98,10 +98,12 @@ class NotifierHook(hooks.PecanHook):
|
||||
|
||||
notifier_method = '%s.%s.end' % (resource_name, action)
|
||||
notifier_action = utils.get_controller(state).plugin_handlers[action]
|
||||
registry.notify(resource_name, events.BEFORE_RESPONSE, self,
|
||||
context=neutron_context, data=result,
|
||||
method_name=notifier_method, action=notifier_action,
|
||||
collection=collection_name, original=original)
|
||||
registry.publish(resource_name, events.BEFORE_RESPONSE, self,
|
||||
payload=events.APIEventPayload(
|
||||
neutron_context, notifier_method, notifier_action,
|
||||
request_body=state.request.body,
|
||||
states=(original, result,),
|
||||
collection_name=collection_name))
|
||||
|
||||
if action == 'delete':
|
||||
resource_id = state.request.context.get('resource_id')
|
||||
|
@ -424,7 +424,7 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
||||
def setUp(self):
|
||||
super(TestCallbackRegistryNotifier, self).setUp()
|
||||
patcher = mock.patch('neutron.pecan_wsgi.hooks.notifier.registry')
|
||||
self.mock_notifier = patcher.start().notify
|
||||
self.mock_notifier = patcher.start().publish
|
||||
|
||||
def _create(self, bulk=False):
|
||||
if bulk:
|
||||
@ -439,19 +439,26 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
||||
def test_create(self):
|
||||
self._create()
|
||||
self.mock_notifier.assert_called_once_with(
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
||||
data=mock.ANY, method_name='network.create.end',
|
||||
action='create_network', collection='networks', original={})
|
||||
actual = self.mock_notifier.call_args[1]['data']
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||
|
||||
payload = self.mock_notifier.call_args[1]['payload']
|
||||
self.assertEqual('network.create.end', payload.method_name)
|
||||
self.assertEqual('create_network', payload.action)
|
||||
self.assertEqual('networks', payload.collection_name)
|
||||
|
||||
actual = payload.latest_state
|
||||
self.assertEqual('meh-1', actual['network']['name'])
|
||||
|
||||
def test_create_bulk(self):
|
||||
self._create(bulk=True)
|
||||
self.mock_notifier.assert_called_once_with(
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
||||
data=mock.ANY, method_name='network.create.end',
|
||||
action='create_network', collection='networks', original={})
|
||||
actual = self.mock_notifier.call_args[1]['data']
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||
|
||||
payload = self.mock_notifier.call_args[1]['payload']
|
||||
self.assertEqual('network.create.end', payload.method_name)
|
||||
self.assertEqual('create_network', payload.action)
|
||||
self.assertEqual('networks', payload.collection_name)
|
||||
actual = payload.latest_state
|
||||
self.assertEqual(2, len(actual['networks']))
|
||||
self.assertEqual('meh-1', actual['networks'][0]['name'])
|
||||
self.assertEqual('meh-2', actual['networks'][1]['name'])
|
||||
@ -463,12 +470,16 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
||||
params={'network': {'name': 'new-meh'}},
|
||||
headers={'X-Project-Id': 'tenid'})
|
||||
self.mock_notifier.assert_called_once_with(
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
||||
data=mock.ANY, method_name='network.update.end',
|
||||
action='update_network', collection='networks', original=mock.ANY)
|
||||
actual_new = self.mock_notifier.call_args[1]['data']
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||
|
||||
payload = self.mock_notifier.call_args[1]['payload']
|
||||
self.assertEqual('network.update.end', payload.method_name)
|
||||
self.assertEqual('update_network', payload.action)
|
||||
self.assertEqual('networks', payload.collection_name)
|
||||
|
||||
actual_new = payload.latest_state
|
||||
self.assertEqual('new-meh', actual_new['network']['name'])
|
||||
actual_original = self.mock_notifier.call_args[1]['original']
|
||||
actual_original = payload.states[0]
|
||||
self.assertEqual(network_id, actual_original['id'])
|
||||
|
||||
def test_delete(self):
|
||||
@ -478,8 +489,12 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
||||
'/v2.0/networks/%s.json' % network_id,
|
||||
headers={'X-Project-Id': 'tenid'})
|
||||
self.mock_notifier.assert_called_once_with(
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
||||
data=mock.ANY, method_name='network.delete.end',
|
||||
action='delete_network', collection='networks', original={})
|
||||
actual = self.mock_notifier.call_args[1]['data']
|
||||
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||
|
||||
payload = self.mock_notifier.call_args[1]['payload']
|
||||
self.assertEqual('network.delete.end', payload.method_name)
|
||||
self.assertEqual('delete_network', payload.action)
|
||||
self.assertEqual('networks', payload.collection_name)
|
||||
|
||||
actual = payload.latest_state
|
||||
self.assertEqual(network_id, actual['network']['id'])
|
||||
|
@ -1349,7 +1349,7 @@ class RegistryNotificationTest(APIv2TestBase):
|
||||
instance.get_networks.return_value = initial_input
|
||||
instance.get_networks_count.return_value = 0
|
||||
expected_code = exc.HTTPCreated.code
|
||||
with mock.patch.object(registry, 'notify') as notify:
|
||||
with mock.patch.object(registry, 'publish') as notify:
|
||||
if opname == 'create':
|
||||
res = self.api.post_json(
|
||||
_get_path('networks'),
|
||||
|
Loading…
Reference in New Issue
Block a user