Add ability to send notifications for actors
Previously, keystone didn't have the ability to send notifications for actor/target relationships due to the structure of the payload. The payload was always expected to be the ID and type of one entity. In notifications that have relationships (like adding or removing users from groups), it is useful to know who was added to what. This commit introduces the ability to send information about who was added or removed from an entity. Change-Id: Iea4437a265f1910a1171b9bcac99d853f5015440 Partial-Bug: 1552639
This commit is contained in:
parent
e2ee064192
commit
06e4bb776c
@ -109,7 +109,8 @@ class Audit(object):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _emit(cls, operation, resource_type, resource_id, initiator, public):
|
||||
def _emit(cls, operation, resource_type, resource_id, initiator, public,
|
||||
actor_dict=None):
|
||||
"""Directly send an event notification.
|
||||
|
||||
:param operation: one of the values from ACTIONS
|
||||
@ -120,6 +121,8 @@ class Audit(object):
|
||||
:param public: If True (default), the event will be sent to the
|
||||
notifier API. If False, the event will only be sent via
|
||||
notify_event_callbacks to in process listeners
|
||||
:param actor_dict: dictionary of actor information in the event of
|
||||
assignment notification
|
||||
"""
|
||||
# NOTE(stevemar): the _send_notification function is
|
||||
# overloaded, it's used to register callbacks and to actually
|
||||
@ -130,6 +133,7 @@ class Audit(object):
|
||||
operation,
|
||||
resource_type,
|
||||
resource_id,
|
||||
actor_dict,
|
||||
public=public)
|
||||
|
||||
if CONF.notification_format == 'cadf' and public:
|
||||
@ -161,6 +165,24 @@ class Audit(object):
|
||||
cls._emit(ACTIONS.deleted, resource_type, resource_id, initiator,
|
||||
public)
|
||||
|
||||
@classmethod
|
||||
def added_to(cls, target_type, target_id, actor_type, actor_id,
|
||||
initiator=None, public=True):
|
||||
actor_dict = {'id': actor_id,
|
||||
'type': actor_type,
|
||||
'actor_operation': 'added'}
|
||||
cls._emit(ACTIONS.updated, target_type, target_id, initiator, public,
|
||||
actor_dict=actor_dict)
|
||||
|
||||
@classmethod
|
||||
def removed_from(cls, target_type, target_id, actor_type, actor_id,
|
||||
initiator=None, public=True):
|
||||
actor_dict = {'id': actor_id,
|
||||
'type': actor_type,
|
||||
'actor_operation': 'removed'}
|
||||
cls._emit(ACTIONS.updated, target_type, target_id, initiator, public,
|
||||
actor_dict=actor_dict)
|
||||
|
||||
|
||||
class ManagerNotificationWrapper(object):
|
||||
"""Send event notifications for ``Manager`` methods.
|
||||
@ -450,7 +472,8 @@ def _create_cadf_payload(operation, resource_type, resource_id,
|
||||
target, event_type, **audit_kwargs)
|
||||
|
||||
|
||||
def _send_notification(operation, resource_type, resource_id, public=True):
|
||||
def _send_notification(operation, resource_type, resource_id, actor_dict=None,
|
||||
public=True):
|
||||
"""Send notification to inform observers about the affected resource.
|
||||
|
||||
This method doesn't raise an exception when sending the notification fails.
|
||||
@ -458,6 +481,7 @@ def _send_notification(operation, resource_type, resource_id, public=True):
|
||||
:param operation: operation being performed (created, updated, or deleted)
|
||||
:param resource_type: type of resource being operated on
|
||||
:param resource_id: ID of resource being operated on
|
||||
:param actor_dict: a dictionary containing the actor's ID and type
|
||||
:param public: if True (default), the event will be sent
|
||||
to the notifier API.
|
||||
if False, the event will only be sent via
|
||||
@ -465,6 +489,11 @@ def _send_notification(operation, resource_type, resource_id, public=True):
|
||||
"""
|
||||
payload = {'resource_info': resource_id}
|
||||
|
||||
if actor_dict:
|
||||
payload['actor_id'] = actor_dict['id']
|
||||
payload['actor_type'] = actor_dict['type']
|
||||
payload['actor_operation'] = actor_dict['actor_operation']
|
||||
|
||||
notify_event_callbacks(SERVICE, resource_type, operation, payload)
|
||||
|
||||
# Only send this notification if the 'basic' format is used, otherwise
|
||||
|
@ -290,13 +290,17 @@ class BaseNotificationTest(test_v3.RestfulTestCase):
|
||||
self._audits = []
|
||||
|
||||
def fake_notify(operation, resource_type, resource_id,
|
||||
public=True):
|
||||
actor_dict=None, public=True):
|
||||
note = {
|
||||
'resource_id': resource_id,
|
||||
'operation': operation,
|
||||
'resource_type': resource_type,
|
||||
'send_notification_called': True,
|
||||
'public': public}
|
||||
if actor_dict:
|
||||
note['actor_id'] = actor_dict.get('id')
|
||||
note['actor_type'] = actor_dict.get('type')
|
||||
note['actor_operation'] = actor_dict.get('actor_operation')
|
||||
self._notifications.append(note)
|
||||
|
||||
self.useFixture(mockpatch.PatchObject(
|
||||
@ -326,7 +330,9 @@ class BaseNotificationTest(test_v3.RestfulTestCase):
|
||||
self.useFixture(mockpatch.PatchObject(
|
||||
notifications, '_send_audit_notification', fake_audit))
|
||||
|
||||
def _assert_last_note(self, resource_id, operation, resource_type):
|
||||
def _assert_last_note(self, resource_id, operation, resource_type,
|
||||
actor_id=None, actor_type=None,
|
||||
actor_operation=None):
|
||||
# NOTE(stevemar): If 'basic' format is not used, then simply
|
||||
# return since this assertion is not valid.
|
||||
if CONF.notification_format != 'basic':
|
||||
@ -337,6 +343,10 @@ class BaseNotificationTest(test_v3.RestfulTestCase):
|
||||
self.assertEqual(resource_id, note['resource_id'])
|
||||
self.assertEqual(resource_type, note['resource_type'])
|
||||
self.assertTrue(note['send_notification_called'])
|
||||
if actor_id:
|
||||
self.assertEqual(actor_id, note['actor_id'])
|
||||
self.assertEqual(actor_type, note['actor_type'])
|
||||
self.assertEqual(actor_operation, note['actor_operation'])
|
||||
|
||||
def _assert_last_audit(self, resource_id, operation, resource_type,
|
||||
target_uri):
|
||||
|
Loading…
x
Reference in New Issue
Block a user