Adding audit middleware specific notification driver conf

Now oslo messaging notifier can use driver information from audit
middleware specific conf section. This allows audit to have different
driver and transport usage from existing standard oslo messaging
configuration. If audit middleware section is not defined, then existing
logic is used which identifies driver from shared common oslo messaging
notification conf section.

Adjusted code and tests to recent oslo messaging notifier topic to
topics arg change. And recent request.context change.

Change-Id: Ia9ce654d3903efd0fd7893347e44ee27a765c745
Closes-Bug: 1544840
This commit is contained in:
Arun Kant 2016-02-12 16:41:19 -08:00
parent 7594bfab79
commit c813c35214
4 changed files with 155 additions and 6 deletions

View File

@ -15,9 +15,9 @@
.. _middleware:
=================
Audit middleware
=================
================
Audit middleware
================
The Keystone middleware library provides an optional WSGI middleware filter
which allows the ability to audit API requests for each component of OpenStack.
@ -78,4 +78,23 @@ Additional options can be set::
service_name = test # opt to set HTTP_X_SERVICE_NAME environ variable
ignore_req_list = GET,POST # opt to ignore specific requests
Audit middleware can be configured to use its own exclusive notification driver
and topic(s) value. This can be useful when the service is already using oslo
messaging notifications and wants to use a different driver for auditing e.g.
service has existing notifications sent to queue via 'messagingv2' and wants to
send audit notifications to a log file via 'log' driver. Example shown below::
[audit_middleware_notifications]
driver = log
When audit events are sent via 'messagingv2' or 'messaging', middleware can
specify a transport URL if its transport URL needs to be different from the
service's own messaging transport setting. Other Transport related settings are
read from oslo messaging sections defined in service configuration e.g.
'oslo_messaging_rabbit'. Example shown below::
[audit_middleware_notifications]
driver = messaging
transport_url = rabbit://user2:passwd@host:5672/another_virtual_host
.. _pyCADF library: https://github.com/openstack/pycadf/tree/master/etc/pycadf

View File

