aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/notifications.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/notifications.py')
-rw-r--r--keystone-moon/keystone/notifications.py88
1 files changed, 76 insertions, 12 deletions
diff --git a/keystone-moon/keystone/notifications.py b/keystone-moon/keystone/notifications.py
index 4a1cd333..801dd737 100644
--- a/keystone-moon/keystone/notifications.py
+++ b/keystone-moon/keystone/notifications.py
@@ -15,12 +15,14 @@
"""Notifications module for OpenStack Identity Service resources"""
import collections
+import functools
import inspect
import logging
import socket
from oslo_config import cfg
from oslo_log import log
+from oslo_log import versionutils
import oslo_messaging
import pycadf
from pycadf import cadftaxonomy as taxonomy
@@ -36,12 +38,12 @@ notifier_opts = [
cfg.StrOpt('default_publisher_id',
help='Default publisher_id for outgoing notifications'),
cfg.StrOpt('notification_format', default='basic',
+ choices=['basic', 'cadf'],
help='Define the notification format for Identity Service '
'events. A "basic" notification has information about '
'the resource being operated on. A "cadf" notification '
'has the same information, as well as information about '
- 'the initiator of the event. Valid options are: basic '
- 'and cadf'),
+ 'the initiator of the event.'),
]
config_section = None
@@ -55,6 +57,7 @@ _ACTIONS = collections.namedtuple(
'created, deleted, disabled, updated, internal')
ACTIONS = _ACTIONS(created='created', deleted='deleted', disabled='disabled',
updated='updated', internal='internal')
+"""The actions on resources."""
CADF_TYPE_MAP = {
'group': taxonomy.SECURITY_GROUP,
@@ -291,6 +294,54 @@ def register_event_callback(event, resource_type, callbacks):
LOG.debug(msg, {'callback': callback_str, 'event': event_str})
+def listener(cls):
+ """A class decorator to declare a class to be a notification listener.
+
+ A notification listener must specify the event(s) it is interested in by
+ defining a ``event_callbacks`` attribute or property. ``event_callbacks``
+ is a dictionary where the key is the type of event and the value is a
+ dictionary containing a mapping of resource types to callback(s).
+
+ :data:`.ACTIONS` contains constants for the currently
+ supported events. There is currently no single place to find constants for
+ the resource types.
+
+ Example::
+
+ @listener
+ class Something(object):
+
+ def __init__(self):
+ self.event_callbacks = {
+ notifications.ACTIONS.created: {
+ 'user': self._user_created_callback,
+ },
+ notifications.ACTIONS.deleted: {
+ 'project': [
+ self._project_deleted_callback,
+ self._do_cleanup,
+ ]
+ },
+ }
+
+ """
+
+ def init_wrapper(init):
+ @functools.wraps(init)
+ def __new_init__(self, *args, **kwargs):
+ init(self, *args, **kwargs)
+ _register_event_callbacks(self)
+ return __new_init__
+
+ def _register_event_callbacks(self):
+ for event, resource_types in self.event_callbacks.items():
+ for resource_type, callbacks in resource_types.items():
+ register_event_callback(event, resource_type, callbacks)
+
+ cls.__init__ = init_wrapper(cls.__init__)
+ return cls
+
+
def notify_event_callbacks(service, resource_type, operation, payload):
"""Sends a notification to registered extensions."""
if operation in _SUBSCRIBERS:
@@ -524,8 +575,10 @@ class CadfRoleAssignmentNotificationWrapper(object):
def __init__(self, operation):
self.action = '%s.%s' % (operation, self.ROLE_ASSIGNMENT)
- self.event_type = '%s.%s.%s' % (SERVICE, operation,
- self.ROLE_ASSIGNMENT)
+ self.deprecated_event_type = '%s.%s.%s' % (SERVICE, operation,
+ self.ROLE_ASSIGNMENT)
+ self.event_type = '%s.%s.%s' % (SERVICE, self.ROLE_ASSIGNMENT,
+ operation)
def __call__(self, f):
def wrapper(wrapped_self, role_id, *args, **kwargs):
@@ -581,19 +634,30 @@ class CadfRoleAssignmentNotificationWrapper(object):
audit_kwargs['inherited_to_projects'] = inherited
audit_kwargs['role'] = role_id
+ # For backward compatibility, send both old and new event_type.
+ # Deprecate old format and remove it in the next release.
+ event_types = [self.deprecated_event_type, self.event_type]
+ versionutils.deprecated(
+ as_of=versionutils.deprecated.KILO,
+ remove_in=+1,
+ what=('sending duplicate %s notification event type' %
+ self.deprecated_event_type),
+ in_favor_of='%s notification event type' % self.event_type)
try:
result = f(wrapped_self, role_id, *args, **kwargs)
except Exception:
- _send_audit_notification(self.action, initiator,
- taxonomy.OUTCOME_FAILURE,
- target, self.event_type,
- **audit_kwargs)
+ for event_type in event_types:
+ _send_audit_notification(self.action, initiator,
+ taxonomy.OUTCOME_FAILURE,
+ target, event_type,
+ **audit_kwargs)
raise
else:
- _send_audit_notification(self.action, initiator,
- taxonomy.OUTCOME_SUCCESS,
- target, self.event_type,
- **audit_kwargs)
+ for event_type in event_types:
+ _send_audit_notification(self.action, initiator,
+ taxonomy.OUTCOME_SUCCESS,
+ target, event_type,
+ **audit_kwargs)
return result
return wrapper