Merge "Add alarm delete resource"

This commit is contained in:
Jenkins 2014-11-13 16:37:18 +00:00 committed by Gerrit Code Review
commit 000056f174
9 changed files with 436 additions and 356 deletions

View File

@ -20,6 +20,9 @@ LOG = log.getLogger(__name__)
class AlarmDefinitionsV2API(object): class AlarmDefinitionsV2API(object):
def __init__(self, global_conf): def __init__(self, global_conf):
super(AlarmDefinitionsV2API, self).__init__(global_conf)
LOG.debug('initializing AlarmDefinitionsV2API!') LOG.debug('initializing AlarmDefinitionsV2API!')
self.global_conf = global_conf self.global_conf = global_conf

View File

@ -20,6 +20,9 @@ LOG = log.getLogger(__name__)
class AlarmsV2API(object): class AlarmsV2API(object):
def __init__(self, global_conf): def __init__(self, global_conf):
super(AlarmsV2API, self).__init__(global_conf)
LOG.debug('initializing AlarmsV2API!') LOG.debug('initializing AlarmsV2API!')
self.global_conf = global_conf self.global_conf = global_conf

View File

@ -16,7 +16,7 @@ import datetime
from monasca.common.repositories import alarm_definitions_repository from monasca.common.repositories import alarm_definitions_repository
from monasca.common.repositories.exceptions import DoesNotExistException from monasca.common.repositories.exceptions import DoesNotExistException
from monasca.common.repositories.mysql.mysql_repository import MySQLRepository from monasca.common.repositories.mysql.mysql_repository import MySQLRepository
from monasca.common.repositories.mysql.mysql_repository import try_catch_block from monasca.common.repositories.mysql.mysql_repository import mysql_try_catch_block
from monasca.openstack.common import log from monasca.openstack.common import log
from monasca.openstack.common import uuidutils from monasca.openstack.common import uuidutils
from monasca.common.repositories import exceptions from monasca.common.repositories import exceptions
@ -56,7 +56,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
super(AlarmDefinitionsRepository, self).__init__() super(AlarmDefinitionsRepository, self).__init__()
@try_catch_block @mysql_try_catch_block
def get_alarm_definition(self, tenant_id, id): def get_alarm_definition(self, tenant_id, id):
parms = [tenant_id, id] parms = [tenant_id, id]
@ -74,7 +74,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
else: else:
raise DoesNotExistException raise DoesNotExistException
@try_catch_block @mysql_try_catch_block
def get_alarm_definitions(self, tenant_id, name, dimensions): def get_alarm_definitions(self, tenant_id, name, dimensions):
parms = [tenant_id] parms = [tenant_id]
@ -114,7 +114,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
return self._execute_query(query, parms) return self._execute_query(query, parms)
@try_catch_block @mysql_try_catch_block
def get_sub_alarms(self, tenant_id, alarm_definition_id): def get_sub_alarms(self, tenant_id, alarm_definition_id):
parms = [tenant_id, alarm_definition_id] parms = [tenant_id, alarm_definition_id]
@ -131,7 +131,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
return self._execute_query(query, parms) return self._execute_query(query, parms)
@try_catch_block @mysql_try_catch_block
def get_alarm_metrics(self, tenant_id, alarm_definition_id): def get_alarm_metrics(self, tenant_id, alarm_definition_id):
parms = [tenant_id, alarm_definition_id] parms = [tenant_id, alarm_definition_id]
@ -156,7 +156,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
return self._execute_query(query, parms) return self._execute_query(query, parms)
@try_catch_block @mysql_try_catch_block
def delete_alarm_definition(self, tenant_id, alarm_definition_id): def delete_alarm_definition(self, tenant_id, alarm_definition_id):
"""Soft delete the alarm definition. """Soft delete the alarm definition.
@ -187,7 +187,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
return True return True
@try_catch_block @mysql_try_catch_block
def get_sub_alarm_definitions(self, alarm_definition_id): def get_sub_alarm_definitions(self, alarm_definition_id):
parms = [alarm_definition_id] parms = [alarm_definition_id]
@ -206,7 +206,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
return self._execute_query(query, parms) return self._execute_query(query, parms)
@try_catch_block @mysql_try_catch_block
def create_alarm_definition(self, tenant_id, name, expression, def create_alarm_definition(self, tenant_id, name, expression,
sub_expr_list, description, severity, match_by, sub_expr_list, description, severity, match_by,
alarm_actions, undetermined_actions, alarm_actions, undetermined_actions,

View File

@ -15,7 +15,7 @@ from monasca.common.repositories.exceptions import DoesNotExistException
from monasca.common.repositories import alarms_repository from monasca.common.repositories import alarms_repository
from monasca.common.repositories.mysql.mysql_repository import MySQLRepository from monasca.common.repositories.mysql.mysql_repository import MySQLRepository
from monasca.common.repositories.mysql.mysql_repository import try_catch_block from monasca.common.repositories.mysql.mysql_repository import mysql_try_catch_block
from monasca.openstack.common import log from monasca.openstack.common import log
@ -47,7 +47,73 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
super(AlarmsRepository, self).__init__() super(AlarmsRepository, self).__init__()
@try_catch_block @mysql_try_catch_block
def get_alarm_metrics(self, alarm_id):
parms = [alarm_id]
query = """select distinct a.id as alarm_id, md.name,
mdg.dimensions
from alarm as a
inner join alarm_metric as am on am.alarm_id = a.id
inner join metric_definition_dimensions as mdd
on mdd.id = am.metric_definition_dimensions_id
inner join metric_definition as md
on md.id = mdd.metric_definition_id
left join (select dimension_set_id,
group_concat(name, '=', value) as dimensions
from metric_dimension group by dimension_set_id) as mdg
on mdg.dimension_set_id = mdd.metric_dimension_set_id
where a.id = ?
order by a.id
"""
return self._execute_query(query, parms)
@mysql_try_catch_block
def get_sub_alarms(self, tenant_id, alarm_id):
parms = [tenant_id, alarm_id]
query = """select distinct sa.id as sub_alarm_id, sa.alarm_id,
sa.expression, ad.id as alarm_definition_id
from sub_alarm as sa
inner join alarm as a
on a.id = sa.alarm_id
inner join alarm_definition as ad
on ad.id = a.alarm_definition_id
where ad.tenant_id = ? and a.id = ?
"""
return self._execute_query(query, parms)
@mysql_try_catch_block
def delete_alarm(self, tenant_id, id):
parms = [tenant_id, id]
query = """
delete alarm.*
from alarm
join
(select distinct a.id
from alarm as a
inner join alarm_definition as ad
on ad.id = a.alarm_definition_id
where ad.tenant_id = ? and a.id = ?) as b
on b.id = alarm.id
"""
cnxn, cursor = self._get_cnxn_cursor_tuple()
cursor.execute(query, parms)
if cursor.rowcount < 1:
raise DoesNotExistException
self._commit_close_cnxn(cnxn)
@mysql_try_catch_block
def get_alarm(self, tenant_id, id): def get_alarm(self, tenant_id, id):
parms = [tenant_id, id] parms = [tenant_id, id]
@ -66,7 +132,7 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
else: else:
return rows return rows
@try_catch_block @mysql_try_catch_block
def get_alarms(self, tenant_id, query_parms): def get_alarms(self, tenant_id, query_parms):
parms = [tenant_id] parms = [tenant_id]

View File

@ -79,7 +79,7 @@ class MySQLRepository(object):
return rows return rows
def try_catch_block(fun): def mysql_try_catch_block(fun):
def try_it(*args, **kwargs): def try_it(*args, **kwargs):

View File

@ -13,8 +13,6 @@
# under the License. # under the License.
import json import json
import re import re
from monasca.common.repositories.exceptions import DoesNotExistException
from pyparsing import ParseException from pyparsing import ParseException
import falcon import falcon
from oslo.config import cfg from oslo.config import cfg
@ -25,17 +23,17 @@ from monasca.api.alarm_definitions_api_v2 import AlarmDefinitionsV2API
from monasca.expression_parser.alarm_expr_parser import AlarmExprParser from monasca.expression_parser.alarm_expr_parser import AlarmExprParser
from monasca.openstack.common import log from monasca.openstack.common import log
from monasca.v2.reference import helpers from monasca.v2.reference import helpers
from monasca.v2.common.schemas import \ from monasca.v2.common.schemas import alarm_definition_request_body_schema as schema_alarms
alarm_definition_request_body_schema as schema_alarms
from monasca.v2.common.schemas import exceptions as schemas_exceptions from monasca.v2.common.schemas import exceptions as schemas_exceptions
from monasca.v2.reference.alarming import Alarming
from monasca.v2.reference.helpers import read_json_msg_body from monasca.v2.reference.helpers import read_json_msg_body
from monasca.common.messaging import exceptions as message_queue_exceptions from monasca.v2.reference.resource import resource_try_catch_block
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
class AlarmDefinitions(AlarmDefinitionsV2API): class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
def __init__(self, global_conf): def __init__(self, global_conf):
@ -53,11 +51,6 @@ class AlarmDefinitions(AlarmDefinitionsV2API):
cfg.CONF.security.default_authorized_roles + \ cfg.CONF.security.default_authorized_roles + \
cfg.CONF.security.agent_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( self._alarm_definitions_repo = resource_api.init_driver(
'monasca.repositories', 'monasca.repositories',
cfg.CONF.repositories.alarm_definitions_driver) cfg.CONF.repositories.alarm_definitions_driver)
@ -138,14 +131,70 @@ class AlarmDefinitions(AlarmDefinitionsV2API):
self._alarm_definition_delete(tenant_id, id) self._alarm_definition_delete(tenant_id, id)
res.status = falcon.HTTP_204 res.status = falcon.HTTP_204
@resource_try_catch_block
def _alarm_definition_show(self, tenant_id, id): def _alarm_definition_show(self, tenant_id, id):
try: alarm_definition_row = \
self._alarm_definitions_repo.get_alarm_definition(
tenant_id, id)
alarm_definition_row = \ match_by = get_comma_separated_str_as_list(
self._alarm_definitions_repo.get_alarm_definition( alarm_definition_row.match_by)
tenant_id, id)
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')}
return result
@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_deleted_event(tenant_id, id, alarm_metric_rows,
sub_alarm_rows)
@resource_try_catch_block
def _alarm_definition_list(self, tenant_id, name, dimensions, req_uri):
alarm_definition_rows = \
self._alarm_definitions_repo.get_alarm_definitions(
tenant_id, name, dimensions)
result = []
for alarm_definition_row in alarm_definition_rows:
match_by = get_comma_separated_str_as_list( match_by = get_comma_separated_str_as_list(
alarm_definition_row.match_by) alarm_definition_row.match_by)
@ -159,113 +208,25 @@ class AlarmDefinitions(AlarmDefinitionsV2API):
undetermined_actions_list = get_comma_separated_str_as_list( undetermined_actions_list = get_comma_separated_str_as_list(
alarm_definition_row.undetermined_actions) alarm_definition_row.undetermined_actions)
result = { ad = {u'id': alarm_definition_row.id.decode('utf8'),
u'actions_enabled': alarm_definition_row.actions_enabled == 1, u'name': alarm_definition_row.name.decode("utf8"),
u'alarm_actions': alarm_actions_list, u'description': alarm_definition_row.description.decode(
u'undetermined_actions': undetermined_actions_list, 'utf8'),
u'ok_actions': ok_actions_list, u'expression': alarm_definition_row.expression.decode(
u'description': alarm_definition_row.description.decode( 'utf8'), u'match_by': match_by,
'utf8'), u'severity': alarm_definition_row.severity.decode(
u'expression': alarm_definition_row.expression.decode('utf8'), 'utf8'),
u'id': alarm_definition_row.id.decode('utf8'), u'actions_enabled':
u'match_by': match_by, alarm_definition_row.actions_enabled == 1,
u'name': alarm_definition_row.name.decode('utf8'), u'alarm_actions': alarm_actions_list,
u'severity': alarm_definition_row.severity.decode('utf8')} u'ok_actions': ok_actions_list,
u'undetermined_actions': undetermined_actions_list}
return result helpers.add_links_to_resource(ad, req_uri)
result.append(ad)
return result
except DoesNotExistException:
raise falcon.HTTPNotFound()
except exceptions.RepositoryException as ex:
LOG.exception(ex)
msg = "".join(ex.message.args)
raise falcon.HTTPInternalServerError('Service unavailable', msg)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex)
def _alarm_definition_delete(self, tenant_id, id):
try:
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_deleted_event(tenant_id, id, alarm_metric_rows,
sub_alarm_rows)
except exceptions.RepositoryException as ex:
LOG.exception(ex)
msg = "".join(ex.message.args)
raise falcon.HTTPInternalServerError('Service unavailable', msg)
except falcon.HTTPNotFound:
raise
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex)
def _alarm_definition_list(self, tenant_id, name, dimensions, req_uri):
try:
alarm_definition_rows = \
self._alarm_definitions_repo.get_alarm_definitions(
tenant_id, name, dimensions)
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'),
u'expression': alarm_definition_row.expression.decode(
'utf8'), u'match_by': match_by,
u'severity': alarm_definition_row.severity.decode(
'utf8'),
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)
return result
except exceptions.RepositoryException as ex:
LOG.exception(ex)
msg = "".join(ex.message.args)
raise falcon.HTTPInternalServerError('Service unavailable', msg)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex)
def _validate_alarm_definition(self, alarm_definition): def _validate_alarm_definition(self, alarm_definition):
@ -275,125 +236,42 @@ class AlarmDefinitions(AlarmDefinitionsV2API):
LOG.debug(ex) LOG.debug(ex)
raise falcon.HTTPBadRequest('Bad request', ex.message) raise falcon.HTTPBadRequest('Bad request', ex.message)
@resource_try_catch_block
def _alarm_definition_create(self, tenant_id, name, expression, def _alarm_definition_create(self, tenant_id, name, expression,
description, severity, match_by, description, severity, match_by,
alarm_actions, undetermined_actions, alarm_actions, undetermined_actions,
ok_actions): ok_actions):
try: try:
sub_expr_list = AlarmExprParser(expression).sub_expr_list sub_expr_list = AlarmExprParser(expression).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: except ParseException as ex:
LOG.exception(ex) LOG.exception(ex)
title = "Invalid alarm expression".encode('utf8') title = "Invalid alarm expression".encode('utf8')
msg = "parser failed on expression '{}' at column {}".format( msg = "parser failed on expression '{}' at column {}".format(
expression.encode('utf8'), str(ex.column).encode('utf')) expression.encode('utf8'), str(ex.column).encode('utf'))
raise falcon.HTTPBadRequest(title, msg) raise falcon.HTTPBadRequest(title, msg)
except exceptions.RepositoryException as ex:
LOG.exception(ex)
msg = "".join(ex.message.args)
raise falcon.HTTPInternalServerError('Service unavailable', msg)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex)
def _send_alarm_deleted_event(self, tenant_id, alarm_definition_id, alarm_definition_id = \
alarm_metric_rows, sub_alarm_rows): self._alarm_definitions_repo.create_alarm_definition(
tenant_id, name, expression, sub_expr_list, description,
severity, match_by, alarm_actions, undetermined_actions,
ok_actions)
if not alarm_metric_rows: self._send_alarm_definition_created_event(tenant_id,
return 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})
# Build a dict mapping alarm id -> list of sub alarms. return result
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]
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_deleted_event_msg = \
self._build_sub_alarm_deleted_event_msg(
sub_alarm_dict, prev_alarm_id)
alarm_deleted_event_msg[u'alarm-delete'][
u'subAlarms': sub_alarms_deleted_event_msg]
self._send_event(alarm_deleted_event_msg)
alarm_metrics_event_msg = []
alarm_deleted_event_msg = {
u'alarm-deleted': {u'tenant_id': tenant_id,
u'alarmDefinitionId':
alarm_definition_id,
u'alarmId': alarm_metric_row.alarm_id,
u'alarmMetrics':
alarm_metrics_event_msg}}
prev_alarm_id = alarm_metric_row.alarm_id
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]
alarm_metrics_event_msg.append(metric)
# Finish last alarm
sub_alarms_deleted_event_msg = self._build_sub_alarm_deleted_event_msg(
sub_alarm_dict, prev_alarm_id)
alarm_deleted_event_msg[u'alarm-deleted'][
u'subAlarms'] = sub_alarms_deleted_event_msg
self._send_event(alarm_deleted_event_msg)
def _build_sub_alarm_deleted_event_msg(self, sub_alarm_dict, alarm_id):
sub_alarms_deleted_event_msg = {}
if alarm_id not in sub_alarm_dict:
return sub_alarms_deleted_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 = AlarmExprParser(sub_alarm.expression).sub_expr_list[0]
dimensions = {}
sub_alarms_deleted_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_deleted_event_msg
def _send_alarm_definition_deleted_event(self, alarm_definition_id, def _send_alarm_definition_deleted_event(self, alarm_definition_id,
sub_alarm_definition_rows): sub_alarm_definition_rows):
@ -456,17 +334,6 @@ class AlarmDefinitions(AlarmDefinitionsV2API):
self._send_event(alarm_definition_created_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): def get_query_alarm_definition_name(alarm_definition):
try: try:
if 'name' in alarm_definition: if 'name' in alarm_definition:

