Merge "Add validate alarm_actions schema in alarm API"

This commit is contained in:
Jenkins 2014-09-15 14:33:15 +00:00 committed by Gerrit Code Review
commit 500388c3fe
3 changed files with 122 additions and 2 deletions

View File

@ -232,13 +232,15 @@ class AlarmNotifierService(os_service.Service):
EXTENSIONS_NAMESPACE = "ceilometer.alarm.notifier"
notifiers = extension.ExtensionManager(EXTENSIONS_NAMESPACE,
invoke_on_load=True)
notifiers_schemas = notifiers.map(lambda x: x.name)
def __init__(self):
super(AlarmNotifierService, self).__init__()
transport = messaging.get_transport()
self.rpc_server = messaging.get_rpc_server(
transport, cfg.CONF.alarm.notifier_rpc_topic, self)
self.notifiers = extension.ExtensionManager(self.EXTENSIONS_NAMESPACE,
invoke_on_load=True)
def start(self):
super(AlarmNotifierService, self).start()

View File

@ -37,6 +37,7 @@ import pytz
import uuid
from oslo.config import cfg
from oslo.utils import netutils
from oslo.utils import strutils
from oslo.utils import timeutils
import pecan
@ -46,6 +47,7 @@ import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ceilometer.alarm import service as alarm_service
from ceilometer.alarm.storage import models as alarm_models
from ceilometer.api import acl
from ceilometer import messaging
@ -1815,6 +1817,7 @@ class Alarm(_Base):
def validate(alarm):
Alarm.check_rule(alarm)
Alarm.check_alarm_actions(alarm)
if alarm.threshold_rule:
# ensure an implicit constraint on project_id is added to
# the query if not already present
@ -1853,6 +1856,25 @@ class Alarm(_Base):
"cannot be set at the same time")
raise ClientSideError(error)
@staticmethod
def check_alarm_actions(alarm):
actions_schema = alarm_service.AlarmNotifierService.notifiers_schemas
for state in state_kind:
actions_name = state.replace(" ", "_") + '_actions'
actions = getattr(alarm, actions_name)
if not actions:
continue
for action in actions:
try:
url = netutils.urlsplit(action)
except Exception:
error = _("Unable to parse action %s") % action
raise ClientSideError(error)
if url.scheme not in actions_schema:
error = _("Unsupported action %s") % action
raise ClientSideError(error)
@classmethod
def sample(cls):
return cls(alarm_id=None,

View File

@ -628,6 +628,64 @@ class TestAlarms(v2.FunctionalTest,
'not valid for this resource',
resp.json['error_message']['faultstring'])
def _do_post_alarm_invalid_action(self, ok_actions=[], alarm_actions=[],
insufficient_data_actions=[],
error_message=None):
json = {
'enabled': False,
'name': 'added_alarm',
'state': 'ok',
'type': 'threshold',
'ok_actions': ok_actions,
'alarm_actions': alarm_actions,
'insufficient_data_actions': insufficient_data_actions,
'repeat_actions': True,
'threshold_rule': {
'meter_name': 'ameter',
'query': [{'field': 'metadata.field',
'op': 'eq',
'value': '5',
'type': 'string'}],
'comparison_operator': 'le',
'statistic': 'count',
'threshold': 50,
'evaluation_periods': '3',
'period': '180',
}
}
resp = self.post_json('/alarms', params=json, status=400,
headers=self.auth_headers)
alarms = list(self.alarm_conn.get_alarms())
self.assertEqual(4, len(alarms))
self.assertEqual(error_message,
resp.json['error_message']['faultstring'])
def test_post_invalid_alarm_ok_actions(self):
self._do_post_alarm_invalid_action(
ok_actions=['spam://something/ok'],
error_message='Unsupported action spam://something/ok')
def test_post_invalid_alarm_alarm_actions(self):
self._do_post_alarm_invalid_action(
alarm_actions=['spam://something/alarm'],
error_message='Unsupported action spam://something/alarm')
def test_post_invalid_alarm_insufficient_data_actions(self):
self._do_post_alarm_invalid_action(
insufficient_data_actions=['spam://something/insufficient'],
error_message='Unsupported action spam://something/insufficient')
@staticmethod
def _fake_urlsplit(*args, **kwargs):
raise Exception("Evil urlsplit!")
def test_post_invalid_alarm_actions_format(self):
with mock.patch('oslo.utils.netutils.urlsplit',
self._fake_urlsplit):
self._do_post_alarm_invalid_action(
alarm_actions=['http://[::1'],
error_message='Unable to parse action http://[::1')
def test_post_alarm_defaults(self):
to_check = {
'enabled': True,
@ -1489,6 +1547,44 @@ class TestAlarms(v2.FunctionalTest,
'Alarm with name=name1 exists',
resp.json['error_message']['faultstring'])
def test_put_invalid_alarm_actions(self):
json = {
'enabled': False,
'name': 'name1',
'state': 'ok',
'type': 'threshold',
'ok_actions': ['spam://something/ok'],
'alarm_actions': ['http://something/alarm'],
'insufficient_data_actions': ['http://something/no'],
'repeat_actions': True,
'threshold_rule': {
'meter_name': 'ameter',
'query': [{'field': 'metadata.field',
'op': 'eq',
'value': '5',
'type': 'string'}],
'comparison_operator': 'le',
'statistic': 'count',
'threshold': 50,
'evaluation_periods': 3,
'period': 180,
}
}
data = self.get_json('/alarms',
q=[{'field': 'name',
'value': 'name2',
}])
self.assertEqual(1, len(data))
alarm_id = data[0]['alarm_id']
resp = self.put_json('/alarms/%s' % alarm_id,
expect_errors=True, status=400,
params=json,
headers=self.auth_headers)
self.assertEqual(
'Unsupported action spam://something/ok',
resp.json['error_message']['faultstring'])
def test_put_alarm_combination_cannot_specify_itself(self):
json = {
'name': 'name4',