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
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):
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
class TrustRestAlarmNotifier(rest.RestAlarmNotifier):
"""Notifier supporting keystone trust authentication.
class TrustAlarmNotifierMixin(object):
"""Mixin class to add Keystone trust support to an AlarmNotifier.
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.
Provides a notify() method that interprets the trust ID and then calls
the parent class's notify(), passing the necessary authentication data in
the headers.
"""
def notify(self, action, alarm_id, alarm_name, severity, previous, current,
@ -45,6 +43,17 @@ class TrustRestAlarmNotifier(rest.RestAlarmNotifier):
action.fragment)
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,
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 import keystone_client
from aodh import notifier
from aodh.notifier import trust
LOG = log.getLogger(__name__)
@ -144,7 +145,7 @@ class ZaqarAlarmNotifier(notifier.AlarmNotifier):
'current': current, 'reason': reason,
'reason_data': reason_data}
message = dict(body=body)
self.notify_zaqar(action, message)
self.notify_zaqar(action, message, headers)
@property
def client(self):
@ -152,7 +153,7 @@ class ZaqarAlarmNotifier(notifier.AlarmNotifier):
self._zclient = self.get_zaqar_client(self._get_client_conf())
return self._zclient
def notify_zaqar(self, action, message):
def notify_zaqar(self, action, message, headers=None):
queue_info = urlparse.parse_qs(action.query)
try:
# 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"
" Zaqar queue"),
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.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):

View File

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