diff options
-rw-r--r-- | ceilometer/alarm/notifier/rest.py | 5 | ||||
-rw-r--r-- | ceilometer/alarm/notifier/trust.py | 66 | ||||
-rw-r--r-- | ceilometer/tests/alarm/test_notifier.py | 19 | ||||
-rw-r--r-- | setup.cfg | 2 |
4 files changed, 91 insertions, 1 deletions
diff --git a/ceilometer/alarm/notifier/rest.py b/ceilometer/alarm/notifier/rest.py index b13befed..93a9f9c9 100644 --- a/ceilometer/alarm/notifier/rest.py +++ b/ceilometer/alarm/notifier/rest.py @@ -54,7 +54,8 @@ class RestAlarmNotifier(notifier.AlarmNotifier): """Rest alarm notifier.""" @staticmethod - def notify(action, alarm_id, previous, current, reason, reason_data): + def notify(action, alarm_id, previous, current, reason, reason_data, + headers=None): LOG.info(_( "Notifying alarm %(alarm_id)s from %(previous)s " "to %(current)s with action %(action)s because " @@ -65,6 +66,8 @@ class RestAlarmNotifier(notifier.AlarmNotifier): 'current': current, 'reason': reason, 'reason_data': reason_data} kwargs = {'data': jsonutils.dumps(body)} + if headers: + kwargs['headers'] = headers if action.scheme == 'https': default_verify = int(cfg.CONF.alarm.rest_notifier_ssl_verify) diff --git a/ceilometer/alarm/notifier/trust.py b/ceilometer/alarm/notifier/trust.py new file mode 100644 index 00000000..b3190b1b --- /dev/null +++ b/ceilometer/alarm/notifier/trust.py @@ -0,0 +1,66 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2014 eNovance +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +"""Rest alarm notifier with trusted authentication.""" + +try: + import urllib.parse + SplitResult = urllib.parse.SplitResult +except ImportError: + import urlparse + SplitResult = urlparse.SplitResult + +from keystoneclient.v3 import client as keystone_client +from oslo.config import cfg + +from ceilometer.alarm import notifier + + +class TrustRestAlarmNotifier(notifier.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 ceilometer service user to + authenticate using the trust ID provided. + + The URL must be in the form trust+http://trust-id@host/action. + """ + + @staticmethod + def notify(action, alarm_id, previous, current, reason, reason_data): + trust_id = action.username + + auth_url = cfg.CONF.service_credentials.os_auth_url.replace( + "v2.0", "v3") + client = keystone_client.Client( + username=cfg.CONF.service_credentials.os_username, + password=cfg.CONF.service_credentials.os_password, + cacert=cfg.CONF.service_credentials.os_cacert, + auth_url=auth_url, + region_name=cfg.CONF.service_credentials.os_region_name, + insecure=cfg.CONF.service_credentials.insecure, + trust_id=trust_id) + + # Remove the fake user + netloc = action.netloc.split("@")[1] + # Remove the trust prefix + scheme = action.scheme[6:] + + action = SplitResult(scheme, netloc, action.path, action.query, + action.fragment) + + headers = {'X-Auth-Token': client.auth_token} + notifier.rest.RestAlarmNotifier.notify( + action, alarm_id, previous, current, reason, reason_data, headers) diff --git a/ceilometer/tests/alarm/test_notifier.py b/ceilometer/tests/alarm/test_notifier.py index 8f282833..3e4ba8ac 100644 --- a/ceilometer/tests/alarm/test_notifier.py +++ b/ceilometer/tests/alarm/test_notifier.py @@ -24,6 +24,7 @@ from ceilometer.alarm import service from ceilometer import messaging from ceilometer.openstack.common import context from ceilometer.openstack.common.fixture import config +from ceilometer.openstack.common.fixture import mockpatch from ceilometer.openstack.common import test @@ -203,3 +204,21 @@ class TestAlarmNotifier(test.BaseTestCase): 'condition': {'threshold': 42}, }) self.assertTrue(LOG.error.called) + + def test_notify_alarm_trust_action(self): + action = 'trust+http://trust-1234@host/action' + url = 'http://host/action' + + client = mock.MagicMock() + client.auth_token = 'token_1234' + + self.useFixture(mockpatch.Patch('keystoneclient.v3.client.Client', + lambda **kwargs: client)) + + with mock.patch('eventlet.spawn_n', self._fake_spawn_n): + with mock.patch.object(requests, 'post') as poster: + self.service.notify_alarm(context.get_admin_context(), + self._notification(action)) + poster.assert_called_with( + url, data=DATA_JSON, + headers={'X-Auth-Token': 'token_1234'}) @@ -174,6 +174,8 @@ ceilometer.alarm.notifier = test = ceilometer.alarm.notifier.test:TestAlarmNotifier http = ceilometer.alarm.notifier.rest:RestAlarmNotifier https = ceilometer.alarm.notifier.rest:RestAlarmNotifier + trust+http = ceilometer.alarm.notifier.trust:TrustRestAlarmNotifier + trust+https = ceilometer.alarm.notifier.trust:TrustRestAlarmNotifier ceilometer.event.trait_plugin = split = ceilometer.event.trait_plugins:SplitterTraitPlugin |