Add alarm definition create resource
Change-Id: I65e1c9f8697632e3c2004282bb624ed814828864
This commit is contained in:
parent
44eaa39649
commit
ba39188b2f
|
@ -39,6 +39,9 @@ events_driver = none
|
|||
# The driver to use for the transforms repository
|
||||
transforms_driver = mysql_transforms_repo
|
||||
|
||||
# The driver to use for the alarm definitions repository
|
||||
alarm_definitions_driver = mysql_alarm_definitions_repo
|
||||
|
||||
# The driver to use for the notifications repository
|
||||
notifications_driver = mysql_notifications_repo
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# Copyright 2014 Hewlett-Packard
|
||||
#
|
||||
# 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.
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class AlarmDefinitionsV2API(object):
|
||||
|
||||
def __init__(self, global_conf):
|
||||
LOG.debug('initializing AlarmDefinitionsV2API!')
|
||||
self.global_conf = global_conf
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions', method='post')
|
||||
def do_post_alarm_definitions(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='get')
|
||||
def do_get_alarm_definition(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='put')
|
||||
def do_put_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions', method='get')
|
||||
def do_get_alarm_definitions(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='patch')
|
||||
def do_patch_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='delete')
|
||||
def do_delete_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
|
@ -46,30 +46,6 @@ class V2API(object):
|
|||
def do_get_statistics(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions', method='post')
|
||||
def do_post_alarm_definitions(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='get')
|
||||
def do_get_alarm_definition(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='put')
|
||||
def do_put_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions', method='get')
|
||||
def do_get_alarm_definitions(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='patch')
|
||||
def do_patch_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='delete')
|
||||
def do_delete_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarms/{id}', method='put')
|
||||
def do_put_alarms(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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
|
||||
|
@ -32,6 +32,7 @@ class TransformsV2API(object):
|
|||
def do_get_transforms(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/events/transforms/{transform_id}', method='delete')
|
||||
@resource_api.Restify('/v2.0/events/transforms/{transform_id}',
|
||||
method='delete')
|
||||
def do_delete_transforms(self, req, res, transform_id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# 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
|
||||
# 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
|
||||
|
@ -24,49 +24,56 @@ from paste.deploy import loadapp
|
|||
from wsgiref import simple_server
|
||||
|
||||
METRICS_DISPATCHER_NAMESPACE = 'monasca.metrics_dispatcher'
|
||||
ALARM_DEFINITIONS_DISPATCHER_NAMESPACE = 'monasca.alarm_definitions_dispatcher'
|
||||
EVENTS_DISPATCHER_NAMESPACE = 'monasca.events_dispatcher'
|
||||
TRANSFORMS_DISPATCHER_NAMESPACE = 'monasca.transforms_dispatcher'
|
||||
NOTIFICATIONS_DISPATCHER_NAMESPACE = 'monasca.notifications_dispatcher'
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
global_opts = [
|
||||
cfg.StrOpt('region', help='Region that API is running in')
|
||||
]
|
||||
global_opts = [cfg.StrOpt('region', help='Region that API is running in')]
|
||||
|
||||
cfg.CONF.register_opts(global_opts)
|
||||
|
||||
security_opts = [
|
||||
cfg.ListOpt('default_authorized_roles', default=['admin'],
|
||||
help='Roles that are allowed full access to the API'),
|
||||
cfg.ListOpt('agent_authorized_roles', default=['agent'],
|
||||
help='Roles that are only allowed to POST to the API'),
|
||||
cfg.ListOpt('delegate_authorized_roles', default=['admin'],
|
||||
help='Roles that are allowed to POST metrics on behalf of another tenant')
|
||||
]
|
||||
security_opts = [cfg.ListOpt('default_authorized_roles', default=['admin'],
|
||||
help='Roles that are allowed full access to the '
|
||||
'API'),
|
||||
cfg.ListOpt('agent_authorized_roles', default=['agent'],
|
||||
help='Roles that are only allowed to POST to '
|
||||
'the API'),
|
||||
cfg.ListOpt('delegate_authorized_roles', default=['admin'],
|
||||
help='Roles that are allowed to POST metrics on '
|
||||
'behalf of another tenant')]
|
||||
|
||||
security_group = cfg.OptGroup(name='security', title='security')
|
||||
cfg.CONF.register_group(security_group)
|
||||
cfg.CONF.register_opts(security_opts, security_group)
|
||||
|
||||
messaging_opts = [
|
||||
cfg.StrOpt('driver', default='kafka', help='The message queue driver to use'),
|
||||
cfg.StrOpt('metrics_message_format', default='reference',
|
||||
help='The type of metrics message format to publish to the message queue'),
|
||||
cfg.StrOpt('events_message_format', default='reference',
|
||||
help='The type of events message format to publish to the message queue')
|
||||
]
|
||||
messaging_opts = [cfg.StrOpt('driver', default='kafka',
|
||||
help='The message queue driver to use'),
|
||||
cfg.StrOpt('metrics_message_format', default='reference',
|
||||
help='The type of metrics message format to '
|
||||
'publish to the message queue'),
|
||||
cfg.StrOpt('events_message_format', default='reference',
|
||||
help='The type of events message format to '
|
||||
'publish to the message queue')]
|
||||
|
||||
messaging_group = cfg.OptGroup(name='messaging', title='messaging')
|
||||
cfg.CONF.register_group(messaging_group)
|
||||
cfg.CONF.register_opts(messaging_opts, messaging_group)
|
||||
|
||||
repositories_opts = [
|
||||
cfg.StrOpt('metrics_driver', default='influxdb_metrics_repo', help='The repository driver to use for metrics'),
|
||||
cfg.StrOpt('events_driver', default='fake_events_repo', help='The repository driver to use for events'),
|
||||
cfg.StrOpt('transforms_driver', default='mysql_transforms_repo', help='The repository driver to use for transforms'),
|
||||
cfg.StrOpt('notifications_driver', default='mysql_notifications_repo', help='The repository driver to use for notifications')
|
||||
]
|
||||
cfg.StrOpt('metrics_driver', default='influxdb_metrics_repo',
|
||||
help='The repository driver to use for metrics'),
|
||||
cfg.StrOpt('alarm_definitions_driver',
|
||||
default='mysql_alarm_definitions_repo',
|
||||
help='The repository driver to use for alarm definitions'),
|
||||
cfg.StrOpt('events_driver', default='fake_events_repo',
|
||||
help='The repository driver to use for events'),
|
||||
cfg.StrOpt('transforms_driver', default='mysql_transforms_repo',
|
||||
help='The repository driver to use for transforms'),
|
||||
cfg.StrOpt('notifications_driver', default='mysql_notifications_repo',
|
||||
help='The repository driver to use for notifications')]
|
||||
|
||||
repositories_group = cfg.OptGroup(name='repositories', title='repositories')
|
||||
cfg.CONF.register_group(repositories_group)
|
||||
|
@ -74,78 +81,58 @@ cfg.CONF.register_opts(repositories_opts, repositories_group)
|
|||
|
||||
dispatcher_opts = [
|
||||
cfg.StrOpt('driver', default='monasca.v2.reference.metrics:Metrics',
|
||||
help='The name of the dispatcher for the api server')
|
||||
]
|
||||
help='The name of the dispatcher for the api server')]
|
||||
|
||||
dispatcher_group = cfg.OptGroup(name='dispatcher', title='dispatcher')
|
||||
cfg.CONF.register_group(dispatcher_group)
|
||||
cfg.CONF.register_opts(dispatcher_opts, dispatcher_group)
|
||||
|
||||
kafka_opts = [
|
||||
cfg.StrOpt('uri',
|
||||
help='Address to kafka server. For example: '
|
||||
'uri=192.168.1.191:9092'),
|
||||
cfg.StrOpt('metrics_topic',
|
||||
default='metrics',
|
||||
help='The topic that metrics will be published too.'),
|
||||
cfg.StrOpt('events_topic',
|
||||
default='raw-events',
|
||||
help='The topic that events will be published too.'),
|
||||
cfg.StrOpt('group',
|
||||
default='api',
|
||||
help='The group name that this service belongs to.'),
|
||||
cfg.IntOpt('wait_time',
|
||||
default=1,
|
||||
help='The wait time when no messages on kafka queue.'),
|
||||
cfg.IntOpt('ack_time',
|
||||
default=20,
|
||||
help='The ack time back to kafka.'),
|
||||
cfg.IntOpt('max_retry',
|
||||
default=3,
|
||||
help='The number of retry when there is a connection error.'),
|
||||
cfg.BoolOpt('auto_commit',
|
||||
default=False,
|
||||
help='If automatically commmit when consume messages.'),
|
||||
cfg.BoolOpt('async',
|
||||
default=True,
|
||||
help='The type of posting.'),
|
||||
cfg.BoolOpt('compact',
|
||||
default=True,
|
||||
help=('Specify if the message received should be parsed.'
|
||||
'If True, message will not be parsed, otherwise '
|
||||
'messages will be parsed.')),
|
||||
cfg.MultiOpt('partitions',
|
||||
item_type=types.Integer(),
|
||||
default=[0],
|
||||
help='The sleep time when no messages on kafka queue.'),
|
||||
cfg.BoolOpt('drop_data',
|
||||
default=False,
|
||||
help=('Specify if received data should be simply dropped. '
|
||||
'This parameter is only for testing purposes.')),
|
||||
]
|
||||
kafka_opts = [cfg.StrOpt('uri', help='Address to kafka server. For example: '
|
||||
'uri=192.168.1.191:9092'),
|
||||
cfg.StrOpt('metrics_topic', default='metrics',
|
||||
help='The topic that metrics will be published too.'),
|
||||
cfg.StrOpt('events_topic', default='raw-events',
|
||||
help='The topic that events will be published too.'),
|
||||
cfg.StrOpt('group', default='api',
|
||||
help='The group name that this service belongs to.'),
|
||||
cfg.IntOpt('wait_time', default=1,
|
||||
help='The wait time when no messages on kafka '
|
||||
'queue.'),
|
||||
cfg.IntOpt('ack_time', default=20,
|
||||
help='The ack time back to kafka.'),
|
||||
cfg.IntOpt('max_retry', default=3,
|
||||
help='The number of retry when there is a '
|
||||
'connection error.'),
|
||||
cfg.BoolOpt('auto_commit', default=False,
|
||||
help='If automatically commmit when consume '
|
||||
'messages.'),
|
||||
cfg.BoolOpt('async', default=True, help='The type of posting.'),
|
||||
cfg.BoolOpt('compact', default=True, help=(
|
||||
'Specify if the message received should be parsed.'
|
||||
'If True, message will not be parsed, otherwise '
|
||||
'messages will be parsed.')),
|
||||
cfg.MultiOpt('partitions', item_type=types.Integer(),
|
||||
default=[0],
|
||||
help='The sleep time when no messages on kafka '
|
||||
'queue.'),
|
||||
cfg.BoolOpt('drop_data', default=False, help=(
|
||||
'Specify if received data should be simply dropped. '
|
||||
'This parameter is only for testing purposes.')), ]
|
||||
|
||||
kafka_group = cfg.OptGroup(name='kafka', title='title')
|
||||
cfg.CONF.register_group(kafka_group)
|
||||
cfg.CONF.register_opts(kafka_opts, kafka_group)
|
||||
|
||||
influxdb_opts = [
|
||||
cfg.StrOpt('database_name'),
|
||||
cfg.StrOpt('ip_address'),
|
||||
cfg.StrOpt('port'),
|
||||
cfg.StrOpt('user'),
|
||||
cfg.StrOpt('password')
|
||||
]
|
||||
influxdb_opts = [cfg.StrOpt('database_name'), cfg.StrOpt('ip_address'),
|
||||
cfg.StrOpt('port'), cfg.StrOpt('user'),
|
||||
cfg.StrOpt('password')]
|
||||
|
||||
influxdb_group = cfg.OptGroup(name='influxdb', title='influxdb')
|
||||
cfg.CONF.register_group(influxdb_group)
|
||||
cfg.CONF.register_opts(influxdb_opts, influxdb_group)
|
||||
|
||||
mysql_opts = [
|
||||
cfg.StrOpt('database_name'),
|
||||
cfg.StrOpt('hostname'),
|
||||
cfg.StrOpt('username'),
|
||||
cfg.StrOpt('password')
|
||||
]
|
||||
mysql_opts = [cfg.StrOpt('database_name'), cfg.StrOpt('hostname'),
|
||||
cfg.StrOpt('username'), cfg.StrOpt('password')]
|
||||
|
||||
mysql_group = cfg.OptGroup(name='mysql', title='mysql')
|
||||
cfg.CONF.register_group(mysql_group)
|
||||
|
@ -179,6 +166,11 @@ def api_app(conf):
|
|||
app.add_resource('notifications', NOTIFICATIONS_DISPATCHER_NAMESPACE,
|
||||
cfg.CONF.dispatcher.driver, [conf])
|
||||
|
||||
# load the alarm definitions resource
|
||||
app.add_resource('alarm-definitions',
|
||||
ALARM_DEFINITIONS_DISPATCHER_NAMESPACE,
|
||||
cfg.CONF.dispatcher.driver, [conf])
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2014 Hewlett-Packard
|
||||
#
|
||||
# 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.
|
||||
import abc
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class AlarmDefinitionsRepository(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_alarm_definition(self, tenant_id, name,
|
||||
expression, sub_expr_list, description, severity, match_by, alarm_actions,
|
||||
undetermined_actions, ok_action):
|
||||
pass
|
|
@ -0,0 +1,152 @@
|
|||
# Copyright 2014 Hewlett-Packard
|
||||
#
|
||||
# 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.
|
||||
import datetime
|
||||
import pyodbc
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.common.repositories import alarm_definitions_repository
|
||||
from monasca.openstack.common import log
|
||||
from monasca.openstack.common import uuidutils
|
||||
from monasca.common.repositories import exceptions
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class AlarmDefinitionsRepository(
|
||||
alarm_definitions_repository.AlarmDefinitionsRepository):
|
||||
database_driver = 'MySQL ODBC 5.3 Unicode Driver'
|
||||
database_cnxn_template = 'DRIVER={' \
|
||||
'%s};Server=%s;CHARSET=UTF8;Database=%s;Uid=%s' \
|
||||
';Pwd=%s'
|
||||
|
||||
def __init__(self):
|
||||
|
||||
try:
|
||||
self.conf = cfg.CONF
|
||||
database_name = self.conf.mysql.database_name
|
||||
database_server = self.conf.mysql.hostname
|
||||
database_uid = self.conf.mysql.username
|
||||
database_pwd = self.conf.mysql.password
|
||||
self._cnxn_string = (
|
||||
AlarmDefinitionsRepository.database_cnxn_template % (
|
||||
AlarmDefinitionsRepository.database_driver,
|
||||
database_server, database_name, database_uid,
|
||||
database_pwd))
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
|
||||
def create_alarm_definition(self, tenant_id, name, expression,
|
||||
sub_expr_list, description, severity, match_by,
|
||||
alarm_actions, undetermined_actions,
|
||||
ok_actions):
|
||||
|
||||
try:
|
||||
cnxn = pyodbc.connect(self._cnxn_string)
|
||||
cursor = cnxn.cursor()
|
||||
now = datetime.datetime.utcnow()
|
||||
alarm_definition_id = uuidutils.generate_uuid()
|
||||
cursor.execute("insert into alarm_definition("
|
||||
"id, "
|
||||
"tenant_id, "
|
||||
"name, "
|
||||
"description, "
|
||||
"expression, "
|
||||
"severity, "
|
||||
"match_by,"
|
||||
"actions_enabled, "
|
||||
"created_at, "
|
||||
"updated_at) "
|
||||
"values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
alarm_definition_id, tenant_id, name.encode('utf8'),
|
||||
description.encode('utf8'),
|
||||
expression.encode('utf8'),
|
||||
severity.upper().encode('utf8'),
|
||||
",".join(match_by).encode('utf8'), 1, now, now)
|
||||
|
||||
for sub_expr in sub_expr_list:
|
||||
sub_alarm_definition_id = uuidutils.generate_uuid()
|
||||
sub_expr.id = sub_alarm_definition_id
|
||||
cursor.execute("insert into sub_alarm_definition("
|
||||
"id, "
|
||||
"alarm_definition_id,"
|
||||
"function, "
|
||||
"metric_name, "
|
||||
"operator, "
|
||||
"threshold,"
|
||||
"period, "
|
||||
"periods, "
|
||||
"created_at, "
|
||||
"updated_at)"
|
||||
" values(?,?,?,?,?,?,?,?,?,?)",
|
||||
sub_alarm_definition_id, alarm_definition_id,
|
||||
sub_expr.get_normalized_func().encode('utf8'),
|
||||
sub_expr.get_normalized_metric_name().encode(
|
||||
"utf8"),
|
||||
sub_expr.get_normalized_operator().encode(
|
||||
'utf8'),
|
||||
sub_expr.get_threshold().encode('utf8'),
|
||||
sub_expr.get_period().encode('utf8'),
|
||||
sub_expr.get_periods().encode('utf8'), now, now)
|
||||
|
||||
for dimension in sub_expr.get_dimensions_as_list():
|
||||
parsed_dimension = dimension.split('=')
|
||||
cursor.execute(
|
||||
"insert into sub_alarm_definition_dimension("
|
||||
"sub_alarm_definition_id,"
|
||||
"dimension_name,"
|
||||
"value)"
|
||||
"values(?,?,?)", sub_alarm_definition_id,
|
||||
parsed_dimension[0].encode('utf8'),
|
||||
parsed_dimension[1].encode('utf8'))
|
||||
|
||||
self._insert_into_alarm_action(cursor, alarm_definition_id,
|
||||
alarm_actions, u"ALARM")
|
||||
self._insert_into_alarm_action(cursor, alarm_definition_id,
|
||||
undetermined_actions,
|
||||
u"UNDETERMINED")
|
||||
self._insert_into_alarm_action(cursor, alarm_definition_id,
|
||||
ok_actions, u"OK")
|
||||
|
||||
cnxn.commit()
|
||||
cnxn.close()
|
||||
|
||||
return alarm_definition_id
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
|
||||
def _insert_into_alarm_action(self, cursor, alarm_definition_id, actions,
|
||||
alarm_state):
|
||||
for action in actions:
|
||||
cursor.execute("select id from notification_method where id = ?",
|
||||
action.encode('utf8'))
|
||||
row = cursor.fetchone()
|
||||
if not row:
|
||||
raise exceptions.RepositoryException(
|
||||
"Non-existent notification id {} submitted for {} "
|
||||
"notification action".format(action.encode('utf8'),
|
||||
alarm_state.encode('utf8')))
|
||||
cursor.execute("insert into alarm_action("
|
||||
"alarm_id,"
|
||||
"alarm_state,"
|
||||
"action_id)"
|
||||
"values(?,?,?)", alarm_definition_id,
|
||||
alarm_state.encode('utf8'), action.encode('utf8'))
|
|
@ -25,21 +25,18 @@ RESOURCE_METHOD_FLAG = 'fab05a04-b861-4651-bd0c-9cb3eb9a6088'
|
|||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def init_driver(namespace, driver_name, drv_invoke_args=None):
|
||||
def init_driver(namespace, driver_name, drv_invoke_args=()):
|
||||
"""Initialize the resource driver and returns it.
|
||||
|
||||
:param namespace: the resource namespace (in setup.cfg).
|
||||
:param driver_name: the driver name (in monasca.conf)
|
||||
:param invoke_args: args to pass to the driver (a tuple)
|
||||
"""
|
||||
invoke_args_tuple = ()
|
||||
if drv_invoke_args:
|
||||
invoke_args_tuple = drv_invoke_args
|
||||
mgr = driver.DriverManager(
|
||||
namespace = namespace,
|
||||
name = driver_name,
|
||||
invoke_on_load = True,
|
||||
invoke_args = invoke_args_tuple
|
||||
invoke_args = drv_invoke_args
|
||||
)
|
||||
return mgr.driver
|
||||
|
||||
|
@ -135,7 +132,7 @@ class ResourceAPI(falcon.API):
|
|||
LOG.debug(self._routes)
|
||||
|
||||
def add_resource(self, resource_name, namespace, driver_name,
|
||||
invoke_args=None, uri=None):
|
||||
invoke_args=(), uri=None):
|
||||
"""Loads the resource driver, and adds it to the routes.
|
||||
|
||||
:param resource_name: the name of the resource.
|
||||
|
|
|
@ -38,4 +38,4 @@ class KafkaDispatcher(monasca_api_v2.V2API):
|
|||
msg = req.stream.read()
|
||||
|
||||
code = self._kafka_conn.send_messages(msg)
|
||||
res.status = getattr(falcon, 'HTTP_' + str(code))
|
||||
res.status = getattr(falcon, 'HTTP_' + str(code))
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 Hewlett-Packard
|
||||
#
|
||||
# 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.
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
from pyparsing import CaselessLiteral
|
||||
from pyparsing import alphanums
|
||||
from pyparsing import delimitedList
|
||||
from pyparsing import Forward
|
||||
from pyparsing import Group
|
||||
from pyparsing import Literal
|
||||
from pyparsing import nums
|
||||
from pyparsing import opAssoc
|
||||
from pyparsing import operatorPrecedence
|
||||
from pyparsing import Optional
|
||||
from pyparsing import stringEnd
|
||||
from pyparsing import Word
|
||||
|
||||
|
||||
class SubExpr(object):
|
||||
def __init__(self, tokens):
|
||||
self.sub_expr = tokens
|
||||
self.func = tokens.func
|
||||
self.metric_name = tokens.metric_name
|
||||
self.dimensions = tokens.dimensions.dimensions_list
|
||||
self.operator = tokens.relational_op
|
||||
self.threshold = tokens.threshold
|
||||
self.period = tokens.period
|
||||
self.periods = tokens.periods
|
||||
|
||||
def get_sub_expr_str(self):
|
||||
return "".join(list(itertools.chain(*self.sub_expr)))
|
||||
|
||||
def get_fmtd_sub_expr(self):
|
||||
|
||||
result = "{}({}".format(self.func.encode('utf8'),
|
||||
self.metric_name.encode('utf8'))
|
||||
|
||||
if self.dimensions:
|
||||
result += "{{{}}}".format(self.dimensions.encode('utf8'))
|
||||
|
||||
if self.period:
|
||||
result += ", {}".format(self.period.encode('utf8'))
|
||||
|
||||
result += ")"
|
||||
|
||||
result += " {} {}".format(self.operator.encode('utf8'),
|
||||
self.threshold.encode('utf8'))
|
||||
|
||||
if self.periods:
|
||||
result += " times {}".format(self.periods.encode('utf8'))
|
||||
|
||||
return result.decode('utf8')
|
||||
|
||||
def get_dimensions_str(self):
|
||||
return self.dimensions
|
||||
|
||||
def get_operands_list(self):
|
||||
return [self]
|
||||
|
||||
def get_func(self):
|
||||
return self.func
|
||||
|
||||
def get_normalized_func(self):
|
||||
return self.func.upper()
|
||||
|
||||
def get_metric_name(self):
|
||||
return self.metric_name
|
||||
|
||||
def get_normalized_metric_name(self):
|
||||
return self.metric_name.lower()
|
||||
|
||||
def get_dimensions(self):
|
||||
return self.dimensions
|
||||
|
||||
def get_dimensions_as_list(self):
|
||||
if self.dimensions:
|
||||
return self.dimensions.split(",")
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_operator(self):
|
||||
return self.operator
|
||||
|
||||
def get_threshold(self):
|
||||
return self.threshold
|
||||
|
||||
def get_period(self):
|
||||
if self.period:
|
||||
return self.period
|
||||
else:
|
||||
return u'60'
|
||||
|
||||
def get_periods(self):
|
||||
if self.periods:
|
||||
return self.periods
|
||||
else:
|
||||
return u'1'
|
||||
|
||||
def get_normalized_operator(self):
|
||||
if self.operator.lower() == "lt" or self.operator == "<":
|
||||
return u"LT"
|
||||
elif self.operator.lower() == "gt" or self.operator == ">":
|
||||
return u"GT"
|
||||
elif self.operator.lower() == "lte" or self.operator == "<=":
|
||||
return u"LTE"
|
||||
elif self.operator.lower() == "gte" or self.operator == ">=":
|
||||
return u"GTE"
|
||||
|
||||
|
||||
class BinaryOp(object):
|
||||
def __init__(self, tokens):
|
||||
self.op = tokens[0][1]
|
||||
self.operands = tokens[0][0::2]
|
||||
|
||||
def get_operands_list(self):
|
||||
return ([sub_operand for operand in self.operands for sub_operand in
|
||||
operand.get_operands_list()])
|
||||
|
||||
|
||||
class AndSubExpr(BinaryOp):
|
||||
""" Expand later as needed.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class OrSubExpr(BinaryOp):
|
||||
"""Expand later as needed.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
COMMA = Literal(",")
|
||||
LPAREN = Literal("(")
|
||||
RPAREN = Literal(")")
|
||||
EQUAL = Literal("=")
|
||||
LBRACE = Literal("{")
|
||||
RBRACE = Literal("}")
|
||||
|
||||
# Initialize non-ascii unicode code points in the Basic Multilingual Plane.
|
||||
unicode_printables = u''.join(
|
||||
unichr(c) for c in xrange(128, 65536) if not unichr(c).isspace())
|
||||
|
||||
# Does not like comma. No Literals from above allowed.
|
||||
valid_identifier_chars = (unicode_printables + alphanums + ".-_#!$%&'*+/:;?@["
|
||||
"\\]^`|~")
|
||||
|
||||
metric_name = Word(valid_identifier_chars, min=1, max=255)("metric_name")
|
||||
dimension_name = Word(valid_identifier_chars, min=1, max=255)
|
||||
dimension_value = Word(valid_identifier_chars, min=1, max=255)
|
||||
|
||||
integer_number = Word(nums)
|
||||
decimal_number = Word(nums + ".")
|
||||
|
||||
max = CaselessLiteral("max")
|
||||
min = CaselessLiteral("min")
|
||||
avg = CaselessLiteral("avg")
|
||||
count = CaselessLiteral("count")
|
||||
sum = CaselessLiteral("sum")
|
||||
func = (max | min | avg | count | sum)("func")
|
||||
|
||||
less_than_op = (CaselessLiteral("<") | CaselessLiteral("lt"))
|
||||
less_than_eq_op = (CaselessLiteral("<=") | CaselessLiteral("lte"))
|
||||
greater_than_op = (CaselessLiteral(">") | CaselessLiteral("gt"))
|
||||
greater_than_eq_op = (CaselessLiteral(">=") | CaselessLiteral("gte"))
|
||||
|
||||
# Order is important. Put longer prefix first.
|
||||
relational_op = (
|
||||
less_than_eq_op | less_than_op | greater_than_eq_op | greater_than_op)(
|
||||
"relational_op")
|
||||
|
||||
AND = CaselessLiteral("and") | CaselessLiteral("&&")
|
||||
OR = CaselessLiteral("or") | CaselessLiteral("||")
|
||||
logical_op = (AND | OR)("logical_op")
|
||||
|
||||
times = CaselessLiteral("times")
|
||||
|
||||
dimension = Group(dimension_name + EQUAL + dimension_value)
|
||||
dimension_list = Group(Optional(
|
||||
LBRACE + delimitedList(dimension, delim=",", combine=True)(
|
||||
"dimensions_list") + RBRACE))
|
||||
|
||||
metric = metric_name + dimension_list("dimensions")
|
||||
period = integer_number("period")
|
||||
threshold = decimal_number("threshold")
|
||||
periods = integer_number("periods")
|
||||
|
||||
expression = Forward()
|
||||
|
||||
sub_expression = (func + LPAREN + metric + Optional(
|
||||
COMMA + period) + RPAREN + relational_op + threshold + Optional(
|
||||
times + periods) | LPAREN + expression + RPAREN)
|
||||
|
||||
sub_expression.setParseAction(SubExpr)
|
||||
|
||||
expression = operatorPrecedence(sub_expression,
|
||||
[(AND, 2, opAssoc.LEFT, AndSubExpr),
|
||||
(OR, 2, opAssoc.LEFT, OrSubExpr)])
|
||||
|
||||
|
||||
class AlarmExprParser(object):
|
||||
def __init__(self, expr):
|
||||
self._expr = expr
|
||||
|
||||
def get_sub_expr_list(self):
|
||||
parseResult = (expression + stringEnd).parseString(self._expr)
|
||||
sub_expr_list = parseResult[0].get_operands_list()
|
||||
return sub_expr_list
|
||||
|
||||
|
||||
def main():
|
||||
""" Used for development and testing.
|
||||
|
||||
:return:
|
||||
"""
|
||||
expr = "max(-_.千幸福的笑脸{घोड़ा=馬,dn2=dv2}, 60) gte 100 times 3 and " \
|
||||
"(min(ເຮືອນ{dn3=dv3,家=дом}) < 10 or sum(biz{dn5=dv5}) > 99 and " \
|
||||
"count(fizzle) lt 0 or count(baz) > 1)".decode('utf8')
|
||||
# expr = "max(foo{hostname=mini-mon,千=千}, 120) > 100 and (max(bar)>100 \
|
||||
# or max(biz)>100)".decode('utf8')
|
||||
alarmExprParser = AlarmExprParser(expr)
|
||||
r = alarmExprParser.get_sub_expr_list()
|
||||
for sub_expression in r:
|
||||
print sub_expression.get_sub_expr_str()
|
||||
print sub_expression.get_fmtd_sub_expr()
|
||||
print sub_expression.get_dimensions_str()
|
||||
print
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
|
@ -12,6 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class MockAuthFilter(object):
|
||||
'''
|
||||
This authorization filter doesn't do any authentication, it just copies the
|
||||
|
@ -27,6 +28,7 @@ class MockAuthFilter(object):
|
|||
env['HTTP_X_ROLES'] = 'admin'
|
||||
return self.app(env, start_response)
|
||||
|
||||
|
||||
def filter_factory(global_conf, **local_conf):
|
||||
def validator_filter(app):
|
||||
return MockAuthFilter(app, local_conf)
|
||||
|
|
|
@ -84,4 +84,4 @@ class BaseTestCase(testtools.TestCase):
|
|||
os.write(fd, contents)
|
||||
finally:
|
||||
os.close(fd)
|
||||
return tempfiles
|
||||
return tempfiles
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright 2014 Hewlett-Packard
|
||||
#
|
||||
# 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.
|
||||
|
||||
from voluptuous import Schema, Length, Optional
|
||||
from voluptuous import Required, Any, All
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
alarm_definition_schema = {
|
||||
Required('name'): All(Any(str, unicode), Length(max=250)),
|
||||
Required('expression'): All(Any(str, unicode), Length(max=4096)),
|
||||
Optional('description'): All(Any(str, unicode), Length(max=250)),
|
||||
Optional('severity'): All(
|
||||
Any('low', 'medium', 'high', 'critical', 'LOW', "MEDIUM", 'HIGH',
|
||||
'CRITICAL')),
|
||||
Optional('match_by'): All(Any([unicode], [str]), Length(max=255)),
|
||||
Optional('ok_actions'): All(Any([str], [unicode]), Length(max=400)),
|
||||
Optional('alarm_actions'): All(Any([str], [unicode]), Length(max=400)),
|
||||
Optional('undetermined_actions'): All(Any([str], [unicode]),
|
||||
Length(max=400))}
|
||||
|
||||
request_body_schema = Schema(alarm_definition_schema, required=True,
|
||||
extra=True)
|
||||
|
||||
|
||||
def validate(msg):
|
||||
try:
|
||||
request_body_schema(msg)
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise exceptions.ValidationException(str(ex))
|
|
@ -19,8 +19,8 @@ from monasca.v2.common.schemas import exceptions
|
|||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# TODO: Add regex to validate dimension names don't use any excluded characters.
|
||||
dimensions_schema = Schema({All(Any(str, unicode), Length(max=255)): All(Any(str, unicode), Length(max=255))})
|
||||
dimensions_schema = Schema({All(Any(str, unicode), Length(max=255)):
|
||||
All(Any(str, unicode), Length(max=255))})
|
||||
|
||||
|
||||
def validate(dimensions):
|
||||
|
@ -28,4 +28,4 @@ def validate(dimensions):
|
|||
dimensions_schema(dimensions)
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
|
|
|
@ -20,7 +20,9 @@ from monasca.v2.common.schemas import exceptions
|
|||
LOG = log.getLogger(__name__)
|
||||
|
||||
# TODO: Add regex to validate key/values don't use any excluded characters.
|
||||
event_schema_request_body = Schema({All(Any(str, unicode), Length(max=255)): All(Any(None, str, unicode, bool, int, float, dict, []))})
|
||||
event_schema_request_body = Schema({All(Any(str, unicode), Length(max=255)):
|
||||
All(Any(None, str, unicode, bool, int,
|
||||
float, dict, []))})
|
||||
|
||||
|
||||
def validate(body):
|
||||
|
@ -28,4 +30,4 @@ def validate(body):
|
|||
event_schema_request_body(body)
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class ValidationException(Exception):
|
||||
pass
|
||||
pass
|
||||
|
|
|
@ -27,4 +27,4 @@ def validate(name):
|
|||
metric_name_schema(name)
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
|
|
|
@ -36,4 +36,4 @@ def validate(msg):
|
|||
request_body_schema(msg)
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
|
|
|
@ -22,7 +22,8 @@ LOG = log.getLogger(__name__)
|
|||
transform_schema = {
|
||||
Required('name'): Schema(All(Any(str, unicode), Length(max=64))),
|
||||
Required('description'): Schema(All(Any(str, unicode), Length(max=250))),
|
||||
Required('specification'): Schema(All(Any(str, unicode), Length(max=64536))),
|
||||
Required('specification'):
|
||||
Schema(All(Any(str, unicode), Length(max=64536))),
|
||||
Optional('enabled'): bool
|
||||
}
|
||||
|
||||
|
@ -34,4 +35,4 @@ def validate(msg):
|
|||
request_body_schema(msg)
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
raise exceptions.ValidationException(str(ex))
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
def date_handler(obj):
|
||||
return obj.isoformat() if hasattr(obj, 'isoformat') else obj
|
||||
return obj.isoformat() if hasattr(obj, 'isoformat') else obj
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
# Copyright 2014 Hewlett-Packard
|
||||
#
|
||||
# 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.
|
||||
import json
|
||||
|
||||
from pyparsing import ParseException
|
||||
import falcon
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common import resource_api
|
||||
from monasca.api.alarm_definitions_api_v2 import AlarmDefinitionsV2API
|
||||
from monasca.expression_parser.alarm_expr_parser import AlarmExprParser
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.common.schemas import \
|
||||
alarm_definition_request_body_schema as schema_alarms
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.reference.helpers import read_json_msg_body
|
||||
from monasca.common.messaging import exceptions as message_queue_exceptions
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class AlarmDefinitions(AlarmDefinitionsV2API):
|
||||
def __init__(self, global_conf):
|
||||
try:
|
||||
super(AlarmDefinitions, self).__init__(global_conf)
|
||||
|
||||
self._region = cfg.CONF.region
|
||||
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._delegate_authorized_roles = \
|
||||
cfg.CONF.security.delegate_authorized_roles
|
||||
self._post_metrics_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles + \
|
||||
cfg.CONF.security.agent_authorized_roles
|
||||
|
||||
self._message_queue = \
|
||||
resource_api.init_driver('monasca.messaging',
|
||||
cfg.CONF.messaging.driver,
|
||||
(['events']))
|
||||
|
||||
self._alarm_definitions_repo = resource_api.init_driver(
|
||||
'monasca.repositories',
|
||||
cfg.CONF.repositories.alarm_definitions_driver)
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions', method='post')
|
||||
def do_post_alarm_definitions(self, req, res):
|
||||
helpers.validate_authorization(req, self._default_authorized_roles)
|
||||
|
||||
alarm_definition = read_json_msg_body(req)
|
||||
|
||||
self._validate_alarm_definition(alarm_definition)
|
||||
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
name = get_query_alarm_definition_name(alarm_definition)
|
||||
expression = get_query_alarm_definition_expression(
|
||||
alarm_definition)
|
||||
description = get_query_alarm_definition_description(
|
||||
alarm_definition)
|
||||
severity = get_query_alarm_definition_severity(
|
||||
alarm_definition)
|
||||
match_by = get_query_alarm_definition_match_by(
|
||||
alarm_definition)
|
||||
alarm_actions = get_query_alarm_definition_alarm_actions(
|
||||
alarm_definition)
|
||||
undetermined_actions = \
|
||||
get_query_alarm_definition_undetermined_actions(
|
||||
alarm_definition)
|
||||
ok_actions = get_query_ok_actions(alarm_definition)
|
||||
|
||||
result = self._alarm_definition_create(tenant_id, name, expression,
|
||||
description, severity, match_by,
|
||||
alarm_actions,
|
||||
undetermined_actions,
|
||||
ok_actions)
|
||||
|
||||
helpers.add_links_to_resource(result, req.uri)
|
||||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||
res.status = falcon.HTTP_201
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='get')
|
||||
def do_get_alarm_definition(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='put')
|
||||
def do_put_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions', method='get')
|
||||
def do_get_alarm_definitions(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='patch')
|
||||
def do_patch_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='delete')
|
||||
def do_delete_alarm_definitions(self, req, res, id):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
def _validate_alarm_definition(self, alarm_definition):
|
||||
|
||||
try:
|
||||
schema_alarms.validate(alarm_definition)
|
||||
except schemas_exceptions.ValidationException as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad reqeust', ex.message)
|
||||
|
||||
def _alarm_definition_create(self, tenant_id, name, expression,
|
||||
description, severity, match_by,
|
||||
alarm_actions, undetermined_actions,
|
||||
ok_actions):
|
||||
try:
|
||||
sub_expr_list = AlarmExprParser(expression).get_sub_expr_list()
|
||||
|
||||
alarm_definition_id = \
|
||||
self._alarm_definitions_repo.create_alarm_definition(
|
||||
tenant_id, name, expression, sub_expr_list, description,
|
||||
severity, match_by, alarm_actions, undetermined_actions,
|
||||
ok_actions)
|
||||
|
||||
self._send_alarm_definition_created_event(tenant_id,
|
||||
alarm_definition_id,
|
||||
name, expression,
|
||||
sub_expr_list,
|
||||
description, match_by)
|
||||
result = (
|
||||
{u'alarm_actions': alarm_actions, u'ok_actions': ok_actions,
|
||||
u'description': description, u'match_by': match_by,
|
||||
u'severity': severity.lower(), u'actions_enabled': u'true',
|
||||
u'undetermined_actions': undetermined_actions,
|
||||
u'expression': expression, u'id': alarm_definition_id,
|
||||
u'name': name})
|
||||
|
||||
return result
|
||||
|
||||
except ParseException as ex:
|
||||
LOG.exception(ex)
|
||||
title = "Invalid alarm expression".encode('utf8')
|
||||
msg = "parser failed on expression '{}' at column {}".format(
|
||||
expression.encode('utf8'), str(ex.column).encode('utf'))
|
||||
raise falcon.HTTPBadRequest(title, msg)
|
||||
except exceptions.RepositoryException as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message[1])
|
||||
|
||||
def _send_alarm_definition_created_event(self, tenant_id,
|
||||
alarm_definition_id, name,
|
||||
expression, sub_expr_list,
|
||||
description, match_by):
|
||||
|
||||
alarm_definition_created_event_msg = {
|
||||
u'alarm-definition-created': {u'tenantId': tenant_id,
|
||||
u'alarmDefinitionId':
|
||||
alarm_definition_id,
|
||||
u'alarmName': name,
|
||||
u'alarmDescription': description,
|
||||
u'alarmExpression': expression,
|
||||
u'matchBy': match_by}}
|
||||
|
||||
sub_expr_event_msg = {}
|
||||
for sub_expr in sub_expr_list:
|
||||
sub_expr_event_msg[sub_expr.id] = {
|
||||
u'function': sub_expr.get_normalized_func()}
|
||||
metric_definition = {
|
||||
u'name': sub_expr.get_normalized_metric_name()}
|
||||
sub_expr_event_msg[sub_expr.id][
|
||||
u'metricDefinition'] = metric_definition
|
||||
dimensions = {}
|
||||
for dimension in sub_expr.get_dimensions_as_list():
|
||||
parsed_dimension = dimension.split("=")
|
||||
dimensions[parsed_dimension[0]] = parsed_dimension[1]
|
||||
metric_definition[u'dimensions'] = dimensions
|
||||
sub_expr_event_msg[sub_expr.id][
|
||||
u'operator'] = sub_expr.get_normalized_operator()
|
||||
sub_expr_event_msg[sub_expr.id][
|
||||
u'threshold'] = sub_expr.get_threshold()
|
||||
sub_expr_event_msg[sub_expr.id][u'period'] = sub_expr.get_period()
|
||||
sub_expr_event_msg[sub_expr.id][
|
||||
u'periods'] = sub_expr.get_periods()
|
||||
sub_expr_event_msg[sub_expr.id][
|
||||
u'expression'] = sub_expr.get_fmtd_sub_expr()
|
||||
|
||||
alarm_definition_created_event_msg[u'alarm-definition-created'][
|
||||
u'alarmSubExpressions'] = sub_expr_event_msg
|
||||
|
||||
self._send_event(alarm_definition_created_event_msg)
|
||||
|
||||
def _send_event(self, event_msg):
|
||||
try:
|
||||
self._message_queue.send_message(
|
||||
json.dumps(event_msg, ensure_ascii=False).encode('utf8'))
|
||||
except message_queue_exceptions.MessageQueueException as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPInternalServerError(
|
||||
'Message queue service unavailable'.encode('utf8'),
|
||||
ex.message.encode('utf8'))
|
||||
|
||||
|
||||
def get_query_alarm_definition_name(alarm_definition):
|
||||
try:
|
||||
if 'name' in alarm_definition:
|
||||
name = alarm_definition['name']
|
||||
return name
|
||||
else:
|
||||
raise Exception("Missing name")
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||
|
||||
|
||||
def get_query_alarm_definition_expression(alarm_definition):
|
||||
try:
|
||||
if 'expression' in alarm_definition:
|
||||
expression = alarm_definition['expression']
|
||||
return expression
|
||||
else:
|
||||
raise Exception("Missing expression")
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||
|
||||
def get_query_alarm_definition_description(alarm_definition):
|
||||
if 'description' in alarm_definition:
|
||||
return alarm_definition['description']
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def get_query_alarm_definition_severity(alarm_definition):
|
||||
if 'severity' in alarm_definition:
|
||||
severity = alarm_definition['severity']
|
||||
severity = severity.decode('utf8').lower()
|
||||
if severity not in ['low', 'medium', 'high', 'critical']:
|
||||
raise falcon.HTTPBadRequest('Bad request, Invalid severity')
|
||||
return severity
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def get_query_alarm_definition_match_by(alarm_definition):
|
||||
if 'match_by' in alarm_definition:
|
||||
match_by = alarm_definition['match_by']
|
||||
return match_by
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_query_alarm_definition_alarm_actions(alarm_definition):
|
||||
if 'alarm_actions' in alarm_definition:
|
||||
alarm_actions = alarm_definition['alarm_actions']
|
||||
return alarm_actions
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_query_alarm_definition_undetermined_actions(alarm_definition):
|
||||
if 'undetermined_actions' in alarm_definition:
|
||||
undetermined_actions = alarm_definition['undetermined_actions']
|
||||
return undetermined_actions
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_query_ok_actions(alarm_definition):
|
||||
if 'ok_actions' in alarm_definition:
|
||||
ok_actions = alarm_definition['ok_actions']
|
||||
return ok_actions
|
||||
else:
|
||||
return []
|
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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
|
||||
|
@ -24,7 +24,8 @@ from monasca.common.messaging import exceptions as message_queue_exceptions
|
|||
from monasca.common.messaging.message_formats import events_transform_factory
|
||||
from monasca.v2.common import utils
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import events_request_body_schema as schemas_event
|
||||
from monasca.v2.common.schemas import \
|
||||
events_request_body_schema as schemas_event
|
||||
from monasca.v2.reference import helpers
|
||||
|
||||
from stevedore import driver
|
||||
|
@ -36,13 +37,19 @@ class Events(monasca_events_api_v2.EventsV2API):
|
|||
def __init__(self, global_conf):
|
||||
super(Events, self).__init__(global_conf)
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = cfg.CONF.security.default_authorized_roles
|
||||
self._delegate_authorized_roles = cfg.CONF.security.delegate_authorized_roles
|
||||
self._post_events_authorized_roles = cfg.CONF.security.default_authorized_roles + \
|
||||
cfg.CONF.security.agent_authorized_roles
|
||||
self._event_transform = events_transform_factory.create_events_transform()
|
||||
self._message_queue = resource_api.init_driver('monasca.messaging',
|
||||
cfg.CONF.messaging.driver, ['raw-events'])
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._delegate_authorized_roles = \
|
||||
cfg.CONF.security.delegate_authorized_roles
|
||||
self._post_events_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles + \
|
||||
cfg.CONF.security.agent_authorized_roles
|
||||
self._event_transform = \
|
||||
events_transform_factory.create_events_transform()
|
||||
self._message_queue = \
|
||||
resource_api.init_driver('monasca.messaging',
|
||||
cfg.CONF.messaging.driver,
|
||||
['raw-events'])
|
||||
|
||||
def _validate_event(self, event):
|
||||
"""Validates the event
|
||||
|
@ -63,11 +70,13 @@ class Events(monasca_events_api_v2.EventsV2API):
|
|||
:raises: falcon.HTTPServiceUnavailable
|
||||
"""
|
||||
try:
|
||||
str_msg = json.dumps(event, default=utils.date_handler)
|
||||
str_msg = json.dumps(event, default=utils.date_handler,
|
||||
ensure_ascii=False).encode('utf8')
|
||||
self._message_queue.send_message(str_msg)
|
||||
except message_queue_exceptions.MessageQueueException as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable', ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
@resource_api.Restify('/v2.0/events/', method='post')
|
||||
def do_post_events(self, req, res):
|
||||
|
@ -76,6 +85,7 @@ class Events(monasca_events_api_v2.EventsV2API):
|
|||
event = helpers.read_http_resource(req)
|
||||
self._validate_event(event)
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
transformed_event = self._event_transform(event, tenant_id, self._region)
|
||||
transformed_event = self._event_transform(event, tenant_id,
|
||||
self._region)
|
||||
self._send_event(transformed_event)
|
||||
res.status = falcon.HTTP_204
|
||||
res.status = falcon.HTTP_204
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import datetime
|
||||
import json
|
||||
|
||||
import falcon
|
||||
from falcon.util.uri import parse_query_string
|
||||
|
@ -25,6 +26,23 @@ import simplejson
|
|||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def read_json_msg_body(req):
|
||||
'''
|
||||
Read the json_msg from the http request body and return them as JSON.
|
||||
:param req: HTTP request object.
|
||||
:return: Returns the metrics as a JSON object.
|
||||
:raises falcon.HTTPBadRequest:
|
||||
'''
|
||||
try:
|
||||
msg = req.stream.read()
|
||||
json_msg = json.loads(msg)
|
||||
return json_msg
|
||||
except ValueError as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad request',
|
||||
'Request body is not valid JSON')
|
||||
|
||||
|
||||
def validate_json_content_type(req):
|
||||
if req.content_type not in ['application/json']:
|
||||
raise falcon.HTTPBadRequest('Bad request', 'Bad content type. Must be '
|
||||
|
@ -79,7 +97,7 @@ def get_tenant_id(req):
|
|||
return req.get_header('X-TENANT-ID')
|
||||
|
||||
|
||||
def get_cross_tenant_or_tenant_id(req, delegate_authorized_roles):
|
||||
def get_x_tenant_or_tenant_id(req, delegate_authorized_roles):
|
||||
"""Evaluates whether the tenant ID or cross tenant ID should be returned.
|
||||
|
||||
:param req: HTTP request object.
|
||||
|
@ -95,16 +113,24 @@ def get_cross_tenant_or_tenant_id(req, delegate_authorized_roles):
|
|||
return get_tenant_id(req)
|
||||
|
||||
|
||||
def get_query_name(req):
|
||||
"""Returns the query param "name" if supplied.
|
||||
|
||||
def get_query_name(req, name_required=False):
|
||||
'''
|
||||
Returns the query param "name" if supplied.
|
||||
:param req: HTTP request object.
|
||||
"""
|
||||
params = parse_query_string(req.query_string)
|
||||
name = ''
|
||||
if 'name' in params:
|
||||
name = params['name']
|
||||
return name
|
||||
'''
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
if 'name' in params:
|
||||
name = params['name']
|
||||
return name
|
||||
else:
|
||||
if name_required:
|
||||
raise Exception("Missing name")
|
||||
else:
|
||||
return ''
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||
|
||||
|
||||
def get_query_dimensions(req):
|
||||
|
|
|
@ -27,7 +27,11 @@ from monasca.v2.common import utils
|
|||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import \
|
||||
metrics_request_body_schema as schemas_metrics
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.reference.helpers import read_json_msg_body
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
@ -35,21 +39,30 @@ LOG = log.getLogger(__name__)
|
|||
|
||||
class Metrics(monasca_api_v2.V2API):
|
||||
def __init__(self, global_conf):
|
||||
super(Metrics, self).__init__(global_conf)
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._delegate_authorized_roles = \
|
||||
cfg.CONF.security.delegate_authorized_roles
|
||||
self._post_metrics_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles + \
|
||||
cfg.CONF.security.agent_authorized_roles
|
||||
self._metrics_transform = \
|
||||
metrics_transform_factory.create_metrics_transform()
|
||||
self._message_queue = resource_api.init_driver('monasca.messaging',
|
||||
cfg.CONF.messaging.driver, ['metrics'])
|
||||
self._metrics_repo = resource_api.init_driver('monasca.repositories',
|
||||
cfg.CONF.repositories.metrics_driver)
|
||||
|
||||
try:
|
||||
super(Metrics, self).__init__(global_conf)
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._delegate_authorized_roles = \
|
||||
cfg.CONF.security.delegate_authorized_roles
|
||||
self._post_metrics_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles + \
|
||||
cfg.CONF.security.agent_authorized_roles
|
||||
self._metrics_transform = \
|
||||
metrics_transform_factory.create_metrics_transform()
|
||||
self._message_queue = resource_api.init_driver(
|
||||
'monasca.messaging',
|
||||
cfg.CONF.messaging.driver,
|
||||
['metrics'])
|
||||
self._metrics_repo = resource_api.init_driver(
|
||||
'monasca.repositories', cfg.CONF.repositories.metrics_driver)
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _validate_metrics(self, metrics):
|
||||
"""Validates the metrics
|
||||
|
@ -101,8 +114,8 @@ class Metrics(monasca_api_v2.V2API):
|
|||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _measurement_list(self, tenant_id, name, dimensions,
|
||||
start_timestamp, end_timestamp):
|
||||
def _measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp):
|
||||
try:
|
||||
return self._metrics_repo.measurement_list(tenant_id, name,
|
||||
dimensions,
|
||||
|
@ -113,21 +126,19 @@ class Metrics(monasca_api_v2.V2API):
|
|||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _metric_statistics(self, tenant_id, name, dimensions,
|
||||
start_timestamp, end_timestamp, statistics, period):
|
||||
def _metric_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp, statistics, period):
|
||||
try:
|
||||
return self._metrics_repo.metrics_statistics(tenant_id, name,
|
||||
dimensions,
|
||||
start_timestamp,
|
||||
end_timestamp,
|
||||
statistics,
|
||||
period)
|
||||
dimensions,
|
||||
start_timestamp,
|
||||
end_timestamp,
|
||||
statistics, period)
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
|
||||
@resource_api.Restify('/v2.0/metrics/', method='post')
|
||||
def do_post_metrics(self, req, res):
|
||||
helpers.validate_json_content_type(req)
|
||||
|
@ -135,8 +146,9 @@ class Metrics(monasca_api_v2.V2API):
|
|||
self._post_metrics_authorized_roles)
|
||||
metrics = helpers.read_http_resource(req)
|
||||
self._validate_metrics(metrics)
|
||||
tenant_id = helpers.get_cross_tenant_or_tenant_id(req,
|
||||
self._delegate_authorized_roles)
|
||||
tenant_id = \
|
||||
helpers.get_x_tenant_or_tenant_id(req,
|
||||
self._delegate_authorized_roles)
|
||||
transformed_metrics = self._metrics_transform(metrics, tenant_id,
|
||||
self._region)
|
||||
self._send_metrics(transformed_metrics)
|
||||
|
@ -182,7 +194,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
statistics = helpers.get_query_statistics(req)
|
||||
period = helpers.get_query_period(req)
|
||||
result = self._metric_statistics(tenant_id, name, dimensions,
|
||||
start_timestamp, end_timestamp,
|
||||
statistics, period)
|
||||
start_timestamp, end_timestamp,
|
||||
statistics, period)
|
||||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||
res.status = falcon.HTTP_200
|
||||
res.status = falcon.HTTP_200
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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
|
||||
|
@ -26,20 +26,21 @@ from monasca.api import monasca_notifications_api_v2
|
|||
from monasca.common import resource_api
|
||||
from monasca.common.repositories import exceptions as repository_exceptions
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import notifications_request_body_schema as schemas_notifications
|
||||
from monasca.v2.common.schemas import \
|
||||
notifications_request_body_schema as schemas_notifications
|
||||
from monasca.v2.reference import helpers
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
||||
|
||||
def __init__(self, global_conf):
|
||||
super(Notifications, self).__init__(global_conf)
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = cfg.CONF.security.default_authorized_roles
|
||||
self._notifications_repo = resource_api.init_driver('monasca.repositories',
|
||||
cfg.CONF.repositories.notifications_driver)
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._notifications_repo = resource_api.init_driver(
|
||||
'monasca.repositories', cfg.CONF.repositories.notifications_driver)
|
||||
|
||||
def _validate_notification(self, notification):
|
||||
"""Validates the notification
|
||||
|
@ -64,20 +65,16 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
notification_type = notification['type'].upper()
|
||||
address = notification['address']
|
||||
if self._notifications_repo.exists(tenant_id, name):
|
||||
raise falcon.HTTPConflict(
|
||||
'Conflict', ('Notification Method already exists: tenant_id=%s name=%s' %
|
||||
(tenant_id, name)), code=409)
|
||||
self._notifications_repo.create_notification(
|
||||
id,
|
||||
tenant_id,
|
||||
name,
|
||||
notification_type,
|
||||
address)
|
||||
raise falcon.HTTPConflict('Conflict', (
|
||||
'Notification Method already exists: tenant_id=%s name=%s' % (
|
||||
tenant_id, name)), code=409)
|
||||
self._notifications_repo.create_notification(id, tenant_id, name,
|
||||
notification_type,
|
||||
address)
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError(
|
||||
'Service unavailable',
|
||||
ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _update_notification(self, id, tenant_id, notification):
|
||||
"""Update the notification using the repository.
|
||||
|
@ -89,31 +86,24 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
name = notification['name']
|
||||
notification_type = notification['type'].upper()
|
||||
address = notification['address']
|
||||
self._notifications_repo.update_notification(
|
||||
id,
|
||||
tenant_id,
|
||||
name,
|
||||
notification_type,
|
||||
address)
|
||||
self._notifications_repo.update_notification(id, tenant_id, name,
|
||||
notification_type,
|
||||
address)
|
||||
except repository_exceptions.DoesNotExistException:
|
||||
helpers.raise_not_found_exception('notification', id, tenant_id)
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError(
|
||||
'Service unavailable',
|
||||
ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _create_notification_response(self, id, notification, uri):
|
||||
name = notification['name']
|
||||
notification_type = notification['type'].upper()
|
||||
address = notification['address']
|
||||
response = {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'type': notification_type,
|
||||
'address': address
|
||||
}
|
||||
return json.dumps(helpers.add_links_to_resource(response, uri))
|
||||
response = {'id': id, 'name': name, 'type': notification_type,
|
||||
'address': address}
|
||||
return json.dumps(helpers.add_links_to_resource(response, uri),
|
||||
ensure_ascii=False).encode('utf8')
|
||||
|
||||
def _list_notifications(self, tenant_id, uri):
|
||||
"""Lists all notifications for this tenant id.
|
||||
|
@ -128,9 +118,8 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
helpers.add_links_to_resource_list(notifications, uri))
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError(
|
||||
'Service unavailable',
|
||||
ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _list_notification(self, tenant_id, notification_id, uri):
|
||||
"""Lists the notification by id.
|
||||
|
@ -141,17 +130,16 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
"""
|
||||
try:
|
||||
notifications = self._notifications_repo.list_notification(
|
||||
tenant_id,
|
||||
notification_id)
|
||||
tenant_id, notification_id)
|
||||
return json.dumps(
|
||||
helpers.add_links_to_resource(notifications, uri))
|
||||
except repository_exceptions.DoesNotExistException:
|
||||
helpers.raise_not_found_exception('notification', notification_id, tenant_id)
|
||||
helpers.raise_not_found_exception('notification', notification_id,
|
||||
tenant_id)
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError(
|
||||
'Service unavailable',
|
||||
ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _delete_notification(self, tenant_id, notification_id):
|
||||
"""Deletes the notification using the repository.
|
||||
|
@ -161,16 +149,15 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
:raises: falcon.HTTPServiceUnavailable,falcon.HTTPError (404)
|
||||
"""
|
||||
try:
|
||||
self._notifications_repo.delete_notification(
|
||||
tenant_id,
|
||||
notification_id)
|
||||
self._notifications_repo.delete_notification(tenant_id,
|
||||
notification_id)
|
||||
except repository_exceptions.DoesNotExistException:
|
||||
helpers.raise_not_found_exception('notification', notification_id, tenant_id)
|
||||
helpers.raise_not_found_exception('notification', notification_id,
|
||||
tenant_id)
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError(
|
||||
'Service unavailable',
|
||||
ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
@resource_api.Restify('/v2.0/notification-methods', method='post')
|
||||
def do_post_notification_methods(self, req, res):
|
||||
|
@ -181,10 +168,8 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
id = uuidutils.generate_uuid()
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
self._create_notification(id, tenant_id, notification)
|
||||
res.body = self._create_notification_response(
|
||||
id,
|
||||
notification,
|
||||
req.uri)
|
||||
res.body = self._create_notification_response(id, notification,
|
||||
req.uri)
|
||||
res.status = falcon.HTTP_200
|
||||
|
||||
@resource_api.Restify('/v2.0/notification-methods', method='get')
|
||||
|
@ -216,8 +201,6 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
self._validate_notification(notification)
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
self._update_notification(id, tenant_id, notification)
|
||||
res.body = self._create_notification_response(
|
||||
id,
|
||||
notification,
|
||||
req.uri)
|
||||
res.body = self._create_notification_response(id, notification,
|
||||
req.uri)
|
||||
res.status = falcon.HTTP_200
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
# 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
|
||||
|
@ -12,7 +12,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# TODO: Used simplejson to read the yaml as simplejson transforms to "str" not "unicode"
|
||||
# TODO: Used simplejson to read the yaml as simplejson transforms to "str"
|
||||
# not "unicode"
|
||||
|
||||
import json
|
||||
import simplejson
|
||||
|
@ -26,7 +27,8 @@ from monasca.api import monasca_transforms_api_v2
|
|||
from monasca.common import resource_api
|
||||
from monasca.common.repositories import exceptions as repository_exceptions
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import transforms_request_body_schema as schemas_transforms
|
||||
from monasca.v2.common.schemas import \
|
||||
transforms_request_body_schema as schemas_transforms
|
||||
from monasca.v2.reference import helpers
|
||||
|
||||
from stevedore import driver
|
||||
|
@ -38,9 +40,10 @@ class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
|||
def __init__(self, global_conf):
|
||||
super(Transforms, self).__init__(global_conf)
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = cfg.CONF.security.default_authorized_roles
|
||||
self._transforms_repo = resource_api.init_driver('monasca.repositories',
|
||||
cfg.CONF.repositories.transforms_driver)
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._transforms_repo = resource_api.init_driver(
|
||||
'monasca.repositories', cfg.CONF.repositories.transforms_driver)
|
||||
|
||||
def _validate_transform(self, transform):
|
||||
"""Validates the transform
|
||||
|
@ -65,32 +68,31 @@ class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
|||
description = transform['description']
|
||||
specification = transform['specification']
|
||||
enabled = transform['enabled']
|
||||
self._transforms_repo.create_transforms(id, tenant_id, name, description, specification, enabled)
|
||||
self._transforms_repo.create_transforms(id, tenant_id, name,
|
||||
description, specification,
|
||||
enabled)
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable', ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _create_transform_response(self, id, transform):
|
||||
name = transform['name']
|
||||
description = transform['description']
|
||||
specification = transform['specification']
|
||||
enabled = transform['enabled']
|
||||
response = {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'specification': specification,
|
||||
'enabled': enabled
|
||||
}
|
||||
response = {'id': id, 'name': name, 'description': description,
|
||||
'specification': specification, 'enabled': enabled}
|
||||
return json.dumps(response)
|
||||
|
||||
def _list_transforms(self, tenant_id):
|
||||
try:
|
||||
transforms = self._transforms_repo.list_transforms(tenant_id)
|
||||
transforms = self._transforms_repo.list_transforms(tenant_id)
|
||||
return json.dumps(transforms)
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable', ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
def _delete_transform(self, tenant_id, transform_id):
|
||||
try:
|
||||
|
@ -99,7 +101,8 @@ class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
|||
raise falcon.HTTPNotFound()
|
||||
except repository_exceptions.RepositoryException as ex:
|
||||
LOG.error(ex)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable', ex.message)
|
||||
raise falcon.HTTPInternalServerError('Service unavailable',
|
||||
ex.message)
|
||||
|
||||
@resource_api.Restify('/v2.0/events/transforms', method='post')
|
||||
def do_post_transforms(self, req, res):
|
||||
|
@ -120,9 +123,10 @@ class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
|||
res.body = self._list_transforms(tenant_id)
|
||||
res.status = falcon.HTTP_200
|
||||
|
||||
@resource_api.Restify('/v2.0/events/transforms/{transform_id}', method='delete')
|
||||
@resource_api.Restify('/v2.0/events/transforms/{transform_id}',
|
||||
method='delete')
|
||||
def do_delete_transforms(self, req, res, transform_id):
|
||||
helpers.validate_authorization(req, self._default_authorized_roles)
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
self._delete_transform(tenant_id, transform_id)
|
||||
res.status = falcon.HTTP_204
|
||||
res.status = falcon.HTTP_204
|
||||
|
|
|
@ -37,6 +37,9 @@ monasca.metrics_dispatcher =
|
|||
kafka = monasca.dispatcher.kafka_dispatcher:KafkaDispatcher
|
||||
v2_reference = monasca.v2.reference.metrics:Metrics
|
||||
|
||||
monasca.alarm_definitions_dispatcher =
|
||||
v2_reference = monasca.v2.reference.alarm_definitions:AlarmDefinitions
|
||||
|
||||
monasca.events_dispatcher =
|
||||
v2_reference = monasca.v2.reference.events:Events
|
||||
|
||||
|
@ -62,6 +65,7 @@ monasca.repositories =
|
|||
influxdb_metrics_repo = monasca.common.repositories.influxdb.metrics_repository:MetricsRepository
|
||||
fake_events_repo = monasca.common.repositories.fake.events_repository:EventsRepository
|
||||
mysql_transforms_repo = monasca.common.repositories.mysql.transforms_repository:TransformsRepository
|
||||
mysql_alarm_definitions_repo = monasca.common.repositories.mysql.alarm_definitions_repository:AlarmDefinitionsRepository
|
||||
mysql_notifications_repo = monasca.common.repositories.mysql.notifications_repository:NotificationsRepository
|
||||
|
||||
[pbr]
|
||||
|
|
Loading…
Reference in New Issue