Opt-out certain Keystone Notifications

This patch will allow certain notifications for events in
Keystone to be opted out. Opting out may be a desired way of
doing this since most keystone deployers will likely like
to by default have all audit traces.

Change-Id: I86caf6e5f25cdd76121881813167c2144bf1d051
Closes-Bug: 1519210
This commit is contained in:
Fernando Diaz 2015-12-04 22:23:15 -06:00 committed by Steve Martinelli
parent 6fe74951ac
commit 255685877e
4 changed files with 147 additions and 1 deletions

View File

@ -28,7 +28,7 @@ The supported operations between the two types of notification formats are
documented below.
Common Notification Structure
==============================
=============================
Notifications generated by Keystone are generated in JSON format. An external
application can format them into ATOM format and publish them as a feed.
@ -414,3 +414,26 @@ ensures this has an immediate impact on the accessibility of the project's
resources by revoking tokens with authorization on the project, but should
**not** have a direct impact on the projects resources (in other words, virtual
machines should **not** be deleted).
Opting out of certain notifications
===================================
There are many notifications that Keystone emits and some deployers may only
care about certain events. In Keystone there is a way to opt-out of certain
notifications. In ``/etc/keystone/keystone.conf`` you can set ``opt_out`` to
the event you wish to opt-out of. It is possible to opt-out of multiple events.
Example:
.. code-block:: ini
[DEFAULT]
notification_opt_out = identity.user.created
notification_opt_out = identity.role_assignment.created
notification_opt_out = identity.authenticate.pending
This will opt-out notifications for user creation, role assignment creation and
successful authentications. For a list of event types that can be used, refer
to: `Telemetry Measurements`_.
.. _Telemetry Measurements: http://docs.openstack.org/admin-guide-cloud/telemetry-measurements.html#openstack-identity

View File

@ -45,6 +45,14 @@ notifier_opts = [
'the resource being operated on. A "cadf" notification '
'has the same information, as well as information about '
'the initiator of the event.'),
cfg.MultiStrOpt('notification_opt_out', default=[],
help='Define the notification options to opt-out from. '
'The value expected is: '
'identity.<resource_type>.<operation>. This field '
'can be set multiple times in order to add more '
'notifications to opt-out from. For example:\n '
'notification_opt_out=identity.user.created\n '
'notification_opt_out=identity.authenticate.success'),
]
config_section = None
@ -470,6 +478,8 @@ def _send_notification(operation, resource_type, resource_id, public=True):
'service': SERVICE,
'resource_type': resource_type,
'operation': operation}
if _check_notification_opt_out(event_type, outcome=None):
return
try:
notifier.info(context, event_type, payload)
except Exception:
@ -716,6 +726,9 @@ def _send_audit_notification(action, initiator, outcome, target,
key-value pairs to the CADF event.
"""
if _check_notification_opt_out(event_type, outcome):
return
event = eventfactory.EventFactory().new_event(
eventType=cadftype.EVENTTYPE_ACTIVITY,
outcome=outcome,
@ -742,6 +755,33 @@ def _send_audit_notification(action, initiator, outcome, target,
{'action': action, 'event_type': event_type})
def _check_notification_opt_out(event_type, outcome):
"""Check if a particular event_type has been opted-out of.
This method checks to see if an event should be sent to the messaging
service. Any event specified in the opt-out list will not be transmitted.
:param event_type: This is the meter name that Ceilometer uses to poll
events. For example: identity.user.created, or
identity.authenticate.success, or identity.role_assignment.created
:param outcome: The CADF outcome (taxonomy.OUTCOME_PENDING,
taxonomy.OUTCOME_SUCCESS, taxonomy.OUTCOME_FAILURE)
"""
# NOTE(stevemar): Special handling for authenticate, we look at the outcome
# as well when evaluating. For authN events, event_type is just
# idenitity.authenticate, which isn't fine enough to provide any opt-out
# value, so we attach the outcome to re-create the meter name used in
# ceilometer.
if 'authenticate' in event_type:
event_type = event_type + "." + outcome
if event_type in CONF.notification_opt_out:
return True
return False
emit_event = CadfNotificationWrapper

View File

@ -201,6 +201,82 @@ class NotificationsTestCase(unit.BaseTestCase):
resource)
mocked.assert_called_once_with(*expected_args)
def test_send_notification_with_opt_out(self):
"""Test the private method _send_notification with opt-out.
Test that _send_notification does not notify when a valid
notification_opt_out configuration is provided.
"""
resource = uuid.uuid4().hex
resource_type = EXP_RESOURCE_TYPE
operation = CREATED_OPERATION
event_type = 'identity.%s.created' % resource_type
# NOTE(diazjf): Here we add notification_opt_out to the
# configuration so that we should return before _get_notifer is
# called. This is because we are opting out notifications for the
# passed resource_type and operation.
conf = self.useFixture(config_fixture.Config(CONF))
conf.config(notification_opt_out=event_type)
with mock.patch.object(notifications._get_notifier(),
'_notify') as mocked:
notifications._send_notification(operation, resource_type,
resource)
mocked.assert_not_called()
def test_send_audit_notification_with_opt_out(self):
"""Test the private method _send_audit_notification with opt-out.
Test that _send_audit_notification does not notify when a valid
notification_opt_out configuration is provided.
"""
resource_type = EXP_RESOURCE_TYPE
action = CREATED_OPERATION + '.' + resource_type
initiator = mock
target = mock
outcome = 'success'
event_type = 'identity.%s.created' % resource_type
conf = self.useFixture(config_fixture.Config(CONF))
conf.config(notification_opt_out=event_type)
with mock.patch.object(notifications._get_notifier(),
'_notify') as mocked:
notifications._send_audit_notification(action,
initiator,
outcome,
target,
event_type)
mocked.assert_not_called()
def test_opt_out_authenticate_event(self):
"""Test that authenticate events are successfully opted out."""
resource_type = EXP_RESOURCE_TYPE
action = CREATED_OPERATION + '.' + resource_type
initiator = mock
target = mock
outcome = 'success'
event_type = 'identity.authenticate'
meter_name = '%s.%s' % (event_type, outcome)
conf = self.useFixture(config_fixture.Config(CONF))
conf.config(notification_opt_out=meter_name)
with mock.patch.object(notifications._get_notifier(),
'_notify') as mocked:
notifications._send_audit_notification(action,
initiator,
outcome,
target,
event_type)
mocked.assert_not_called()
class BaseNotificationTest(test_v3.RestfulTestCase):

View File

@ -0,0 +1,7 @@
---
features:
- >
[`bug 1519210 <https://bugs.launchpad.net/keystone/+bug/1519210>`_]
A user may now opt-out of notifications by specifying a list of
`event_types` in the ``notification_opt_out`` option in `keystone.conf`.
These events are never sent to a messaging service.