View File

@ -0,0 +1,127 @@
# 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.common import resource_api
from monasca.expression_parser.alarm_expr_parser import AlarmExprParser
from monasca.openstack.common import log
from monasca.common.messaging import exceptions as message_queue_exceptions
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._message_queue \
= resource_api.init_driver('monasca.messaging',
cfg.CONF.messaging.driver,
(['events']))
def _send_alarm_deleted_event(self, tenant_id, alarm_definition_id,
alarm_metric_rows, sub_alarm_rows):
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]
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_deleted_event_msg = \
self._build_sub_alarm_deleted_event_msg(
sub_alarm_dict, prev_alarm_id)
alarm_deleted_event_msg[u'alarm-delete'][
u'subAlarms': sub_alarms_deleted_event_msg]
self._send_event(alarm_deleted_event_msg)
alarm_metrics_event_msg = []
alarm_deleted_event_msg = {
u'alarm-deleted': {u'tenant_id': tenant_id,
u'alarmDefinitionId':
alarm_definition_id,
u'alarmId': alarm_metric_row.alarm_id,
u'alarmMetrics':
alarm_metrics_event_msg}}
prev_alarm_id = alarm_metric_row.alarm_id
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]
alarm_metrics_event_msg.append(metric)
# Finish last alarm
sub_alarms_deleted_event_msg = self._build_sub_alarm_deleted_event_msg(
sub_alarm_dict, prev_alarm_id)
alarm_deleted_event_msg[u'alarm-deleted'][
u'subAlarms'] = sub_alarms_deleted_event_msg
self._send_event(alarm_deleted_event_msg)
def _build_sub_alarm_deleted_event_msg(self, sub_alarm_dict, alarm_id):
sub_alarms_deleted_event_msg = {}
if alarm_id not in sub_alarm_dict:
return sub_alarms_deleted_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 = AlarmExprParser(sub_alarm.expression).sub_expr_list[0]
dimensions = {}
sub_alarms_deleted_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_deleted_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'))

