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"
|
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):
|
def __init__(self):
|
||||||
super(AlarmNotifierService, self).__init__()
|
super(AlarmNotifierService, self).__init__()
|
||||||
transport = messaging.get_transport()
|
transport = messaging.get_transport()
|
||||||
self.rpc_server = messaging.get_rpc_server(
|
self.rpc_server = messaging.get_rpc_server(
|
||||||
transport, cfg.CONF.alarm.notifier_rpc_topic, self)
|
transport, cfg.CONF.alarm.notifier_rpc_topic, self)
|
||||||
self.notifiers = extension.ExtensionManager(self.EXTENSIONS_NAMESPACE,
|
|
||||||
invoke_on_load=True)
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
super(AlarmNotifierService, self).start()
|
super(AlarmNotifierService, self).start()
|
||||||
|
@ -37,6 +37,7 @@ import pytz
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
from oslo.utils import netutils
|
||||||
from oslo.utils import strutils
|
from oslo.utils import strutils
|
||||||
from oslo.utils import timeutils
|
from oslo.utils import timeutils
|
||||||
import pecan
|
import pecan
|
||||||
@ -46,6 +47,7 @@ import wsme
|
|||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
import wsmeext.pecan as wsme_pecan
|
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.alarm.storage import models as alarm_models
|
||||||
from ceilometer.api import acl
|
from ceilometer.api import acl
|
||||||
from ceilometer import messaging
|
from ceilometer import messaging
|
||||||
@ -1815,6 +1817,7 @@ class Alarm(_Base):
|
|||||||
def validate(alarm):
|
def validate(alarm):
|
||||||
|
|
||||||
Alarm.check_rule(alarm)
|
Alarm.check_rule(alarm)
|
||||||
|
Alarm.check_alarm_actions(alarm)
|
||||||
if alarm.threshold_rule:
|
if alarm.threshold_rule:
|
||||||
# ensure an implicit constraint on project_id is added to
|
# ensure an implicit constraint on project_id is added to
|
||||||
# the query if not already present
|
# the query if not already present
|
||||||
@ -1853,6 +1856,25 @@ class Alarm(_Base):
|
|||||||
"cannot be set at the same time")
|
"cannot be set at the same time")
|
||||||
raise ClientSideError(error)
|
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
|
@classmethod
|
||||||
def sample(cls):
|
def sample(cls):
|
||||||
return cls(alarm_id=None,
|
return cls(alarm_id=None,
|
||||||
|
@ -628,6 +628,64 @@ class TestAlarms(v2.FunctionalTest,
|
|||||||
'not valid for this resource',
|
'not valid for this resource',
|
||||||
resp.json['error_message']['faultstring'])
|
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):
|
def test_post_alarm_defaults(self):
|
||||||
to_check = {
|
to_check = {
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
@ -1489,6 +1547,44 @@ class TestAlarms(v2.FunctionalTest,
|
|||||||
'Alarm with name=name1 exists',
|
'Alarm with name=name1 exists',
|
||||||
resp.json['error_message']['faultstring'])
|
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):
|
def test_put_alarm_combination_cannot_specify_itself(self):
|
||||||
json = {
|
json = {
|
||||||
'name': 'name4',
|
'name': 'name4',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user