Removed non-events API methods
This commit is contained in:
Joe Keen 2015-04-27 15:55:55 -06:00
parent d8270168e9
commit 9e688a1169
17 changed files with 0 additions and 2424 deletions

View File

@ -1,51 +0,0 @@
# 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):
super(AlarmDefinitionsV2API, self).__init__(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'

View File

@ -1,55 +0,0 @@
# 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 AlarmsV2API(object):
def __init__(self, global_conf):
super(AlarmsV2API, self).__init__(global_conf)
LOG.debug('initializing AlarmsV2API!')
self.global_conf = global_conf
@resource_api.Restify('/v2.0/alarms/{id}', method='put')
def do_put_alarms(self, req, res, id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/alarms/{id}', method='patch')
def do_patch_alarms(self, req, res, id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/alarms/{id}', method='delete')
def do_delete_alarms(self, req, res, id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/alarms/', method='get')
def do_get_alarms(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/alarms/{id}', method='get')
def do_get_alarm_by_id(self, req, res, id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/alarms/x', method='get')
def do_get_alarms_state_history(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/alarms/{id}/state-history', method='get')
def do_get_alarm_state_history(self, req, res, id):
res.status = '501 Not Implemented'

View File

@ -1,47 +0,0 @@
# Copyright 2013 IBM Corp
#
# Author: Tong Li <litong01@us.ibm.com>
#
# 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 V2API(object):
def __init__(self, global_conf):
LOG.debug('initializing V2API!')
self.global_conf = global_conf
@resource_api.Restify('/v2.0/metrics', method='get')
def do_get_metrics(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/metrics/', method='post')
def do_post_metrics(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/{version_id}', method='get')
def do_get_version(self, req, res, version_id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/metrics/measurements', method='get')
def do_get_measurements(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/metrics/statistics', method='get')
def do_get_statistics(self, req, res):
res.status = '501 Not Implemented'

View File

@ -1,46 +0,0 @@
# 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 NotificationsV2API(object):
def __init__(self, global_conf):
LOG.debug('initializing V2API!')
self.global_conf = global_conf
@resource_api.Restify('/v2.0/notification-methods', method='post')
def do_post_notification_methods(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/notification-methods/{id}', method='delete')
def do_delete_notification_methods(self, req, res, id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/notification-methods', method='get')
def do_get_notification_methods(self, req, res):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/notification-methods/{id}', method='get')
def do_get_notification_method(self, req, res, id):
res.status = '501 Not Implemented'
@resource_api.Restify('/v2.0/notification-methods/{id}', method='put')
def do_put_notification_methods(self, req, res, id):
res.status = '501 Not Implemented'

View File

@ -1,297 +0,0 @@
#!/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
import pyparsing
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
self._id = None
@property
def sub_expr_str(self):
"""Get the entire sub expression as a string with no spaces."""
return "".join(list(itertools.chain(*self._sub_expr)))
@property
def fmtd_sub_expr_str(self):
"""Get the entire sub expressions as a string with spaces."""
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')
@property
def dimensions_str(self):
"""Get all the dimensions as a single comma delimited string."""
return self._dimensions
@property
def operands_list(self):
"""Get this sub expression as a list."""
return [self]
@property
def func(self):
"""Get the function as it appears in the orig expression."""
return self._func
@property
def normalized_func(self):
"""Get the function upper-cased."""
return self._func.upper()
@property
def metric_name(self):
"""Get the metric name as it appears in the orig expression."""
return self._metric_name
@property
def normalized_metric_name(self):
"""Get the metric name lower-cased."""
return self._metric_name.lower()
@property
def dimensions(self):
"""Get the dimensions."""
return self._dimensions
@property
def dimensions_as_list(self):
"""Get the dimensions as a list."""
if self._dimensions:
return self._dimensions.split(",")
else:
return []
@property
def operator(self):
"""Get the operator."""
return self._operator
@property
def threshold(self):
"""Get the threshold value."""
return self._threshold
@property
def period(self):
"""Get the period. Default is 60 seconds."""
if self._period:
return self._period
else:
return u'60'
@property
def periods(self):
"""Get the periods. Default is 1."""
if self._periods:
return self._periods
else:
return u'1'
@property
def normalized_operator(self):
"""Get the operator as one of LT, GT, LTE, or GTE."""
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"
@property
def id(self):
"""Get the id used to identify this sub expression in the repo."""
return self._id
@id.setter
def id(self, id):
"""Set the d used to identify this sub expression in the repo."""
self._id = id
class BinaryOp(object):
def __init__(self, tokens):
self.op = tokens[0][1]
self.operands = tokens[0][0::2]
@property
def operands_list(self):
return ([sub_operand for operand in self.operands for sub_operand in
operand.operands_list])
class AndSubExpr(BinaryOp):
"""Expand later as needed."""
pass
class OrSubExpr(BinaryOp):
"""Expand later as needed."""
pass
COMMA = pyparsing.Literal(",")
LPAREN = pyparsing.Literal("(")
RPAREN = pyparsing.Literal(")")
EQUAL = pyparsing.Literal("=")
LBRACE = pyparsing.Literal("{")
RBRACE = pyparsing.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 + pyparsing.alphanums + ".-_#!$%&'*+/:;?@[\\]^`|~"))
metric_name = (
pyparsing.Word(valid_identifier_chars, min=1, max=255)("metric_name"))
dimension_name = pyparsing.Word(valid_identifier_chars, min=1, max=255)
dimension_value = pyparsing.Word(valid_identifier_chars, min=1, max=255)
integer_number = pyparsing.Word(pyparsing.nums)
decimal_number = pyparsing.Word(pyparsing.nums + ".")
max = pyparsing.CaselessLiteral("max")
min = pyparsing.CaselessLiteral("min")
avg = pyparsing.CaselessLiteral("avg")
count = pyparsing.CaselessLiteral("count")
sum = pyparsing.CaselessLiteral("sum")
func = (max | min | avg | count | sum)("func")
less_than_op = (
(pyparsing.CaselessLiteral("<") | pyparsing.CaselessLiteral("lt")))
less_than_eq_op = (
(pyparsing.CaselessLiteral("<=") | pyparsing.CaselessLiteral("lte")))
greater_than_op = (
(pyparsing.CaselessLiteral(">") | pyparsing.CaselessLiteral("gt")))
greater_than_eq_op = (
(pyparsing.CaselessLiteral(">=") | pyparsing.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 = pyparsing.CaselessLiteral("and") | pyparsing.CaselessLiteral("&&")
OR = pyparsing.CaselessLiteral("or") | pyparsing.CaselessLiteral("||")
logical_op = (AND | OR)("logical_op")
times = pyparsing.CaselessLiteral("times")
dimension = pyparsing.Group(dimension_name + EQUAL + dimension_value)
# Cannot have any whitespace after the comma delimiter.
dimension_list = pyparsing.Group(pyparsing.Optional(
LBRACE + pyparsing.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 = pyparsing.Forward()
sub_expression = (func + LPAREN + metric + pyparsing.Optional(
COMMA + period) + RPAREN + relational_op + threshold + pyparsing.Optional(
times + periods) | LPAREN + expression + RPAREN)
sub_expression.setParseAction(SubExpr)
expression = (
pyparsing.operatorPrecedence(sub_expression,
[(AND, 2, pyparsing.opAssoc.LEFT, AndSubExpr),
(OR, 2, pyparsing.opAssoc.LEFT, OrSubExpr)]))
class AlarmExprParser(object):
def __init__(self, expr):
self._expr = expr
@property
def sub_expr_list(self):
# Remove all spaces before parsing. Simple, quick fix for whitespace
# issue with dimension list not allowing whitespace after comma.
parseResult = (expression + pyparsing.stringEnd).parseString(
self._expr.replace(' ', ''))
sub_expr_list = parseResult[0].operands_list
return sub_expr_list
def main():
"""Used for development and testing."""
expr0 = (
"max(-_.千幸福的笑脸{घोड़ा=馬, "
"dn2=dv2,千幸福的笑脸घ=千幸福的笑脸घ}) gte 100 "
"times 3 && "
"(min(ເຮືອນ{dn3=dv3,家=дом}) < 10 or sum(biz{dn5=dv5}) >9 9and "
"count(fizzle) lt 0 or count(baz) > 1)".decode('utf8'))
expr1 = ("max(foo{hostname=mini-mon,千=千}, 120) > 100 and (max(bar)>100 "
" or max(biz)>100)".decode('utf8'))
expr2 = "max(foo)>=100"
for expr in (expr0, expr1, expr2):
print ('orig expr: {}'.format(expr.encode('utf8')))
alarmExprParser = AlarmExprParser(expr)
sub_expr = alarmExprParser.sub_expr_list
for sub_expression in sub_expr:
print ('sub expr: {}'.format(
sub_expression.sub_expr_str.encode('utf8')))
print ('fmtd sub expr: {}'.format(
sub_expression.fmtd_sub_expr_str.encode('utf8')))
print ('sub_expr dimensions: {}'.format(
sub_expression.dimensions_str.encode('utf8')))
print ()
print ()
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,125 +0,0 @@
# Copyright 2013 IBM Corp
#
# Author: Tong Li <litong01@us.ibm.com>
#
# 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 StringIO
try:
import ujson as json
except ImportError:
import json
class MetricValidator(object):
"""middleware that validate the metric input stream.
This middleware checks if the input stream actually follows metric spec
and all the messages in the request has valid metric data. If the body
is valid json and compliant with the spec, then the request will forward
the request to the next in the pipeline, otherwise, it will reject the
request with response code of 400 or 406.
"""
def __init__(self, app, conf):
self.app = app
self.conf = conf
def _is_valid_metric(self, metric):
"""Validate a message
The external message format is
{
"name":"name1",
"dimensions":{
"key1":"value1",
"key2":"value2"
},
"timestamp":1405630174,
"value":1.0
}
Once this is validated, the message needs to be transformed into
the following internal format:
The current valid message format is as follows (interna):
{
"metric": {"something": "The metric as a JSON object"},
"meta": {
"tenantId": "the tenant ID acquired",
"region": "the region that the metric was submitted under",
},
"creation_time": "the time when the API received the metric",
}
"""
if (metric.get('name') and metric.get('dimensions') and
metric.get('timestamp') and metric.get('value')):
return True
else:
return False
def __call__(self, env, start_response):
# if request starts with /datapoints/, then let it go on.
# this login middle
if (env.get('PATH_INFO', '').startswith('/v2.0/metrics') and
env.get('REQUEST_METHOD', '') == 'POST'):
# We only check the requests which are posting against metrics
# endpoint
try:
body = env['wsgi.input'].read()
metrics = json.loads(body)
# Do business logic validation here.
is_valid = True
if isinstance(metrics, list):
for metric in metrics:
if not self._is_valid_metric(metric):
is_valid = False
break
else:
is_valid = self._is_valid_metric(metrics)
if is_valid:
# If the message is valid, then wrap it into this internal
# format. The tenantId should be available from the
# request since this should have been authenticated.
# ideally this transformation should be done somewhere
# else. For the sake of simplicity, do the simple one
# here to make the life a bit easier.
# TODO(HP) Add logic to get region id from request header
# HTTP_X_SERVICE_CATALOG, then find endpoints, then region
region_id = None
msg = {'metric': metrics,
'meta': {'tenantId': env.get('HTTP_X_PROJECT_ID'),
'region': region_id},
'creation_time': datetime.datetime.now()}
env['wsgi.input'] = StringIO.StringIO(json.dumps(msg))
return self.app(env, start_response)
except Exception:
pass
# It is either invalid or exceptioned out while parsing json
# we will send the request back with 400.
start_response("400 Bad Request", [], '')
return []
else:
# not a metric post request, move on.
return self.app(env, start_response)
def filter_factory(global_conf, **local_conf):
def validator_filter(app):
return MetricValidator(app, local_conf)
return validator_filter

View File

@ -1,52 +0,0 @@
# 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 voluptuous
from monasca.openstack.common import log
from monasca.v2.common.schemas import exceptions
LOG = log.getLogger(__name__)
alarm_definition_schema = {
voluptuous.Required('name'): voluptuous.All(voluptuous.Any(str, unicode),
voluptuous.Length(max=250)),
voluptuous.Required('expression'): voluptuous.All(
voluptuous.Any(str, unicode), voluptuous.Length(max=4096)),
voluptuous.Optional('description'): voluptuous.All(
voluptuous.Any(str, unicode), voluptuous.Length(max=250)),
voluptuous.Optional('severity'): voluptuous.All(
voluptuous.Any('low', 'medium', 'high', 'critical', 'LOW', "MEDIUM",
'HIGH', 'CRITICAL')),
voluptuous.Optional('match_by'): voluptuous.All(
voluptuous.Any([unicode], [str]), voluptuous.Length(max=255)),
voluptuous.Optional('ok_actions'): voluptuous.All(
voluptuous.Any([str], [unicode]), voluptuous.Length(max=400)),
voluptuous.Optional('alarm_actions'): voluptuous.All(
voluptuous.Any([str], [unicode]), voluptuous.Length(max=400)),
voluptuous.Optional('undetermined_actions'): voluptuous.All(
voluptuous.Any([str], [unicode]), voluptuous.Length(max=400)),
voluptuous.Optional('actions_enabled'): bool}
request_body_schema = voluptuous.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))

View File

@ -1,33 +0,0 @@
# 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 voluptuous
from monasca.openstack.common import log
from monasca.v2.common.schemas import exceptions
LOG = log.getLogger(__name__)
dimensions_schema = voluptuous.Schema({
voluptuous.All(voluptuous.Any(str, unicode),
voluptuous.Length(max=255)): voluptuous.All(
voluptuous.Any(str, unicode), voluptuous.Length(max=255))})
def validate(dimensions):
try:
dimensions_schema(dimensions)
except Exception as ex:
LOG.debug(ex)
raise exceptions.ValidationException(str(ex))

View File

@ -1,31 +0,0 @@
# 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 voluptuous
from monasca.openstack.common import log
from monasca.v2.common.schemas import exceptions
LOG = log.getLogger(__name__)
metric_name_schema = voluptuous.Schema(
voluptuous.All(voluptuous.Any(str, unicode), voluptuous.Length(max=64)))
def validate(name):
try:
metric_name_schema(name)
except Exception as ex:
LOG.debug(ex)
raise exceptions.ValidationException(str(ex))

View File

@ -1,40 +0,0 @@
# 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 voluptuous
from monasca.openstack.common import log
from monasca.v2.common.schemas import dimensions_schema
from monasca.v2.common.schemas import exceptions
from monasca.v2.common.schemas import metric_name_schema
LOG = log.getLogger(__name__)
metric_schema = {
voluptuous.Required('name'): metric_name_schema.metric_name_schema,
voluptuous.Optional('dimensions'): dimensions_schema.dimensions_schema,
voluptuous.Required('timestamp'): voluptuous.All(
voluptuous.Any(int, float), voluptuous.Range(min=0)),
voluptuous.Required('value'): voluptuous.Any(int, float)}
request_body_schema = voluptuous.Schema(
voluptuous.Any(metric_schema, [metric_schema]))
def validate(msg):
try:
request_body_schema(msg)
except Exception as ex:
LOG.debug(ex)
raise exceptions.ValidationException(str(ex))

View File

@ -1,41 +0,0 @@
# 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 voluptuous
from monasca.openstack.common import log
from monasca.v2.common.schemas import exceptions
LOG = log.getLogger(__name__)
notification_schema = {
voluptuous.Required('name'): voluptuous.Schema(
voluptuous.All(voluptuous.Any(str, unicode),
voluptuous.Length(max=250))),
voluptuous.Required('type'): voluptuous.Schema(
voluptuous.Any("EMAIL", "email", "WEBHOOK", "webhook",
"PAGERDUTY", "pagerduty")),
voluptuous.Required('address'): voluptuous.Schema(
voluptuous.All(voluptuous.Any(str, unicode),
voluptuous.Length(max=100)))}
request_body_schema = voluptuous.Schema(voluptuous.Any(notification_schema))
def validate(msg):
try:
request_body_schema(msg)
except Exception as ex:
LOG.debug(ex)
raise exceptions.ValidationException(str(ex))

View File

@ -1,687 +0,0 @@
# 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 re
import falcon
from oslo.config import cfg
import pyparsing
from monasca.api import alarm_definitions_api_v2
from monasca.common.repositories import exceptions
from monasca.common import resource_api
import monasca.expression_parser.alarm_expr_parser
from monasca.openstack.common import log
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 import alarming
from monasca.v2.reference import helpers
from monasca.v2.reference import resource
LOG = log.getLogger(__name__)
class AlarmDefinitions(alarm_definitions_api_v2.AlarmDefinitionsV2API,
alarming.Alarming):
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._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 = helpers.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 = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_201
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='get')
def do_get_alarm_definition(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
result = self._alarm_definition_show(tenant_id, id)
helpers.add_links_to_resource(result, re.sub('/' + id, '', req.uri))
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='put')
def do_put_alarm_definitions(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
alarm_definition = helpers.read_json_msg_body(req)
self._validate_alarm_definition(alarm_definition)
tenant_id = helpers.get_tenant_id(req)
# Mandatory positional args
name = get_query_alarm_definition_name(alarm_definition)
expression = get_query_alarm_definition_expression(alarm_definition)
actions_enabled = (
get_query_alarm_definition_actions_enabled(alarm_definition,
required=True))
# Validator makes actions_enabled optional. So, check it here.
if not actions_enabled:
raise falcon.HTTPBadRequest('Bad request', 'Missing '
'actions_enabled')
# Optional args
description = get_query_alarm_definition_description(alarm_definition,
return_none=True)
alarm_actions = get_query_alarm_definition_alarm_actions(
alarm_definition, return_none=True)
ok_actions = get_query_ok_actions(alarm_definition, return_none=True)
undetermined_actions = get_query_alarm_definition_undetermined_actions(
alarm_definition, return_none=True)
match_by = get_query_alarm_definition_match_by(alarm_definition,
return_none=True)
severity = get_query_alarm_definition_severity(alarm_definition,
return_none=True)
result = self._alarm_definition_update_or_patch(tenant_id,
id,
name,
expression,
actions_enabled,
description,
alarm_actions,
ok_actions,
undetermined_actions,
match_by,
severity,
patch=False)
helpers.add_links_to_resource(result, req.uri)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarm-definitions', method='get')
def do_get_alarm_definitions(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
name = helpers.get_query_name(req)
dimensions = helpers.get_query_dimensions(req)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._alarm_definition_list(tenant_id, name, dimensions,
req.uri, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='patch')
def do_patch_alarm_definitions(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
alarm_definition = helpers.read_json_msg_body(req)
tenant_id = helpers.get_tenant_id(req)
# Optional args
name = get_query_alarm_definition_name(alarm_definition,
return_none=True)
expression = get_query_alarm_definition_expression(alarm_definition,
return_none=True)
actions_enabled = (
get_query_alarm_definition_actions_enabled(alarm_definition,
return_none=True))
description = get_query_alarm_definition_description(alarm_definition,
return_none=True)
alarm_actions = get_query_alarm_definition_alarm_actions(
alarm_definition, return_none=True)
ok_actions = get_query_ok_actions(alarm_definition, return_none=True)
undetermined_actions = get_query_alarm_definition_undetermined_actions(
alarm_definition, return_none=True)
match_by = get_query_alarm_definition_match_by(alarm_definition,
return_none=True)
severity = get_query_alarm_definition_severity(alarm_definition,
return_none=True)
result = self._alarm_definition_update_or_patch(tenant_id,
id,
name,
expression,
actions_enabled,
description,
alarm_actions,
ok_actions,
undetermined_actions,
match_by,
severity,
patch=True)
helpers.add_links_to_resource(result, req.uri)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='delete')
def do_delete_alarm_definitions(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
self._alarm_definition_delete(tenant_id, id)
res.status = falcon.HTTP_204
@resource.resource_try_catch_block
def _alarm_definition_show(self, tenant_id, id):
alarm_definition_row = (
self._alarm_definitions_repo.get_alarm_definition(tenant_id, id))
return self._build_alarm_definition_show_result(alarm_definition_row)
def _build_alarm_definition_show_result(self, alarm_definition_row):
match_by = get_comma_separated_str_as_list(
alarm_definition_row['match_by'])
alarm_actions_list = get_comma_separated_str_as_list(
alarm_definition_row['alarm_actions'])
ok_actions_list = get_comma_separated_str_as_list(
alarm_definition_row['ok_actions'])
undetermined_actions_list = get_comma_separated_str_as_list(
alarm_definition_row['undetermined_actions'])
result = {
u'actions_enabled': alarm_definition_row['actions_enabled'] == 1,
u'alarm_actions': alarm_actions_list,
u'undetermined_actions': undetermined_actions_list,
u'ok_actions': ok_actions_list,
u'description': alarm_definition_row['description'].decode(
'utf8'),
u'expression': alarm_definition_row['expression'].decode('utf8'),
u'id': alarm_definition_row['id'].decode('utf8'),
u'match_by': match_by,
u'name': alarm_definition_row['name'].decode('utf8'),
u'severity': alarm_definition_row['severity'].decode(
'utf8').upper()}
return result
@resource.resource_try_catch_block
def _alarm_definition_delete(self, tenant_id, id):
sub_alarm_definition_rows = (
self._alarm_definitions_repo.get_sub_alarm_definitions(id))
alarm_metric_rows = self._alarm_definitions_repo.get_alarm_metrics(
tenant_id, id)
sub_alarm_rows = self._alarm_definitions_repo.get_sub_alarms(
tenant_id, id)
if not self._alarm_definitions_repo.delete_alarm_definition(
tenant_id, id):
raise falcon.HTTPNotFound
self._send_alarm_definition_deleted_event(id,
sub_alarm_definition_rows)
self._send_alarm_event(u'alarm-deleted', tenant_id, id,
alarm_metric_rows, sub_alarm_rows)
@resource.resource_try_catch_block
def _alarm_definition_list(self, tenant_id, name, dimensions, req_uri,
offset):
alarm_definition_rows = (
self._alarm_definitions_repo.get_alarm_definitions(tenant_id, name,
dimensions,
offset))
result = []
for alarm_definition_row in alarm_definition_rows:
match_by = get_comma_separated_str_as_list(
alarm_definition_row['match_by'])
alarm_actions_list = get_comma_separated_str_as_list(
alarm_definition_row['alarm_actions'])
ok_actions_list = get_comma_separated_str_as_list(
alarm_definition_row['ok_actions'])
undetermined_actions_list = get_comma_separated_str_as_list(
alarm_definition_row['undetermined_actions'])
ad = {u'id': alarm_definition_row['id'].decode('utf8'),
u'name': alarm_definition_row['name'].decode("utf8"),
u'description': alarm_definition_row['description'].decode(
'utf8') if alarm_definition_row['description'] else u'',
u'expression': alarm_definition_row['expression'].decode(
'utf8'), u'match_by': match_by,
u'severity': alarm_definition_row['severity'].decode(
'utf8').upper(),
u'actions_enabled':
alarm_definition_row['actions_enabled'] == 1,
u'alarm_actions': alarm_actions_list,
u'ok_actions': ok_actions_list,
u'undetermined_actions': undetermined_actions_list}
helpers.add_links_to_resource(ad, req_uri)
result.append(ad)
result = helpers.paginate(result, req_uri, offset)
return result
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 request', ex.message)
@resource.resource_try_catch_block
def _alarm_definition_update_or_patch(self, tenant_id,
id,
name,
expression,
actions_enabled,
description,
alarm_actions,
ok_actions,
undetermined_actions,
match_by,
severity,
patch):
if expression:
try:
sub_expr_list = (
monasca.expression_parser.alarm_expr_parser.
AlarmExprParser(expression).sub_expr_list)
except pyparsing.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('utf8'))
raise falcon.HTTPBadRequest(title, msg)
else:
sub_expr_list = None
alarm_def_row, sub_alarm_def_dicts = (
self._alarm_definitions_repo.update_or_patch_alarm_definition(
tenant_id,
id,
name,
expression,
sub_expr_list,
actions_enabled,
description,
alarm_actions,
ok_actions,
undetermined_actions,
match_by,
severity,
patch))
old_sub_alarm_def_event_dict = (
self._build_sub_alarm_def_update_dict(
sub_alarm_def_dicts['old']))
new_sub_alarm_def_event_dict = (
self._build_sub_alarm_def_update_dict(sub_alarm_def_dicts[
'new']))
changed_sub_alarm_def_event_dict = (
self._build_sub_alarm_def_update_dict(sub_alarm_def_dicts[
'changed']))
unchanged_sub_alarm_def_event_dict = (
self._build_sub_alarm_def_update_dict(sub_alarm_def_dicts[
'unchanged']))
alarm_def_event_dict = (
{u'tenantId': tenant_id,
u'alarmDefinitionId': id,
u'alarmName': name,
u'alarmDescription': description,
u'alarmExpression': expression,
u'severity': severity,
u'matchBy': match_by,
u'alarmActionsEnabled': actions_enabled,
u'oldAlarmSubExpressions': old_sub_alarm_def_event_dict,
u'changedSubExpressions': changed_sub_alarm_def_event_dict,
u'unchangedSubExpressions': unchanged_sub_alarm_def_event_dict,
u'newAlarmSubExpressions': new_sub_alarm_def_event_dict})
alarm_definition_updated_event = (
{u'alarm-definition-updated': alarm_def_event_dict})
self.send_event(self.events_message_queue,
alarm_definition_updated_event)
result = self._build_alarm_definition_show_result(alarm_def_row)
return result
def _build_sub_alarm_def_update_dict(self, sub_alarm_def_dict):
sub_alarm_def_update_dict = {}
for id, sub_alarm_def in sub_alarm_def_dict.items():
dimensions = {}
for name, value in sub_alarm_def.dimensions.items():
dimensions[u'uname'] = value
sub_alarm_def_update_dict[sub_alarm_def.id] = {}
sub_alarm_def_update_dict[sub_alarm_def.id][u'function'] = (
sub_alarm_def.function)
sub_alarm_def_update_dict[sub_alarm_def.id][
u'metricDefinition'] = (
{u'name': sub_alarm_def.metric_name,
u'dimensions': dimensions})
sub_alarm_def_update_dict[sub_alarm_def.id][u'operator'] = (
sub_alarm_def.operator)
sub_alarm_def_update_dict[sub_alarm_def.id][u'threshold'] = (
sub_alarm_def.threshold)
sub_alarm_def_update_dict[sub_alarm_def.id][u'period'] = (
sub_alarm_def.period)
sub_alarm_def_update_dict[sub_alarm_def.id][u'periods'] = (
sub_alarm_def.periods)
sub_alarm_def_update_dict[sub_alarm_def.id][u'expression'] = (
sub_alarm_def.expression)
return sub_alarm_def_update_dict
@resource.resource_try_catch_block
def _alarm_definition_create(self, tenant_id, name, expression,
description, severity, match_by,
alarm_actions, undetermined_actions,
ok_actions):
try:
sub_expr_list = (
monasca.expression_parser.alarm_expr_parser.
AlarmExprParser(expression).sub_expr_list)
except pyparsing.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('utf8'))
raise falcon.HTTPBadRequest(title, msg)
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, u'actions_enabled': u'true',
u'undetermined_actions': undetermined_actions,
u'expression': expression, u'id': alarm_definition_id,
u'name': name})
return result
def _send_alarm_definition_deleted_event(self, alarm_definition_id,
sub_alarm_definition_rows):
sub_alarm_definition_deleted_event_msg = {}
alarm_definition_deleted_event_msg = {u"alarm-definition-deleted": {
u"alarmDefinitionId": alarm_definition_id,
u'subAlarmMetricDefinitions':
sub_alarm_definition_deleted_event_msg}}
for sub_alarm_definition in sub_alarm_definition_rows:
sub_alarm_definition_deleted_event_msg[
sub_alarm_definition['id']] = {
u'name': sub_alarm_definition['metric_name']}
dimensions = {}
sub_alarm_definition_deleted_event_msg[sub_alarm_definition['id']][
u'dimensions'] = dimensions
if sub_alarm_definition['dimensions']:
for dimension in sub_alarm_definition['dimensions'].split(','):
parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
self.send_event(self.events_message_queue,
alarm_definition_deleted_event_msg)
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.normalized_func}
metric_definition = {u'name': sub_expr.normalized_metric_name}
sub_expr_event_msg[sub_expr.id][
u'metricDefinition'] = metric_definition
dimensions = {}
for dimension in sub_expr.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.normalized_operator
sub_expr_event_msg[sub_expr.id][u'threshold'] = sub_expr.threshold
sub_expr_event_msg[sub_expr.id][u'period'] = sub_expr.period
sub_expr_event_msg[sub_expr.id][u'periods'] = sub_expr.periods
sub_expr_event_msg[sub_expr.id][
u'expression'] = sub_expr.fmtd_sub_expr_str
alarm_definition_created_event_msg[u'alarm-definition-created'][
u'alarmSubExpressions'] = sub_expr_event_msg
self.send_event(self.events_message_queue,
alarm_definition_created_event_msg)
def get_query_alarm_definition_name(alarm_definition, return_none=False):
try:
if 'name' in alarm_definition:
name = alarm_definition['name']
return name
else:
if return_none:
return None
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,
return_none=False):
try:
if 'expression' in alarm_definition:
expression = alarm_definition['expression']
return expression
else:
if return_none:
return None
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,
return_none=False):
if 'description' in alarm_definition:
return alarm_definition['description']
else:
if return_none:
return None
else:
return ''
def get_query_alarm_definition_severity(alarm_definition, return_none=False):
if 'severity' in alarm_definition:
severity = alarm_definition['severity']
severity = severity.decode('utf8').upper()
if severity not in ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']:
raise falcon.HTTPBadRequest('Bad request', 'Invalid severity')
return severity
else:
if return_none:
return None
else:
return 'LOW'
def get_query_alarm_definition_match_by(alarm_definition, return_none=False):
if 'match_by' in alarm_definition:
match_by = alarm_definition['match_by']
return match_by
else:
if return_none:
return None
else:
return []
def get_query_alarm_definition_alarm_actions(alarm_definition,
return_none=False):
if 'alarm_actions' in alarm_definition:
alarm_actions = alarm_definition['alarm_actions']
return alarm_actions
else:
if return_none:
return None
else:
return []
def get_query_alarm_definition_undetermined_actions(alarm_definition,
return_none=False):
if 'undetermined_actions' in alarm_definition:
undetermined_actions = alarm_definition['undetermined_actions']
return undetermined_actions
else:
if return_none:
return None
else:
return []
def get_query_ok_actions(alarm_definition, return_none=False):
if 'ok_actions' in alarm_definition:
ok_actions = alarm_definition['ok_actions']
return ok_actions
else:
if return_none:
return None
else:
return []
def get_query_alarm_definition_actions_enabled(alarm_definition,
required=False,
return_none=False):
try:
if 'actions_enabled' in alarm_definition:
enabled_actions = alarm_definition['actions_enabled']
return enabled_actions
else:
if return_none:
return None
elif required:
raise Exception("Missing actions-enabled")
else:
return ''
except Exception as ex:
LOG.debug(ex)
raise falcon.HTTPBadRequest('Bad request', ex.message)
def get_comma_separated_str_as_list(comma_separated_str):
if not comma_separated_str:
return []
else:
return comma_separated_str.decode('utf8').split(',')

View File

@ -1,176 +0,0 @@
# 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 falcon
from oslo.config import cfg
from monasca.common.messaging import exceptions as message_queue_exceptions
from monasca.common import resource_api
import monasca.expression_parser.alarm_expr_parser
from monasca.openstack.common import log
from monasca.v2.reference import helpers
LOG = log.getLogger(__name__)
class Alarming(object):
"""Super class for Alarms and AlarmDefinitions.
Shared attributes and methods for classes Alarms and AlarmDefinitions.
"""
def __init__(self, global_conf):
super(Alarming, self).__init__()
self.events_message_queue = (
resource_api.init_driver('monasca.messaging',
cfg.CONF.messaging.driver,
(['events'])))
self.alarm_state_transitions_message_queue = (
resource_api.init_driver('monasca.messaging',
cfg.CONF.messaging.driver,
(['alarm-state-transitions'])))
def _send_alarm_transitioned_event(self, tenant_id, alarm_id,
alarm_definition_row,
alarm_metric_rows,
old_state, new_state):
metrics = []
alarm_transitioned_event_msg = {u'alarm-transitioned': {
u'tenantId': tenant_id,
u'alarmId': alarm_id,
u'alarmDefinitionId': alarm_definition_row['id'],
u'alarmName': alarm_definition_row['name'],
u'alarmDescription': alarm_definition_row['description'],
u'actionsEnabled': alarm_definition_row['actions_enabled'] == 1,
u'stateChangeReason': 'Alarm state updated via API',
u'severity': alarm_definition_row['severity'],
u'oldState': old_state,
u'newState': new_state,
u'metrics': metrics}
}
for alarm_metric_row in alarm_metric_rows:
metric = self._build_metric(alarm_metric_row)
metrics.append(metric)
self.send_event(self.alarm_state_transitions_message_queue,
alarm_transitioned_event_msg)
def _build_metric(self, alarm_metric_row):
dimensions = {}
metric = {u'name': alarm_metric_row['name'],
u'dimensions': dimensions}
for dimension in alarm_metric_row['dimensions'].split(','):
parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
return metric
def _send_alarm_event(self, event_type, tenant_id, alarm_definition_id,
alarm_metric_rows, sub_alarm_rows, extra_info=None):
if not alarm_metric_rows:
return
# Build a dict mapping alarm id -> list of sub alarms.
sub_alarm_dict = {}
for sub_alarm_row in sub_alarm_rows:
if sub_alarm_row['alarm_id'] in sub_alarm_dict:
sub_alarm_dict[sub_alarm_row['alarm_id']] += [sub_alarm_row]
else:
sub_alarm_dict[sub_alarm_row['alarm_id']] = [sub_alarm_row]
# Forward declaration.
alarm_event_msg = {}
prev_alarm_id = None
for alarm_metric_row in alarm_metric_rows:
if prev_alarm_id != alarm_metric_row['alarm_id']:
if prev_alarm_id is not None:
sub_alarms_event_msg = (
self._build_sub_alarm_event_msg(sub_alarm_dict,
prev_alarm_id))
alarm_event_msg[event_type][
u'subAlarms': sub_alarms_event_msg]
self.send_event(self.events_message_queue,
alarm_event_msg)
alarm_metrics_event_msg = []
alarm_event_msg = {event_type: {u'tenant_id': tenant_id,
u'alarmDefinitionId':
alarm_definition_id,
u'alarmId': alarm_metric_row[
'alarm_id'],
u'alarmMetrics':
alarm_metrics_event_msg}}
if extra_info:
alarm_event_msg[event_type].update(extra_info)
prev_alarm_id = alarm_metric_row['alarm_id']
metric = self._build_metric(alarm_metric_row)
alarm_metrics_event_msg.append(metric)
# Finish last alarm
sub_alarms_event_msg = self._build_sub_alarm_event_msg(sub_alarm_dict,
prev_alarm_id)
alarm_event_msg[event_type][u'subAlarms'] = sub_alarms_event_msg
self.send_event(self.events_message_queue,
alarm_event_msg)
def _build_sub_alarm_event_msg(self, sub_alarm_dict, alarm_id):
sub_alarms_event_msg = {}
if alarm_id not in sub_alarm_dict:
return sub_alarms_event_msg
for sub_alarm in sub_alarm_dict[alarm_id]:
# There's only one expr in a sub alarm, so just take the first.
sub_expr = (
monasca.expression_parser.alarm_expr_parser.AlarmExprParser(
sub_alarm['expression']).sub_expr_list[0])
dimensions = {}
sub_alarms_event_msg[sub_alarm['sub_alarm_id']] = {
u'function': sub_expr.normalized_func,
u'metricDefinition': {u'name': sub_expr.metric_name,
u'dimensions': dimensions},
u'operator': sub_expr.normalized_operator,
u'threshold': sub_expr.threshold, u'period': sub_expr.period,
u'periods': sub_expr.periods,
u'expression': sub_expr.fmtd_sub_expr_str}
for dimension in sub_expr.dimensions_as_list:
parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
return sub_alarms_event_msg
def send_event(self, message_queue, event_msg):
try:
message_queue.send_message(
helpers.dumpit_utf8(event_msg))
except message_queue_exceptions.MessageQueueException as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError(
'Message queue service unavailable'.encode('utf8'),
ex.message.encode('utf8'))

View File

@ -1,328 +0,0 @@
# 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 re
import falcon
from oslo.config import cfg
from monasca.api import alarms_api_v2
from monasca.common.repositories import exceptions
from monasca.common import resource_api
from monasca.openstack.common import log
from monasca.v2.reference.alarming import Alarming
from monasca.v2.reference import helpers
from monasca.v2.reference import resource
LOG = log.getLogger(__name__)
class Alarms(alarms_api_v2.AlarmsV2API, Alarming):
def __init__(self, global_conf):
try:
super(Alarms, 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._alarms_repo = resource_api.init_driver(
'monasca.repositories', cfg.CONF.repositories.alarms_driver)
self._metrics_repo = resource_api.init_driver(
'monasca.repositories', cfg.CONF.repositories.metrics_driver)
except Exception as ex:
LOG.exception(ex)
raise exceptions.RepositoryException(ex)
@resource_api.Restify('/v2.0/alarms/{id}', method='put')
def do_put_alarms(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
state = self._get_alarm_state(req)
self._alarm_update(tenant_id, id, state)
result = self._alarm_show(req.uri, tenant_id, id)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarms/{id}', method='patch')
def do_patch_alarms(self, req, res, id):
# Same logic as alarm_update
return self.do_put_alarms(req, res, id)
@resource_api.Restify('/v2.0/alarms/{id}', method='delete')
def do_delete_alarms(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
self._alarm_delete(tenant_id, id)
res.status = falcon.HTTP_204
@resource_api.Restify('/v2.0/alarms', method='get')
def do_get_alarms(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
query_parms = falcon.uri.parse_query_string(req.query_string)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._alarm_list(req.uri, tenant_id, query_parms, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarms/{id}', method='get')
def do_get_alarm_by_id(self, req, res, id):
# Necessary because falcon interprets 'state-history' as an
# alarm id, and this url masks '/v2.0/alarms/state-history'.
if id.lower() == 'state-history':
return self.do_get_alarms_state_history(req, res)
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
result = self._alarm_show(req.uri, tenant_id, id)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarms/state-history', method='get')
def do_get_alarms_state_history(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
start_timestamp = helpers.get_query_starttime_timestamp(req, False)
end_timestamp = helpers.get_query_endtime_timestamp(req, False)
query_parms = falcon.uri.parse_query_string(req.query_string)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._alarm_history_list(tenant_id, start_timestamp,
end_timestamp, query_parms,
req.uri, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/alarms/{id}/state-history', method='get')
def do_get_alarm_state_history(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._alarm_history(tenant_id, [id], req.uri, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource.resource_try_catch_block
def _alarm_update(self, tenant_id, id, new_state):
alarm_metric_rows = self._alarms_repo.get_alarm_metrics(id)
sub_alarm_rows = self._alarms_repo.get_sub_alarms(tenant_id, id)
old_state = self._alarms_repo.update_alarm(tenant_id, id, new_state)
# alarm_definition_id is the same for all rows.
alarm_definition_id = sub_alarm_rows[0]['alarm_definition_id']
state_info = {u'alarmState': new_state, u'oldAlarmState': old_state}
self._send_alarm_event(u'alarm-updated', tenant_id,
alarm_definition_id, alarm_metric_rows,
sub_alarm_rows, state_info)
if old_state != new_state:
try:
alarm_definition_row = self._alarms_repo.get_alarm_definition(
tenant_id, id)
except exceptions.DoesNotExistException:
# Alarm definition does not exist. May have been deleted
# in another transaction. In that case, all associated
# alarms were also deleted, so don't send transition events.
pass
else:
self._send_alarm_transitioned_event(tenant_id, id,
alarm_definition_row,
alarm_metric_rows,
old_state, new_state)
@resource.resource_try_catch_block
def _alarm_history_list(self, tenant_id, start_timestamp,
end_timestamp, query_parms, req_uri, offset):
# get_alarms expects 'metric_dimensions' for dimensions key.
if 'dimensions' in query_parms:
new_query_parms = {'metric_dimensions': query_parms['dimensions']}
else:
new_query_parms = {}
alarm_rows = self._alarms_repo.get_alarms(tenant_id, new_query_parms)
alarm_id_list = [alarm_row['alarm_id'] for alarm_row in alarm_rows]
result = self._metrics_repo.alarm_history(tenant_id, alarm_id_list,
offset,
start_timestamp,
end_timestamp)
return helpers.paginate(result, req_uri, offset)
@resource.resource_try_catch_block
def _alarm_history(self, tenant_id, alarm_id, req_uri, offset):
result = self._metrics_repo.alarm_history(tenant_id, alarm_id, offset)
return helpers.paginate(result, req_uri, offset)
@resource.resource_try_catch_block
def _alarm_delete(self, tenant_id, id):
alarm_metric_rows = self._alarms_repo.get_alarm_metrics(id)
sub_alarm_rows = self._alarms_repo.get_sub_alarms(tenant_id, id)
self._alarms_repo.delete_alarm(tenant_id, id)
# alarm_definition_id is the same for all rows.
alarm_definition_id = sub_alarm_rows[0]['alarm_definition_id']
self._send_alarm_event(u'alarm-deleted', tenant_id,
alarm_definition_id, alarm_metric_rows,
sub_alarm_rows)
@resource.resource_try_catch_block
def _alarm_show(self, req_uri, tenant_id, id):
alarm_rows = self._alarms_repo.get_alarm(tenant_id, id)
first_row = True
for alarm_row in alarm_rows:
if first_row:
ad = {u'id': alarm_row['alarm_definition_id'],
u'name': alarm_row['alarm_definition_name'],
u'severity': alarm_row['severity'], }
helpers.add_links_to_resource(ad,
re.sub('alarms',
'alarm-definitions',
req_uri),
rel=None)
metrics = []
alarm = {u'id': alarm_row['alarm_id'], u'metrics': metrics,
u'state': alarm_row['state'],
u'alarm_definition': ad}
helpers.add_links_to_resource(alarm, req_uri)
first_row = False
dimensions = {}
metric = {u'name': alarm_row['metric_name'],
u'dimensions': dimensions}
if alarm_row['metric_dimensions']:
for dimension in alarm_row['metric_dimensions'].split(','):
parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
metrics.append(metric)
return alarm
@resource.resource_try_catch_block
def _alarm_list(self, req_uri, tenant_id, query_parms, offset):
alarm_rows = self._alarms_repo.get_alarms(tenant_id, query_parms,
offset)
result = []
if not alarm_rows:
return result
# Forward declaration
alarm = {}
prev_alarm_id = None
for alarm_row in alarm_rows:
if prev_alarm_id != alarm_row['alarm_id']:
if prev_alarm_id is not None:
result.append(alarm)
ad = {u'id': alarm_row['alarm_definition_id'],
u'name': alarm_row['alarm_definition_name'],
u'severity': alarm_row['severity'], }
helpers.add_links_to_resource(ad,
re.sub('alarms',
'alarm-definitions',
req_uri),
rel=None)
metrics = []
alarm = {u'id': alarm_row['alarm_id'], u'metrics': metrics,
u'state': alarm_row['state'],
u'alarm_definition': ad}
helpers.add_links_to_resource(alarm, req_uri)
prev_alarm_id = alarm_row['alarm_id']
dimensions = {}
metric = {u'name': alarm_row['metric_name'],
u'dimensions': dimensions}
if alarm_row['metric_dimensions']:
for dimension in alarm_row['metric_dimensions'].split(','):
parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
metrics.append(metric)
result.append(alarm)
return helpers.paginate(result, req_uri, offset)
def _get_alarm_state(self, req):
json_msg = helpers.read_http_resource(req)
if 'state' in json_msg:
state = json_msg['state'].upper()
if state not in ['OK', 'ALARM', 'UNDETERMINED']:
raise falcon.HTTPBadRequest('Bad request', 'Invalid state')
return state
else:
raise falcon.HTTPBadRequest('Bad request', 'Missing state')

View File

@ -1,230 +0,0 @@
# 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
import falcon
from oslo.config import cfg
from monasca.api import monasca_api_v2
from monasca.common.messaging import exceptions as message_queue_exceptions
from monasca.common.messaging.message_formats import metrics_transform_factory
from monasca.common import resource_api
from monasca.openstack.common import log
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.v2.common import utils
from monasca.v2.reference import helpers
LOG = log.getLogger(__name__)
class Metrics(monasca_api_v2.V2API):
def __init__(self, global_conf):
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
:param metrics: A metric object or array of metrics objects.
:raises falcon.HTTPBadRequest
"""
try:
schemas_metrics.validate(metrics)
except schemas_exceptions.ValidationException as ex:
LOG.debug(ex)
raise falcon.HTTPBadRequest('Bad request', ex.message)
def _send_metrics(self, metrics):
"""Send the metrics using the message queue.
:param metrics: A metric object or array of metrics objects.
:raises: falcon.HTTPServiceUnavailable
"""
def _send_metric(metric):
try:
str_msg = json.dumps(metric, default=utils.date_handler)
self._message_queue.send_message(str_msg)
except message_queue_exceptions.MessageQueueException as ex:
LOG.exception(ex)
raise falcon.HTTPServiceUnavailable('Service unavailable',
ex.message, 60)
if isinstance(metrics, list):
for metric in metrics:
_send_metric(metric)
else:
_send_metric(metrics)
def _list_metrics(self, tenant_id, name, dimensions, req_uri, offset):
"""Query the metric repo for the metrics, format them and return them.
:param tenant_id:
:param name:
:param dimensions:
:raises falcon.HTTPServiceUnavailable
"""
try:
result = self._metrics_repo.list_metrics(tenant_id,
self._region,
name,
dimensions, offset)
return helpers.paginate(result, req_uri, offset)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPServiceUnavailable('Service unavailable',
ex.message, 60)
def _measurement_list(self, tenant_id, name, dimensions, start_timestamp,
end_timestamp, req_uri, offset):
try:
result = self._metrics_repo.measurement_list(tenant_id,
self._region,
name,
dimensions,
start_timestamp,
end_timestamp,
offset)
if offset is not None:
paginated_result = []
for measurement in result:
paginated_result.append(
helpers.paginate_measurement(measurement,
req_uri, offset))
result = {u'links': [{u'rel': u'self',
u'href': req_uri.decode('utf8')}],
u'elements': paginated_result}
return result
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPServiceUnavailable('Service unavailable',
ex.message, 60)
def _metric_statistics(self, tenant_id, name, dimensions, start_timestamp,
end_timestamp, statistics, period):
try:
return self._metrics_repo.metrics_statistics(tenant_id,
self._region,
name,
dimensions,
start_timestamp,
end_timestamp,
statistics, period)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPServiceUnavailable('Service unavailable',
ex.message, 60)
@resource_api.Restify('/v2.0/metrics/', method='post')
def do_post_metrics(self, req, res):
helpers.validate_json_content_type(req)
helpers.validate_authorization(req,
self._post_metrics_authorized_roles)
metrics = helpers.read_http_resource(req)
self._validate_metrics(metrics)
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)
res.status = falcon.HTTP_204
@resource_api.Restify('/v2.0/metrics/', method='get')
def do_get_metrics(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
name = helpers.get_query_name(req)
helpers.validate_query_name(name)
dimensions = helpers.get_query_dimensions(req)
helpers.validate_query_dimensions(dimensions)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._list_metrics(tenant_id, name, dimensions,
req.uri, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/metrics/measurements', method='get')
def do_get_measurements(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
name = helpers.get_query_name(req)
helpers.validate_query_name(name)
dimensions = helpers.get_query_dimensions(req)
helpers.validate_query_dimensions(dimensions)
start_timestamp = helpers.get_query_starttime_timestamp(req)
end_timestamp = helpers.get_query_endtime_timestamp(req, False)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._measurement_list(tenant_id, name, dimensions,
start_timestamp, end_timestamp,
req.uri, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/metrics/statistics', method='get')
def do_get_statistics(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
name = helpers.get_query_name(req)
helpers.validate_query_name(name)
dimensions = helpers.get_query_dimensions(req)
helpers.validate_query_dimensions(dimensions)
start_timestamp = helpers.get_query_starttime_timestamp(req)
end_timestamp = helpers.get_query_endtime_timestamp(req, False)
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)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200

View File

@ -1,185 +0,0 @@
# 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 falcon
from oslo.config import cfg
from monasca.api import monasca_notifications_api_v2
from monasca.common import resource_api
from monasca.openstack.common import log
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.reference import helpers
from monasca.v2.reference import resource
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)
def _validate_notification(self, notification):
"""Validates the notification
:param notification: An event object.
:raises falcon.HTTPBadRequest
"""
try:
schemas_notifications.validate(notification)
except schemas_exceptions.ValidationException as ex:
LOG.debug(ex)
raise falcon.HTTPBadRequest('Bad request', ex.message)
@resource.resource_try_catch_block
def _create_notification(self, tenant_id, notification, uri):
name = notification['name'].decode('utf8')
notification_type = notification['type'].upper().decode('utf8')
address = notification['address'].decode('utf8')
notification_id = self._notifications_repo.create_notification(
tenant_id,
name,
notification_type,
address)
return self._create_notification_response(notification_id,
name,
notification_type,
address,
uri)
@resource.resource_try_catch_block
def _update_notification(self, id, tenant_id, notification, uri):
name = notification['name'].decode('utf8')
notification_type = notification['type'].upper().decode('utf8')
address = notification['address'].decode('utf8')
self._notifications_repo.update_notification(id, tenant_id, name,
notification_type,
address)
return self._create_notification_response(id,
name,
notification_type,
address,
uri)
def _create_notification_response(self, id, name, type,
address, uri):
response = {
'id': id,
'name': name,
'type': type,
'address': address
}
return helpers.add_links_to_resource(response, uri)
@resource.resource_try_catch_block
def _list_notifications(self, tenant_id, uri, offset):
rows = self._notifications_repo.list_notifications(tenant_id, offset)
result = [self._build_notification_result(row,
uri) for row in rows]
return helpers.paginate(result, uri, offset)
@resource.resource_try_catch_block
def _list_notification(self, tenant_id, notification_id, uri):
row = self._notifications_repo.list_notification(
tenant_id,
notification_id)
return self._build_notification_result(row, uri)
def _build_notification_result(self, notification_row, uri):
result = {
u'id': notification_row['id'],
u'name': notification_row['name'],
u'type': notification_row['type'],
u'address': notification_row['address']
}
helpers.add_links_to_resource(result, uri)
return result
@resource.resource_try_catch_block
def _delete_notification(self, tenant_id, notification_id):
self._notifications_repo.delete_notification(tenant_id,
notification_id)
@resource_api.Restify('/v2.0/notification-methods', method='post')
def do_post_notification_methods(self, req, res):
helpers.validate_json_content_type(req)
helpers.validate_authorization(req, self._default_authorized_roles)
notification = helpers.read_http_resource(req)
self._validate_notification(notification)
tenant_id = helpers.get_tenant_id(req)
result = self._create_notification(tenant_id, notification, req.uri)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_201
@resource_api.Restify('/v2.0/notification-methods', method='get')
def do_get_notification_methods(self, req, res):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
offset = helpers.normalize_offset(helpers.get_query_param(req,
'offset'))
result = self._list_notifications(tenant_id, req.uri, offset)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/notification-methods/{id}', method='delete')
def do_delete_notification_methods(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
self._delete_notification(tenant_id, id)
res.status = falcon.HTTP_204
@resource_api.Restify('/v2.0/notification-methods/{id}', method='get')
def do_get_notification_method(self, req, res, id):
helpers.validate_authorization(req, self._default_authorized_roles)
tenant_id = helpers.get_tenant_id(req)
result = self._list_notification(tenant_id, id, req.uri)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200
@resource_api.Restify('/v2.0/notification-methods/{id}', method='put')
def do_put_notification_methods(self, req, res, id):
helpers.validate_json_content_type(req)
helpers.validate_authorization(req, self._default_authorized_roles)
notification = helpers.read_http_resource(req)
self._validate_notification(notification)
tenant_id = helpers.get_tenant_id(req)
result = self._update_notification(id, tenant_id, notification,
req.uri)
res.body = helpers.dumpit_utf8(result)
res.status = falcon.HTTP_200