@ -56,6 +56,27 @@ from keystonemiddleware.i18n import _LE, _LI
_LOG = None
_AUDIT_OPTS = [
cfg.StrOpt('driver',
default=None,
help='The Driver to handle sending notifications. Possible '
'values are messaging, messagingv2, routing, log, test, '
'noop. If not specified, then value from '
'oslo_messaging_notifications conf section is used.'),
cfg.ListOpt('topics',
default=None,
help='List of AMQP topics used for OpenStack notifications. If'
' not specified, then value from '
' oslo_messaging_notifications conf section is used.'),
cfg.StrOpt('transport_url',
default=None,
secret=True,
help='A URL representing messaging driver to use for '
'notification. If not specified, we fall back to the same '
'configuration used for RPC.'),
]
cfg.CONF.register_opts(_AUDIT_OPTS, group="audit_middleware_notifications")
def _log_and_ignore_error(fn):
@functools.wraps(fn)
@ -345,10 +366,15 @@ class AuditMiddleware(object):
transport_aliases = self._get_aliases(cfg.CONF.project)
if messaging:
transport = oslo_messaging.get_transport(
cfg.CONF,
url=cfg.CONF.audit_middleware_notifications.transport_url,
aliases=transport_aliases)
self._notifier = oslo_messaging.Notifier(
oslo_messaging.get_transport(cfg.CONF,
aliases=transport_aliases),
os.path.basename(sys.argv[0]))
transport,
os.path.basename(sys.argv[0]),
driver=cfg.CONF.audit_middleware_notifications.driver,
topics=cfg.CONF.audit_middleware_notifications.topics)
def _emit_audit(self, context, event_type, payload):
"""Emit audit notification.

View File

@ -258,6 +258,104 @@ class AuditMiddlewareTest(BaseAuditMiddlewareTest):
notify.call_args_list[0][0][2]['id'])
def _get_transport(conf, aliases=None, url=None):
transport = mock.MagicMock()
transport.conf = conf
conf.register_opts = mock.MagicMock()
return transport
@mock.patch('oslo_messaging.get_transport', side_effect=_get_transport)
class AuditNotifierConfigTest(BaseAuditMiddlewareTest):
def test_conf_middleware_log_and_default_as_messaging(self, t):
cfg.CONF.notification_driver = ['messaging'] # MultiOptStr value
cfg.CONF.audit_middleware_notifications.driver = 'log'
middleware = audit.AuditMiddleware(
FakeApp(),
audit_map_file=self.audit_map,
service_name='pycadf')
req = webob.Request.blank('/foo/bar',
environ=self.get_environ_header('GET'))
req.context = {}
with mock.patch('oslo_messaging.notify._impl_log.LogDriver.notify',
side_effect=Exception('error')) as driver:
middleware._process_request(req)
# audit middleware conf has 'log' make sure that driver is invoked
# and not the one specified in DEFAULT section
self.assertTrue(driver.called)
def test_conf_middleware_log_and_oslo_msg_as_messaging(self, t):
cfg.CONF.notification_driver = None
cfg.CONF.oslo_messaging_notifications.driver = ['messaging']
cfg.CONF.audit_middleware_notifications.driver = 'log'
middleware = audit.AuditMiddleware(
FakeApp(),
audit_map_file=self.audit_map,
service_name='pycadf')
req = webob.Request.blank('/foo/bar',
environ=self.get_environ_header('GET'))
req.context = {}
with mock.patch('oslo_messaging.notify._impl_log.LogDriver.notify',
side_effect=Exception('error')) as driver:
middleware._process_request(req)
# audit middleware conf has 'log' make sure that driver is invoked
# and not the one specified in oslo_messaging_notifications section
self.assertTrue(driver.called)
def test_conf_middleware_messaging_and_oslo_msg_as_log(self, t):
cfg.CONF.notification_driver = None
cfg.CONF.oslo_messaging_notifications.driver = ['log']
cfg.CONF.audit_middleware_notifications.driver = 'messaging'
middleware = audit.AuditMiddleware(
FakeApp(),
audit_map_file=self.audit_map,
service_name='pycadf')
req = webob.Request.blank('/foo/bar',
environ=self.get_environ_header('GET'))
req.context = {}
with mock.patch('oslo_messaging.notify.messaging.MessagingDriver'
'.notify',
side_effect=Exception('error')) as driver:
# audit middleware has 'messaging' make sure that driver is invoked
# and not the one specified in oslo_messaging_notifications section
middleware._process_request(req)
self.assertTrue(driver.called)
def test_with_no_middleware_notification_conf(self, t):
cfg.CONF.notification_driver = None
cfg.CONF.oslo_messaging_notifications.driver = ['messaging']
cfg.CONF.audit_middleware_notifications.driver = None
middleware = audit.AuditMiddleware(
FakeApp(),
audit_map_file=self.audit_map,
service_name='pycadf')
req = webob.Request.blank('/foo/bar',
environ=self.get_environ_header('GET'))
req.context = {}
with mock.patch('oslo_messaging.notify.messaging.MessagingDriver'
'.notify',
side_effect=Exception('error')) as driver:
# audit middleware section is not set. So driver needs to be
# invoked from oslo_messaging_notifications section.
middleware._process_request(req)
self.assertTrue(driver.called)
def test_conf_middleware_messaging_and_transport_set(self, mock_transport):
transport_url = 'rabbit://me:passwd@host:5672/virtual_host'
cfg.CONF.audit_middleware_notifications.driver = 'messaging'
cfg.CONF.audit_middleware_notifications.transport_url = transport_url
audit.AuditMiddleware(
FakeApp(),
audit_map_file=self.audit_map,
service_name='pycadf')
self.assertTrue(mock_transport.called)
# make sure first call kwarg 'url' is same as provided transport_url
self.assertEqual(transport_url,
mock_transport.call_args_list[0][1]['url'])
@mock.patch('oslo_messaging.rpc', mock.MagicMock())
class AuditApiLogicTest(BaseAuditMiddlewareTest):

View File

@ -0,0 +1,6 @@
---
features:
- >
[`bug 1544840 <https://bugs.launchpad.net/keystonemiddleware/+bug/1544840>`_]
Adding audit middleware specific notification related configuration
to allow a different notification driver and transport for audit if needed.