Merge "Add validate alarm_actions schema in alarm API"
This commit is contained in:
commit
500388c3fe
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user