View File

@ -14,34 +14,26 @@
import json import json
from falcon.util.uri import parse_query_string from falcon.util.uri import parse_query_string
import re import re
from monasca.common.repositories.exceptions import DoesNotExistException
from pyparsing import ParseException
import falcon import falcon
from oslo.config import cfg from oslo.config import cfg
from monasca.api.alarms_api_v2 import AlarmsV2API from monasca.api.alarms_api_v2 import AlarmsV2API
from monasca.common.repositories import exceptions from monasca.common.repositories import exceptions
from monasca.common import resource_api 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.openstack.common import log
from monasca.v2.reference import helpers from monasca.v2.reference import helpers
from monasca.v2.common.schemas import \ from monasca.v2.reference.alarming import Alarming
alarm_definition_request_body_schema as schema_alarms from monasca.v2.reference.resource import resource_try_catch_block
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__) LOG = log.getLogger(__name__)
class Alarms(AlarmsV2API): class Alarms(AlarmsV2API, Alarming):
def __init__(self, global_conf): def __init__(self, global_conf):
try: try:
super(Alarms, self).__init__(global_conf) super(Alarms, self).__init__(global_conf)
self._region = cfg.CONF.region self._region = cfg.CONF.region
@ -54,11 +46,6 @@ class Alarms(AlarmsV2API):
cfg.CONF.security.default_authorized_roles + \ cfg.CONF.security.default_authorized_roles + \
cfg.CONF.security.agent_authorized_roles cfg.CONF.security.agent_authorized_roles
self._message_queue \
= resource_api.init_driver('monasca.messaging',
cfg.CONF.messaging.driver,
(['events']))
self._alarms_repo = resource_api.init_driver( self._alarms_repo = resource_api.init_driver(
'monasca.repositories', cfg.CONF.repositories.alarms_driver) 'monasca.repositories', cfg.CONF.repositories.alarms_driver)
@ -92,10 +79,11 @@ class Alarms(AlarmsV2API):
helpers.validate_authorization(req, self._default_authorized_roles) helpers.validate_authorization(req, self._default_authorized_roles)
result = '' tenant_id = helpers.get_tenant_id(req)
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
res.status = falcon.HTTP_200 self._alarm_delete(tenant_id, id)
res.status = '501 Not Implemented'
res.status = falcon.HTTP_204
@resource_api.Restify('/v2.0/alarms', method='get') @resource_api.Restify('/v2.0/alarms', method='get')
def do_get_alarms(self, req, res): def do_get_alarms(self, req, res):
@ -121,108 +109,102 @@ class Alarms(AlarmsV2API):
res.body = json.dumps(result, ensure_ascii=False).encode('utf8') res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
res.status = falcon.HTTP_200 res.status = falcon.HTTP_200
@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_deleted_event(tenant_id, alarm_definition_id,
alarm_metric_rows, sub_alarm_rows)
@resource_try_catch_block
def _alarm_show(self, req_uri, tenant_id, id): def _alarm_show(self, req_uri, tenant_id, id):
try: alarm_rows = self._alarms_repo.get_alarm(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)
first_row = True metrics = []
for alarm_row in alarm_rows: alarm = {u'id': alarm_row.alarm_id, u'metrics': metrics,
if first_row: u'state': alarm_row.state,
ad = {u'id': alarm_row.alarm_definition_id, u'alarm_definition': ad}
u'name': alarm_row.alarm_definition_name, helpers.add_links_to_resource(alarm, req_uri)
u'severity': alarm_row.severity, }
helpers.add_links_to_resource(ad,
re.sub('alarms',
'alarm-definitions',
req_uri),
rel=None)
metrics = [] first_row = False
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}
dimensions = {} if alarm_row.metric_dimensions:
metric = {u'name': alarm_row.metric_name, for dimension in alarm_row.metric_dimensions.split(','):
u'dimensions': dimensions} parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
if alarm_row.metric_dimensions: metrics.append(metric)
for dimension in alarm_row.metric_dimensions.split(','):
parsed_dimension = dimension.split('=')
dimensions[parsed_dimension[0]] = parsed_dimension[1]
metrics.append(metric) return alarm
return alarm
except DoesNotExistException:
raise falcon.HTTPNotFound()
except exceptions.RepositoryException as ex:
LOG.exception(ex)
msg = "".join(ex.message.args)
raise falcon.HTTPInternalServerError('Service unavailable', msg)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex)
@resource_try_catch_block
def _alarm_list(self, req_uri, tenant_id, query_parms): def _alarm_list(self, req_uri, tenant_id, query_parms):
try: alarm_rows = self._alarms_repo.get_alarms(tenant_id, query_parms)
alarm_rows = self._alarms_repo.get_alarms(tenant_id, query_parms) result = []
result = []
if not alarm_rows:
return result
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)
if not alarm_rows:
return result return result
except exceptions.RepositoryException as ex: prev_alarm_id = None
LOG.exception(ex) for alarm_row in alarm_rows:
msg = "".join(ex.message.args) if prev_alarm_id != alarm_row.alarm_id:
raise falcon.HTTPInternalServerError('Service unavailable', msg) if prev_alarm_id is not None:
except Exception as ex: result.append(alarm)
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex) 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 result

View File

@ -0,0 +1,32 @@
import falcon
from monasca.common.messaging import exceptions
from monasca.common.repositories.exceptions import DoesNotExistException
from monasca.openstack.common import log
LOG = log.getLogger(__name__)
def resource_try_catch_block(fun):
def try_it(*args, **kwargs):
try:
return fun(*args, **kwargs)
except falcon.HTTPNotFound:
raise
except DoesNotExistException:
raise falcon.HTTPNotFound
except falcon.HTTPBadRequest:
raise
except exceptions.RepositoryException as ex:
LOG.exception(ex)
msg = "".join(ex.message.args)
raise falcon.HTTPInternalServerError('Service unavailable', msg)
except Exception as ex:
LOG.exception(ex)
raise falcon.HTTPInternalServerError('Service unavailable', ex)
return try_it