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:
parent
6fe74951ac
commit
255685877e
|
@ -28,7 +28,7 @@ The supported operations between the two types of notification formats are
|
||||||
documented below.
|
documented below.
|
||||||
|
|
||||||
Common Notification Structure
|
Common Notification Structure
|
||||||
==============================
|
=============================
|
||||||
|
|
||||||
Notifications generated by Keystone are generated in JSON format. An external
|
Notifications generated by Keystone are generated in JSON format. An external
|
||||||
application can format them into ATOM format and publish them as a feed.
|
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
|
resources by revoking tokens with authorization on the project, but should
|
||||||
**not** have a direct impact on the projects resources (in other words, virtual
|
**not** have a direct impact on the projects resources (in other words, virtual
|
||||||
machines should **not** be deleted).
|
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
|
||||||
|
|
|
@ -45,6 +45,14 @@ notifier_opts = [
|
||||||
'the resource being operated on. A "cadf" notification '
|
'the resource being operated on. A "cadf" notification '
|
||||||
'has the same information, as well as information about '
|
'has the same information, as well as information about '
|
||||||
'the initiator of the event.'),
|
'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
|
config_section = None
|
||||||
|
@ -470,6 +478,8 @@ def _send_notification(operation, resource_type, resource_id, public=True):
|
||||||
'service': SERVICE,
|
'service': SERVICE,
|
||||||
'resource_type': resource_type,
|
'resource_type': resource_type,
|
||||||
'operation': operation}
|
'operation': operation}
|
||||||
|
if _check_notification_opt_out(event_type, outcome=None):
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
notifier.info(context, event_type, payload)
|
notifier.info(context, event_type, payload)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -716,6 +726,9 @@ def _send_audit_notification(action, initiator, outcome, target,
|
||||||
key-value pairs to the CADF event.
|
key-value pairs to the CADF event.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if _check_notification_opt_out(event_type, outcome):
|
||||||
|
return
|
||||||
|
|
||||||
event = eventfactory.EventFactory().new_event(
|
event = eventfactory.EventFactory().new_event(
|
||||||
eventType=cadftype.EVENTTYPE_ACTIVITY,
|
eventType=cadftype.EVENTTYPE_ACTIVITY,
|
||||||
outcome=outcome,
|
outcome=outcome,
|
||||||
|
@ -742,6 +755,33 @@ def _send_audit_notification(action, initiator, outcome, target,
|
||||||
{'action': action, 'event_type': event_type})
|
{'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
|
emit_event = CadfNotificationWrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,82 @@ class NotificationsTestCase(unit.BaseTestCase):
|
||||||
resource)
|
resource)
|
||||||
mocked.assert_called_once_with(*expected_args)
|
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):
|
class BaseNotificationTest(test_v3.RestfulTestCase):
|
||||||
|
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue