From 54ea7e6beac769978ba34ef56b9bf60871dd05ab Mon Sep 17 00:00:00 2001 From: Mehdi Abaakouk Date: Thu, 11 Jul 2013 18:02:13 +0200 Subject: [PATCH] Implement a basic REST alarm notification This change adds schemes http:// to the alarm notifier. The URL is called as a POST request. The body of request contains a json dictionnary with alarm state and the reason. Change-Id: I0dbdd6afdef1a88602c9fbc55d651d3d8f6ad3e0 Blueprint: alarm-notifier --- ceilometer/alarm/notifier/rest.py | 41 +++++++++++++++++++++++++++++++ setup.cfg | 3 ++- tests/alarm/test_notifier.py | 22 +++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 ceilometer/alarm/notifier/rest.py diff --git a/ceilometer/alarm/notifier/rest.py b/ceilometer/alarm/notifier/rest.py new file mode 100644 index 000000000..39076d0be --- /dev/null +++ b/ceilometer/alarm/notifier/rest.py @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 eNovance +# +# Author: Mehdi Abaakouk +# +# 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.""" + +import eventlet +import requests + +from ceilometer.alarm import notifier +from ceilometer.openstack.common import jsonutils +from ceilometer.openstack.common import log + +LOG = log.getLogger(__name__) + + +class RestAlarmNotifier(notifier.AlarmNotifier): + """Rest alarm notifier.""" + + def notify(self, action, alarm, state, reason): + LOG.info("Notifying alarm %s in state %s with action %s because %s", + alarm, state, action, reason) + data = { + 'state': state, + 'reason': reason, + } + eventlet.spawn_n(requests.post, action, + data=jsonutils.dumps(data)) diff --git a/setup.cfg b/setup.cfg index e2a1724f7..60f6859d9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -103,6 +103,7 @@ ceilometer.alarm = ceilometer.alarm.notifier = log = ceilometer.alarm.notifier.log:LogAlarmNotifier test = ceilometer.alarm.notifier.test:TestAlarmNotifier + http = ceilometer.alarm.notifier.rest:RestAlarmNotifier paste.filter_factory = swift = ceilometer.objectstore.swift_middleware:filter_factory @@ -115,7 +116,7 @@ console_scripts = ceilometer-collector = ceilometer.collector.service:collector ceilometer-collector-udp = ceilometer.collector.service:udp_collector ceilometer-alarm-singleton = ceilometer.alarm.service:singleton_alarm - ceilometer-alarm-notifier = ceilometer.alarm.notifier:alarm_notifier + ceilometer-alarm-notifier = ceilometer.alarm.service:alarm_notifier [build_sphinx] all_files = 1 diff --git a/tests/alarm/test_notifier.py b/tests/alarm/test_notifier.py index e6b5d298b..f5604b3c1 100644 --- a/tests/alarm/test_notifier.py +++ b/tests/alarm/test_notifier.py @@ -15,11 +15,14 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +import eventlet import urlparse import mock +import requests from ceilometer.alarm import service from ceilometer.openstack.common import context +from ceilometer.openstack.common import network_utils from ceilometer.tests import base @@ -56,6 +59,25 @@ class TestAlarmNotifier(base.TestCase): 'condition': {'threshold': 42}, }) + def test_notify_alarm_rest_action(self): + action = 'http://host/action' + data_json = '{"state": "ALARM", "reason": "what ?"}' + + self.mox.StubOutWithMock(requests, "post") + requests.post(network_utils.urlsplit(action), data=data_json) + self.mox.ReplayAll() + self.service.notify_alarm(context.get_admin_context(), + { + 'actions': [action], + 'alarm': {'name': 'foobar'}, + 'condition': {'threshold': 42}, + 'reason': 'what ?', + 'state': 'ALARM', + }) + eventlet.sleep(1) + self.mox.UnsetStubs() + self.mox.VerifyAll() + @staticmethod def _fake_urlsplit(*args, **kwargs): raise Exception("Evil urlsplit!")