Add trust+zaqar:// action

Allow Zaqar messages to be posted to a queue under the user's own tenant
by using a Keystone trust.

Change-Id: Ia9e200ecef13ba46479a155fee064d6dded08917
This commit is contained in:
Zane Bitter 2016-12-09 20:01:43 -05:00
parent b9242bf984
commit ef08bc2e6a
5 changed files with 75 additions and 11 deletions

View File

@ -384,7 +384,7 @@ class Alarm(base.Base):
@staticmethod @staticmethod
def _is_trust_url(url): def _is_trust_url(url):
return url.scheme in ('trust+http', 'trust+https') return url.scheme.startswith('trust+')
def update_actions(self, old_alarm=None): def update_actions(self, old_alarm=None):
trustor_user_id = pecan.request.headers.get('X-User-Id') trustor_user_id = pecan.request.headers.get('X-User-Id')

View File

@ -20,14 +20,12 @@ from aodh import keystone_client
from aodh.notifier import rest from aodh.notifier import rest
class TrustRestAlarmNotifier(rest.RestAlarmNotifier): class TrustAlarmNotifierMixin(object):
"""Notifier supporting keystone trust authentication. """Mixin class to add Keystone trust support to an AlarmNotifier.
This alarm notifier is intended to be used to call an endpoint using Provides a notify() method that interprets the trust ID and then calls
keystone authentication. It uses the aodh service user to the parent class's notify(), passing the necessary authentication data in
authenticate using the trust ID provided. the headers.
The URL must be in the form trust+http://trust-id@host/action.
""" """
def notify(self, action, alarm_id, alarm_name, severity, previous, current, def notify(self, action, alarm_id, alarm_name, severity, previous, current,
@ -45,6 +43,17 @@ class TrustRestAlarmNotifier(rest.RestAlarmNotifier):
action.fragment) action.fragment)
headers = {'X-Auth-Token': keystone_client.get_auth_token(client)} headers = {'X-Auth-Token': keystone_client.get_auth_token(client)}
super(TrustRestAlarmNotifier, self).notify( super(TrustAlarmNotifierMixin, self).notify(
action, alarm_id, alarm_name, severity, previous, current, reason, action, alarm_id, alarm_name, severity, previous, current, reason,
reason_data, headers) reason_data, headers)
class TrustRestAlarmNotifier(TrustAlarmNotifierMixin, rest.RestAlarmNotifier):
"""Notifier supporting keystone trust authentication.
This alarm notifier is intended to be used to call an endpoint using
keystone authentication. It uses the aodh service user to
authenticate using the trust ID provided.
The URL must be in the form ``trust+http://trust-id@host/action``.
"""

View File

@ -22,6 +22,7 @@ import six.moves.urllib.parse as urlparse
from aodh.i18n import _LE, _LI from aodh.i18n import _LE, _LI
from aodh import keystone_client from aodh import keystone_client
from aodh import notifier from aodh import notifier
from aodh.notifier import trust
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -144,7 +145,7 @@ class ZaqarAlarmNotifier(notifier.AlarmNotifier):
'current': current, 'reason': reason, 'current': current, 'reason': reason,
'reason_data': reason_data} 'reason_data': reason_data}
message = dict(body=body) message = dict(body=body)
self.notify_zaqar(action, message) self.notify_zaqar(action, message, headers)
@property @property
def client(self): def client(self):
@ -152,7 +153,7 @@ class ZaqarAlarmNotifier(notifier.AlarmNotifier):
self._zclient = self.get_zaqar_client(self._get_client_conf()) self._zclient = self.get_zaqar_client(self._get_client_conf())
return self._zclient return self._zclient
def notify_zaqar(self, action, message): def notify_zaqar(self, action, message, headers=None):
queue_info = urlparse.parse_qs(action.query) queue_info = urlparse.parse_qs(action.query)
try: try:
# NOTE(flwang): Try to get build a pre-signed client if user has # NOTE(flwang): Try to get build a pre-signed client if user has
@ -187,3 +188,41 @@ class ZaqarAlarmNotifier(notifier.AlarmNotifier):
LOG.error(_LE("Unknown error occurred; Failed to post message to" LOG.error(_LE("Unknown error occurred; Failed to post message to"
" Zaqar queue"), " Zaqar queue"),
exc_info=True) exc_info=True)
class TrustZaqarAlarmNotifier(trust.TrustAlarmNotifierMixin,
ZaqarAlarmNotifier):
"""Zaqar notifier using a Keystone trust to post to user-defined queues.
The URL must be in the form ``trust+zaqar://trust_id@?queue_name=example``.
"""
def _get_client_conf(self, auth_token):
return {
'auth_opts': {
'backend': 'keystone',
'options': {
'os_auth_token': auth_token,
}
}
}
def notify_zaqar(self, action, message, headers):
queue_info = urlparse.parse_qs(action.query)
try:
queue_name = queue_info.get('queue_name')[-1]
except IndexError:
LOG.error(_LE("Required 'queue_name' query option missing in"
" action %s"),
action)
return
try:
conf = self._get_client_conf(headers['X-Auth-Token'])
client = self.get_zaqar_client(conf)
queue = client.queue(queue_name)
queue.post(message)
except Exception:
LOG.error(_LE("Unknown error occurred; Failed to post message to"
" Zaqar queue"),
exc_info=True)

View File

@ -405,6 +405,21 @@ class TestAlarmNotifier(tests_base.BaseTestCase):
self.assertEqual(1, self.zaqar.subscriptions) self.assertEqual(1, self.zaqar.subscriptions)
self.assertEqual(1, self.zaqar.posts) self.assertEqual(1, self.zaqar.posts)
def test_trust_zaqar_notifier_action(self):
client = mock.MagicMock()
client.session.auth.get_access.return_value.auth_token = 'token_1234'
self.useFixture(
mockpatch.Patch('aodh.keystone_client.get_trusted_client',
lambda *args: client))
action = 'trust+zaqar://trust-1234:delete@?queue_name=foobar-critical'
self._msg_notifier.sample({}, 'alarm.update',
self._notification(action))
time.sleep(1)
self.assertEqual(0, self.zaqar.subscriptions)
self.assertEqual(1, self.zaqar.posts)
class FakeZaqarClient(object): class FakeZaqarClient(object):

View File

@ -102,6 +102,7 @@ aodh.notifier =
trust+http = aodh.notifier.trust:TrustRestAlarmNotifier trust+http = aodh.notifier.trust:TrustRestAlarmNotifier
trust+https = aodh.notifier.trust:TrustRestAlarmNotifier trust+https = aodh.notifier.trust:TrustRestAlarmNotifier
zaqar = aodh.notifier.zaqar:ZaqarAlarmNotifier zaqar = aodh.notifier.zaqar:ZaqarAlarmNotifier
trust+zaqar = aodh.notifier.zaqar:TrustZaqarAlarmNotifier
wsgi_scripts = wsgi_scripts =
aodh-api = aodh.api.app:build_wsgi_app aodh-api = aodh.api.app:build_wsgi_app