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:
Boden R 2017-12-14 14:12:34 -07:00 committed by garyk
parent 2bfc219e88
commit 3f1a9846d2
6 changed files with 68 additions and 48 deletions

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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')

View File

@ -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'])

View File

@ -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'),