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 False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _send_dhcp_notification(self, resource, event, trigger, context=None,
|
def _send_dhcp_notification(self, resource, event, trigger, payload=None):
|
||||||
data=None, method_name=None, collection=None,
|
action = payload.action.split('_')[0]
|
||||||
action='', **kwargs):
|
|
||||||
action = action.split('_')[0]
|
|
||||||
if (resource in self.uses_native_notifications and
|
if (resource in self.uses_native_notifications and
|
||||||
self.uses_native_notifications[resource][action]):
|
self.uses_native_notifications[resource][action]):
|
||||||
return
|
return
|
||||||
if collection and collection in data:
|
data = payload.latest_state
|
||||||
for body in data[collection]:
|
if payload.collection_name and payload.collection_name in data:
|
||||||
|
for body in data[payload.collection_name]:
|
||||||
item = {resource: body}
|
item = {resource: body}
|
||||||
self.notify(context, item, method_name)
|
self.notify(payload.context, item, payload.method_name)
|
||||||
else:
|
else:
|
||||||
self.notify(context, data, method_name)
|
self.notify(payload.context, data, payload.method_name)
|
||||||
|
|
||||||
def notify(self, context, data, method_name):
|
def notify(self, context, data, method_name):
|
||||||
# data is {'key' : 'value'} with only one key
|
# data is {'key' : 'value'} with only one key
|
||||||
|
@ -486,11 +486,12 @@ class Controller(object):
|
|||||||
self._notifier.info(request.context,
|
self._notifier.info(request.context,
|
||||||
notifier_method,
|
notifier_method,
|
||||||
create_result)
|
create_result)
|
||||||
registry.notify(self._resource, events.BEFORE_RESPONSE, self,
|
registry.publish(self._resource, events.BEFORE_RESPONSE, self,
|
||||||
context=request.context, data=create_result,
|
payload=events.APIEventPayload(
|
||||||
method_name=notifier_method,
|
request.context, notifier_method, action,
|
||||||
collection=self._collection,
|
request_body=body,
|
||||||
action=action, original={})
|
states=({}, create_result,),
|
||||||
|
collection_name=self._collection))
|
||||||
return create_result
|
return create_result
|
||||||
|
|
||||||
def do_create(body, bulk=False, emulated=False):
|
def do_create(body, bulk=False, emulated=False):
|
||||||
@ -586,10 +587,12 @@ class Controller(object):
|
|||||||
self._notifier.info(request.context,
|
self._notifier.info(request.context,
|
||||||
notifier_method,
|
notifier_method,
|
||||||
notifier_payload)
|
notifier_payload)
|
||||||
registry.notify(self._resource, events.BEFORE_RESPONSE, self,
|
|
||||||
context=request.context, data=result,
|
registry.publish(self._resource, events.BEFORE_RESPONSE, self,
|
||||||
method_name=notifier_method, action=action,
|
payload=events.APIEventPayload(
|
||||||
original={})
|
request.context, notifier_method, action,
|
||||||
|
states=({}, obj, result,),
|
||||||
|
collection_name=self._collection))
|
||||||
|
|
||||||
def update(self, request, id, body=None, **kwargs):
|
def update(self, request, id, body=None, **kwargs):
|
||||||
"""Updates the specified entity's attributes."""
|
"""Updates the specified entity's attributes."""
|
||||||
@ -660,10 +663,12 @@ class Controller(object):
|
|||||||
result = {self._resource: self._view(request.context, obj)}
|
result = {self._resource: self._view(request.context, obj)}
|
||||||
notifier_method = self._resource + '.update.end'
|
notifier_method = self._resource + '.update.end'
|
||||||
self._notifier.info(request.context, notifier_method, result)
|
self._notifier.info(request.context, notifier_method, result)
|
||||||
registry.notify(self._resource, events.BEFORE_RESPONSE, self,
|
registry.publish(self._resource, events.BEFORE_RESPONSE, self,
|
||||||
context=request.context, data=result,
|
payload=events.APIEventPayload(
|
||||||
method_name=notifier_method, action=action,
|
request.context, notifier_method, action,
|
||||||
original=orig_object_copy)
|
request_body=body,
|
||||||
|
states=(orig_object_copy, result,),
|
||||||
|
collection_name=self._collection))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -96,10 +96,9 @@ class Notifier(object):
|
|||||||
|
|
||||||
@registry.receives(resources.PORT, [events.BEFORE_RESPONSE])
|
@registry.receives(resources.PORT, [events.BEFORE_RESPONSE])
|
||||||
@registry.receives(resources.FLOATING_IP, [events.BEFORE_RESPONSE])
|
@registry.receives(resources.FLOATING_IP, [events.BEFORE_RESPONSE])
|
||||||
def _send_nova_notification(self, resource, event, trigger,
|
def _send_nova_notification(self, resource, event, trigger, payload=None):
|
||||||
action=None, original=None, data=None,
|
self.send_network_change(payload.action, payload.states[0],
|
||||||
**kwargs):
|
payload.latest_state)
|
||||||
self.send_network_change(action, original, data)
|
|
||||||
|
|
||||||
def send_network_change(self, action, original_obj,
|
def send_network_change(self, action, original_obj,
|
||||||
returned_obj):
|
returned_obj):
|
||||||
|
@ -98,10 +98,12 @@ class NotifierHook(hooks.PecanHook):
|
|||||||
|
|
||||||
notifier_method = '%s.%s.end' % (resource_name, action)
|
notifier_method = '%s.%s.end' % (resource_name, action)
|
||||||
notifier_action = utils.get_controller(state).plugin_handlers[action]
|
notifier_action = utils.get_controller(state).plugin_handlers[action]
|
||||||
registry.notify(resource_name, events.BEFORE_RESPONSE, self,
|
registry.publish(resource_name, events.BEFORE_RESPONSE, self,
|
||||||
context=neutron_context, data=result,
|
payload=events.APIEventPayload(
|
||||||
method_name=notifier_method, action=notifier_action,
|
neutron_context, notifier_method, notifier_action,
|
||||||
collection=collection_name, original=original)
|
request_body=state.request.body,
|
||||||
|
states=(original, result,),
|
||||||
|
collection_name=collection_name))
|
||||||
|
|
||||||
if action == 'delete':
|
if action == 'delete':
|
||||||
resource_id = state.request.context.get('resource_id')
|
resource_id = state.request.context.get('resource_id')
|
||||||
|
@ -424,7 +424,7 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCallbackRegistryNotifier, self).setUp()
|
super(TestCallbackRegistryNotifier, self).setUp()
|
||||||
patcher = mock.patch('neutron.pecan_wsgi.hooks.notifier.registry')
|
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):
|
def _create(self, bulk=False):
|
||||||
if bulk:
|
if bulk:
|
||||||
@ -439,19 +439,26 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
|||||||
def test_create(self):
|
def test_create(self):
|
||||||
self._create()
|
self._create()
|
||||||
self.mock_notifier.assert_called_once_with(
|
self.mock_notifier.assert_called_once_with(
|
||||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||||
data=mock.ANY, method_name='network.create.end',
|
|
||||||
action='create_network', collection='networks', original={})
|
payload = self.mock_notifier.call_args[1]['payload']
|
||||||
actual = self.mock_notifier.call_args[1]['data']
|
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'])
|
self.assertEqual('meh-1', actual['network']['name'])
|
||||||
|
|
||||||
def test_create_bulk(self):
|
def test_create_bulk(self):
|
||||||
self._create(bulk=True)
|
self._create(bulk=True)
|
||||||
self.mock_notifier.assert_called_once_with(
|
self.mock_notifier.assert_called_once_with(
|
||||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||||
data=mock.ANY, method_name='network.create.end',
|
|
||||||
action='create_network', collection='networks', original={})
|
payload = self.mock_notifier.call_args[1]['payload']
|
||||||
actual = self.mock_notifier.call_args[1]['data']
|
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(2, len(actual['networks']))
|
||||||
self.assertEqual('meh-1', actual['networks'][0]['name'])
|
self.assertEqual('meh-1', actual['networks'][0]['name'])
|
||||||
self.assertEqual('meh-2', actual['networks'][1]['name'])
|
self.assertEqual('meh-2', actual['networks'][1]['name'])
|
||||||
@ -463,12 +470,16 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
|||||||
params={'network': {'name': 'new-meh'}},
|
params={'network': {'name': 'new-meh'}},
|
||||||
headers={'X-Project-Id': 'tenid'})
|
headers={'X-Project-Id': 'tenid'})
|
||||||
self.mock_notifier.assert_called_once_with(
|
self.mock_notifier.assert_called_once_with(
|
||||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||||
data=mock.ANY, method_name='network.update.end',
|
|
||||||
action='update_network', collection='networks', original=mock.ANY)
|
payload = self.mock_notifier.call_args[1]['payload']
|
||||||
actual_new = self.mock_notifier.call_args[1]['data']
|
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'])
|
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'])
|
self.assertEqual(network_id, actual_original['id'])
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
@ -478,8 +489,12 @@ class TestCallbackRegistryNotifier(test_functional.PecanFunctionalTest):
|
|||||||
'/v2.0/networks/%s.json' % network_id,
|
'/v2.0/networks/%s.json' % network_id,
|
||||||
headers={'X-Project-Id': 'tenid'})
|
headers={'X-Project-Id': 'tenid'})
|
||||||
self.mock_notifier.assert_called_once_with(
|
self.mock_notifier.assert_called_once_with(
|
||||||
'network', events.BEFORE_RESPONSE, mock.ANY, context=mock.ANY,
|
'network', events.BEFORE_RESPONSE, mock.ANY, payload=mock.ANY)
|
||||||
data=mock.ANY, method_name='network.delete.end',
|
|
||||||
action='delete_network', collection='networks', original={})
|
payload = self.mock_notifier.call_args[1]['payload']
|
||||||
actual = self.mock_notifier.call_args[1]['data']
|
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'])
|
self.assertEqual(network_id, actual['network']['id'])
|
||||||
|
@ -1349,7 +1349,7 @@ class RegistryNotificationTest(APIv2TestBase):
|
|||||||
instance.get_networks.return_value = initial_input
|
instance.get_networks.return_value = initial_input
|
||||||
instance.get_networks_count.return_value = 0
|
instance.get_networks_count.return_value = 0
|
||||||
expected_code = exc.HTTPCreated.code
|
expected_code = exc.HTTPCreated.code
|
||||||
with mock.patch.object(registry, 'notify') as notify:
|
with mock.patch.object(registry, 'publish') as notify:
|
||||||
if opname == 'create':
|
if opname == 'create':
|
||||||
res = self.api.post_json(
|
res = self.api.post_json(
|
||||||
_get_path('networks'),
|
_get_path('networks'),
|
||||||
|
Loading…
Reference in New Issue
Block a user