From 92fd2dbfb672d7b2b1cdfd5dd5cf89f7716b3e12 Mon Sep 17 00:00:00 2001 From: asteroide Date: Tue, 1 Sep 2015 16:03:26 +0200 Subject: Update Keystone code from official Github repository with branch Master on 09/01/2015. Change-Id: I0ff6099e6e2580f87f502002a998bbfe12673498 --- keystone-moon/keystone/notifications.py | 88 ++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 12 deletions(-) (limited to 'keystone-moon/keystone/notifications.py') 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 -- cgit 1.2.3-korg