Add alarm history resource
Change-Id: Ic19c09cc0808c994cadfb7e3c7680dd58438852d
This commit is contained in:
parent
000056f174
commit
71c9acb1cc
|
@ -45,3 +45,11 @@ class AlarmsV2API(object):
|
|||
@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'
|
||||
|
|
|
@ -45,13 +45,3 @@ class V2API(object):
|
|||
@resource_api.Restify('/v2.0/metrics/statistics', method='get')
|
||||
def do_get_statistics(self, req, res):
|
||||
res.status = '501 Not Implemented'
|
||||
|
||||
|
||||
|
||||
@resource_api.Restify('/v2.0/alarms/state-history', method='get')
|
||||
def do_get_alarms_state_history(self, req, res, id):
|
||||
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'
|
||||
|
|
|
@ -14,14 +14,16 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from stevedore import driver
|
||||
import os
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
from wsgiref import simple_server
|
||||
|
||||
from oslo.config import cfg
|
||||
from oslo.config import types
|
||||
from paste.deploy import loadapp
|
||||
from wsgiref import simple_server
|
||||
import paste.deploy
|
||||
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
METRICS_DISPATCHER_NAMESPACE = 'monasca.metrics_dispatcher'
|
||||
ALARM_DEFINITIONS_DISPATCHER_NAMESPACE = 'monasca.alarm_definitions_dispatcher'
|
||||
|
@ -183,6 +185,8 @@ def api_app(conf):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
wsgi_app = loadapp('config:etc/monasca.ini', relative_to=os.getcwd())
|
||||
wsgi_app = (
|
||||
paste.deploy.loadapp('config:etc/monasca.ini',
|
||||
relative_to=os.getcwd()))
|
||||
httpd = simple_server.make_server('127.0.0.1', 9000, wsgi_app)
|
||||
httpd.serve_forever()
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
# 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 time
|
||||
|
||||
from kafka import client
|
||||
from kafka import common
|
||||
from kafka import consumer
|
||||
from kafka import producer
|
||||
from oslo.config import cfg
|
||||
import time
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class MessageQueueException(Exception):
|
||||
pass
|
|
@ -11,16 +11,16 @@
|
|||
# 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 time
|
||||
|
||||
from kafka import client
|
||||
from kafka import common
|
||||
from kafka import producer
|
||||
from oslo.config import cfg
|
||||
import time
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.common.messaging import publisher
|
||||
from monasca.common.messaging import exceptions
|
||||
from monasca.common.messaging import publisher
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
def transform(events, tenant_id, region):
|
||||
raise NotImplemented()
|
|
@ -12,5 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
def transform(metrics, tenant_id, region):
|
||||
raise NotImplemented()
|
|
@ -13,15 +13,17 @@
|
|||
# under the License.
|
||||
|
||||
from oslo.config import cfg
|
||||
import monasca.common.messaging.message_formats.reference.events as reference_events
|
||||
|
||||
import monasca.common.messaging.message_formats.cadf.events as cadf_events
|
||||
import monasca.common.messaging.message_formats.identity.events as identity_events
|
||||
import monasca.common.messaging.message_formats.identity.events as ident_events
|
||||
import monasca.common.messaging.message_formats.reference.events as ref_events
|
||||
|
||||
|
||||
def create_events_transform():
|
||||
message_format = cfg.CONF.messaging.events_message_format
|
||||
if message_format == 'reference':
|
||||
return reference_events.transform
|
||||
return ref_events.transform
|
||||
elif message_format == 'cadf':
|
||||
return cadf_events.transform
|
||||
else:
|
||||
return identity_events.transform
|
||||
return ident_events.transform
|
|
@ -12,5 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class TransformationException(Exception):
|
||||
pass
|
|
@ -12,7 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
def transform(events, tenant_id, region):
|
||||
return events
|
|
@ -12,7 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
def transform(metrics, tenant_id, region):
|
||||
return metrics
|
|
@ -13,15 +13,17 @@
|
|||
# under the License.
|
||||
|
||||
from oslo.config import cfg
|
||||
import monasca.common.messaging.message_formats.reference.metrics as reference_metrics
|
||||
|
||||
import monasca.common.messaging.message_formats.cadf.metrics as cadf_metrics
|
||||
import monasca.common.messaging.message_formats.identity.metrics as identity_metrics
|
||||
import monasca.common.messaging.message_formats.identity.metrics as id_metrics
|
||||
import monasca.common.messaging.message_formats.reference.metrics as r_metrics
|
||||
|
||||
|
||||
def create_metrics_transform():
|
||||
metrics_message_format = cfg.CONF.messaging.metrics_message_format
|
||||
if metrics_message_format == 'reference':
|
||||
return reference_metrics.transform
|
||||
return r_metrics.transform
|
||||
elif metrics_message_format == 'cadf':
|
||||
return cadf_metrics.transform
|
||||
else:
|
||||
return identity_metrics.transform
|
||||
return id_metrics.transform
|
|
@ -12,7 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
|
||||
|
||||
def transform(event, tenant_id, region):
|
||||
|
|
|
@ -12,17 +12,13 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
|
||||
|
||||
def transform(metrics, tenant_id, region):
|
||||
transformed_metric = {
|
||||
'metric': {},
|
||||
'meta': {
|
||||
'tenantId': tenant_id,
|
||||
'region': region
|
||||
},
|
||||
'creation_time': datetime.now()
|
||||
}
|
||||
transformed_metric = {'metric': {},
|
||||
'meta': {'tenantId': tenant_id, 'region': region},
|
||||
'creation_time': datetime.now()}
|
||||
|
||||
if isinstance(metrics, list):
|
||||
transformed_metrics = []
|
||||
|
|
|
@ -13,16 +13,16 @@
|
|||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class Publisher(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def send_message(self, message):
|
||||
'''
|
||||
Sends the message using the message queue.
|
||||
"""Sends the message using the message queue.
|
||||
|
||||
:param message: Message to send.
|
||||
'''
|
||||
"""
|
||||
return
|
|
@ -12,20 +12,20 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class AlarmDefinitionsRepository(object):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(AlarmDefinitionsRepository, self).__init__()
|
||||
super(AlarmDefinitionsRepository, self).__init__()
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_alarm_definition(self, tenant_id, name,
|
||||
expression, sub_expr_list, description, severity, match_by, alarm_actions,
|
||||
undetermined_actions, ok_action):
|
||||
def create_alarm_definition(self, tenant_id, name, expression,
|
||||
sub_expr_list, description, severity, match_by,
|
||||
alarm_actions, undetermined_actions,
|
||||
ok_action):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
|
@ -12,9 +12,33 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class AlarmsRepository(object):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(AlarmsRepository, self).__init__()
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_alarm_metrics(self, alarm_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_sub_alarms(self, tenant_id, alarm_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_alarm(self, tenant_id, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_alarm(self, tenant_id, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_alarms(self, tenant_id, query_parms):
|
||||
pass
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class RepositoryException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DoesNotExistException(RepositoryException):
|
||||
pass
|
|
@ -12,13 +12,12 @@
|
|||
# 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 re
|
||||
import time
|
||||
import urllib
|
||||
from time import strftime
|
||||
from time import gmtime
|
||||
|
||||
from influxdb import InfluxDBClient
|
||||
from influxdb.client import InfluxDBClientError
|
||||
from influxdb import client
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
|
@ -30,11 +29,12 @@ LOG = log.getLogger(__name__)
|
|||
|
||||
|
||||
class MetricsRepository(metrics_repository.MetricsRepository):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
try:
|
||||
self.conf = cfg.CONF
|
||||
self.influxdb_client = InfluxDBClient(
|
||||
self.influxdb_client = client.InfluxDBClient(
|
||||
self.conf.influxdb.ip_address, self.conf.influxdb.port,
|
||||
self.conf.influxdb.user, self.conf.influxdb.password,
|
||||
self.conf.influxdb.database_name)
|
||||
|
@ -144,8 +144,8 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
|
||||
def _decode_influxdb_serie_name_list(self, series_names):
|
||||
|
||||
"""
|
||||
Example series_names from InfluxDB.
|
||||
"""Example series_names from InfluxDB.
|
||||
|
||||
[
|
||||
{
|
||||
"points": [
|
||||
|
@ -178,11 +178,11 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
|
||||
return json_metric_list
|
||||
|
||||
|
||||
def _decode_influxdb_serie_name(self, serie_name):
|
||||
|
||||
"""
|
||||
Decodes a serie name from InfluxDB. The raw serie name is
|
||||
"""Decodes a serie name from InfluxDB.
|
||||
|
||||
The raw serie name is
|
||||
formed by url encoding the name, tenant id, region, and dimensions,
|
||||
and concatenating them into a quasi URL query string.
|
||||
|
||||
|
@ -227,11 +227,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
|
||||
return metric
|
||||
|
||||
|
||||
def measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp):
|
||||
"""
|
||||
Example result from InfluxDB.
|
||||
"""Example result from InfluxDB.
|
||||
|
||||
[
|
||||
{
|
||||
"points": [
|
||||
|
@ -285,9 +284,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
|
||||
try:
|
||||
result = self.influxdb_client.query(query, 's')
|
||||
except InfluxDBClientError as ex:
|
||||
if ex.code == 400 and ex.content == 'Couldn\'t look up ' \
|
||||
'columns':
|
||||
except client.InfluxDBClientError as ex:
|
||||
# check for non-existent serie name.
|
||||
msg = "Couldn't look up columns"
|
||||
if ex.code == 400 and ex.content == (msg):
|
||||
return json_measurement_list
|
||||
else:
|
||||
raise ex
|
||||
|
@ -307,8 +307,9 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
columns]
|
||||
|
||||
# format the utc date in the points
|
||||
fmtd_pts = [[strftime("%Y-%m-%dT%H:%M:%SZ", gmtime(point[0])),
|
||||
point[1], point[2]] for point in serie['points']]
|
||||
fmtd_pts = [[time.strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||
time.gmtime(point[0])), point[1],
|
||||
point[2]] for point in serie['points']]
|
||||
|
||||
measurement = {"name": metric['name'],
|
||||
"dimensions": metric['dimensions'],
|
||||
|
@ -322,7 +323,6 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
|
||||
def metrics_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp, statistics, period):
|
||||
|
||||
|
@ -336,9 +336,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
|
||||
try:
|
||||
result = self.influxdb_client.query(query, 's')
|
||||
except InfluxDBClientError as ex:
|
||||
if ex.code == 400 and ex.content == 'Couldn\'t look up ' \
|
||||
'columns':
|
||||
except client.InfluxDBClientError as ex:
|
||||
# check for non-existent serie name.
|
||||
msg = "Couldn't look up columns"
|
||||
if ex.code == 400 and ex.content == (msg):
|
||||
return json_statistics_list
|
||||
else:
|
||||
raise ex
|
||||
|
@ -357,9 +358,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
columns = [column.replace('time', 'timestamp') for column in
|
||||
columns]
|
||||
|
||||
fmtd_pts_list_list = [[strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||
gmtime(pts_list[0]))] + pts_list[1:]
|
||||
for pts_list in serie['points']]
|
||||
fmtd_pts_list_list = [[time.strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||
time.gmtime(pts_list[
|
||||
0]))] + pts_list[1:]
|
||||
for pts_list in serie['points']]
|
||||
|
||||
measurement = {"name": metric['name'],
|
||||
"dimensions": metric['dimensions'],
|
||||
|
@ -373,3 +375,118 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
def alarm_history(self, tenant_id, alarm_id_list, start_timestamp=None,
|
||||
end_timestamp=None):
|
||||
"""Example result from Influxdb.
|
||||
|
||||
[
|
||||
{
|
||||
"points": [
|
||||
[
|
||||
1415894490,
|
||||
272140001,
|
||||
"6ac10841-d02f-4f7d-a191-ae0a3d9a25f2",
|
||||
"[{\"name\": \"cpu.system_perc\", \"dimensions\": {
|
||||
\"hostname\": \"mini-mon\", \"component\":
|
||||
\"monasca-agent\", \"service\": \"monitoring\"}},
|
||||
{\"name\": \"load.avg_1_min\", \"dimensions\": {
|
||||
\"hostname\": \"mini-mon\", \"component\":
|
||||
\"monasca-agent\", \"service\": \"monitoring\"}}]",
|
||||
"ALARM",
|
||||
"OK",
|
||||
"Thresholds were exceeded for the sub-alarms: [max(
|
||||
load.avg_1_min{hostname=mini-mon}) > 0.0,
|
||||
max(cpu.system_perc) > 0.0]",
|
||||
"{}"
|
||||
],
|
||||
],
|
||||
"name": "alarm_state_history",
|
||||
"columns": [
|
||||
"time",
|
||||
"sequence_number",
|
||||
"alarm_id",
|
||||
"metrics",
|
||||
"new_state",
|
||||
"old_state",
|
||||
"reason",
|
||||
"reason_data"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
:param tenant_id:
|
||||
:param alarm_id:
|
||||
:return:
|
||||
"""
|
||||
|
||||
try:
|
||||
|
||||
json_alarm_history_list = []
|
||||
|
||||
if not alarm_id_list:
|
||||
return json_alarm_history_list
|
||||
|
||||
for alarm_id in alarm_id_list:
|
||||
if '\'' in alarm_id or ';' in alarm_id:
|
||||
raise Exception(
|
||||
"Input from user contains single quote ['] or "
|
||||
"semi-colon [;] characters[ {} ]".format(alarm_id))
|
||||
|
||||
query = """
|
||||
select alarm_id, metrics, old_state, new_state,
|
||||
reason, reason_data
|
||||
from alarm_state_history
|
||||
"""
|
||||
|
||||
where_clause = (
|
||||
" where tenant_id = '{}' ".format(tenant_id.encode('utf8')))
|
||||
|
||||
alarm_id_where_clause_list = (
|
||||
[" alarm_id = '{}' ".format(id.encode('utf8'))
|
||||
for id in alarm_id_list])
|
||||
|
||||
alarm_id_where_clause = " or ".join(alarm_id_where_clause_list)
|
||||
|
||||
where_clause += ' and (' + alarm_id_where_clause + ')'
|
||||
|
||||
time_clause = ''
|
||||
if start_timestamp:
|
||||
# subtract 1 from timestamp to get >= semantics
|
||||
time_clause += " and time > " + str(start_timestamp - 1) + "s"
|
||||
if end_timestamp:
|
||||
# add 1 to timestamp to get <= semantics
|
||||
time_clause += " and time < " + str(end_timestamp + 1) + "s"
|
||||
|
||||
query += where_clause + time_clause
|
||||
try:
|
||||
result = self.influxdb_client.query(query, 's')
|
||||
except client.InfluxDBClientError as ex:
|
||||
# check for non-existent serie name. only happens
|
||||
# if alarm_state_history serie does not exist.
|
||||
msg = "Couldn't look up columns"
|
||||
if ex.code == 400 and ex.content == (msg):
|
||||
return json_alarm_history_list
|
||||
else:
|
||||
raise ex
|
||||
|
||||
if not result:
|
||||
return json_alarm_history_list
|
||||
|
||||
# There's only one serie, alarm_state_history.
|
||||
for point in result[0]['points']:
|
||||
alarm_point = {u'alarm_id': point[2],
|
||||
u'metrics': json.loads(point[3]),
|
||||
u'old_state': point[4], u'new_state': point[5],
|
||||
u'reason': point[6], u'reason_data': point[7],
|
||||
u'timestamp': time.strftime(
|
||||
"%Y-%m-%dT%H:%M:%SZ",
|
||||
time.gmtime(point[0]))}
|
||||
|
||||
json_alarm_history_list.append(alarm_point)
|
||||
|
||||
return json_alarm_history_list
|
||||
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise exceptions.RepositoryException(ex)
|
|
@ -30,5 +30,5 @@ class MetricsRepository(object):
|
|||
|
||||
@abc.abstractmethod
|
||||
def metrics_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp, statistics):
|
||||
end_timestamp, statistics, period):
|
||||
pass
|
|
@ -13,20 +13,19 @@
|
|||
# under the License.
|
||||
import datetime
|
||||
|
||||
from monasca.common.repositories import alarm_definitions_repository
|
||||
from monasca.common.repositories.exceptions import DoesNotExistException
|
||||
from monasca.common.repositories.mysql.mysql_repository import MySQLRepository
|
||||
from monasca.common.repositories.mysql.mysql_repository import mysql_try_catch_block
|
||||
from monasca.common.repositories import alarm_definitions_repository as adr
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common.repositories.mysql import mysql_repository
|
||||
from monasca.openstack.common import log
|
||||
from monasca.openstack.common import uuidutils
|
||||
from monasca.common.repositories import exceptions
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class AlarmDefinitionsRepository(MySQLRepository,
|
||||
alarm_definitions_repository.AlarmDefinitionsRepository):
|
||||
class AlarmDefinitionsRepository(mysql_repository.MySQLRepository,
|
||||
adr.AlarmDefinitionsRepository):
|
||||
|
||||
base_query = """
|
||||
select ad.id, ad.name, ad.description, ad.expression,
|
||||
ad.match_by, ad.severity, ad.actions_enabled,
|
||||
|
@ -56,7 +55,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
super(AlarmDefinitionsRepository, self).__init__()
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_alarm_definition(self, tenant_id, id):
|
||||
|
||||
parms = [tenant_id, id]
|
||||
|
@ -72,9 +71,9 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
if rows:
|
||||
return rows[0]
|
||||
else:
|
||||
raise DoesNotExistException
|
||||
raise exceptions.DoesNotExistException
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_alarm_definitions(self, tenant_id, name, dimensions):
|
||||
|
||||
parms = [tenant_id]
|
||||
|
@ -113,8 +112,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
return self._execute_query(query, parms)
|
||||
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_sub_alarms(self, tenant_id, alarm_definition_id):
|
||||
|
||||
parms = [tenant_id, alarm_definition_id]
|
||||
|
@ -131,10 +129,10 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
return self._execute_query(query, parms)
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_alarm_metrics(self, tenant_id, alarm_definition_id):
|
||||
|
||||
parms = [tenant_id, alarm_definition_id]
|
||||
parms = [tenant_id, alarm_definition_id]
|
||||
|
||||
query = """select distinct a.id as alarm_id, md.name,
|
||||
mdg.dimensions
|
||||
|
@ -156,7 +154,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
return self._execute_query(query, parms)
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def delete_alarm_definition(self, tenant_id, alarm_definition_id):
|
||||
"""Soft delete the alarm definition.
|
||||
|
||||
|
@ -187,7 +185,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
return True
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_sub_alarm_definitions(self, alarm_definition_id):
|
||||
|
||||
parms = [alarm_definition_id]
|
||||
|
@ -206,7 +204,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
return self._execute_query(query, parms)
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def create_alarm_definition(self, tenant_id, name, expression,
|
||||
sub_expr_list, description, severity, match_by,
|
||||
alarm_actions, undetermined_actions,
|
||||
|
@ -275,7 +273,6 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
|
||||
return alarm_definition_id
|
||||
|
||||
|
||||
def _insert_into_alarm_action(self, cursor, alarm_definition_id, actions,
|
||||
alarm_state):
|
||||
for action in actions:
|
||||
|
@ -293,5 +290,3 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
|||
action_id)
|
||||
values(?,?,?)""", alarm_definition_id,
|
||||
alarm_state.encode('utf8'), action.encode('utf8'))
|
||||
|
||||
|
||||
|
|
|
@ -11,18 +11,18 @@
|
|||
# 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.repositories.exceptions import DoesNotExistException
|
||||
|
||||
from monasca.common.repositories import alarms_repository
|
||||
from monasca.common.repositories.mysql.mysql_repository import MySQLRepository
|
||||
from monasca.common.repositories.mysql.mysql_repository import mysql_try_catch_block
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common.repositories.mysql import mysql_repository
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
||||
class AlarmsRepository(mysql_repository.MySQLRepository,
|
||||
alarms_repository.AlarmsRepository):
|
||||
|
||||
base_query = """
|
||||
select distinct a.id as alarm_id, a.state,
|
||||
|
@ -47,10 +47,10 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
|||
|
||||
super(AlarmsRepository, self).__init__()
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_alarm_metrics(self, alarm_id):
|
||||
|
||||
parms = [alarm_id]
|
||||
parms = [alarm_id]
|
||||
|
||||
query = """select distinct a.id as alarm_id, md.name,
|
||||
mdg.dimensions
|
||||
|
@ -70,7 +70,7 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
|||
|
||||
return self._execute_query(query, parms)
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_sub_alarms(self, tenant_id, alarm_id):
|
||||
|
||||
parms = [tenant_id, alarm_id]
|
||||
|
@ -87,20 +87,20 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
|||
|
||||
return self._execute_query(query, parms)
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.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
|
||||
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
|
||||
where ad.tenant_id = ? and a.id = ?) as b
|
||||
on b.id = alarm.id
|
||||
"""
|
||||
|
||||
|
@ -109,11 +109,11 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
|||
cursor.execute(query, parms)
|
||||
|
||||
if cursor.rowcount < 1:
|
||||
raise DoesNotExistException
|
||||
raise exceptions.DoesNotExistException
|
||||
|
||||
self._commit_close_cnxn(cnxn)
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_alarm(self, tenant_id, id):
|
||||
|
||||
parms = [tenant_id, id]
|
||||
|
@ -128,11 +128,11 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
|||
rows = self._execute_query(query, parms)
|
||||
|
||||
if not rows:
|
||||
raise DoesNotExistException
|
||||
raise exceptions.DoesNotExistException
|
||||
else:
|
||||
return rows
|
||||
|
||||
@mysql_try_catch_block
|
||||
@mysql_repository.mysql_try_catch_block
|
||||
def get_alarms(self, tenant_id, query_parms):
|
||||
|
||||
parms = [tenant_id]
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from oslo.config import cfg
|
||||
import peewee
|
||||
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
db = peewee.MySQLDatabase(cfg.CONF.mysql.database_name,
|
||||
|
|
|
@ -11,27 +11,22 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import datetime
|
||||
import pyodbc
|
||||
from monasca.common.repositories.exceptions import DoesNotExistException
|
||||
|
||||
from oslo.config import cfg
|
||||
import pyodbc
|
||||
|
||||
from monasca.common.repositories import alarms_repository
|
||||
from monasca.openstack.common import log
|
||||
from monasca.openstack.common import uuidutils
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class MySQLRepository(object):
|
||||
|
||||
database_driver = 'MySQL ODBC 5.3 ANSI Driver'
|
||||
database_cnxn_template = 'DRIVER={' \
|
||||
'%s};Server=%s;CHARSET=UTF8;Database=%s;Uid=%s' \
|
||||
';Pwd=%s'
|
||||
database_cnxn_template = ('DRIVER={'
|
||||
'%s};Server=%s;CHARSET=UTF8;Database=%s;Uid=%s'
|
||||
';Pwd=%s')
|
||||
|
||||
def __init__(self):
|
||||
|
||||
|
@ -65,7 +60,6 @@ class MySQLRepository(object):
|
|||
cnxn.commit()
|
||||
cnxn.close()
|
||||
|
||||
|
||||
def _execute_query(self, query, parms):
|
||||
|
||||
cnxn, cursor = self._get_cnxn_cursor_tuple()
|
||||
|
@ -87,7 +81,7 @@ def mysql_try_catch_block(fun):
|
|||
|
||||
return fun(*args, **kwargs)
|
||||
|
||||
except DoesNotExistException:
|
||||
except exceptions.DoesNotExistException:
|
||||
raise
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
|
|
@ -13,11 +13,14 @@
|
|||
# under the License.
|
||||
|
||||
import datetime
|
||||
from monasca.common.repositories import notifications_repository
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.openstack.common import log
|
||||
import peewee
|
||||
|
||||
import model
|
||||
import peewee
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common.repositories import notifications_repository
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
@ -55,7 +58,7 @@ class NotificationsRepository(
|
|||
self, id, tenant_id, name, notification_type, address):
|
||||
try:
|
||||
now = datetime.datetime.utcnow()
|
||||
q = Notification_Method.create(
|
||||
Notification_Method.create(
|
||||
id=id,
|
||||
tenant_id=tenant_id,
|
||||
name=name,
|
||||
|
@ -73,7 +76,6 @@ class NotificationsRepository(
|
|||
Notification_Method.tenant_id == tenant_id)
|
||||
results = q.execute()
|
||||
|
||||
notifications = []
|
||||
notifications = [
|
||||
self.notification_from_result(result) for result in results]
|
||||
return notifications
|
||||
|
@ -82,7 +84,6 @@ class NotificationsRepository(
|
|||
raise exceptions.RepositoryException(ex)
|
||||
|
||||
def delete_notification(self, tenant_id, notification_id):
|
||||
num_rows_deleted = 0
|
||||
|
||||
try:
|
||||
q = Notification_Method.delete().where(
|
||||
|
@ -113,7 +114,6 @@ class NotificationsRepository(
|
|||
def update_notification(
|
||||
self, id, tenant_id, name, notification_type, address):
|
||||
now = datetime.datetime.utcnow()
|
||||
num_rows_updated = 0
|
||||
try:
|
||||
q = Notification_Method.update(
|
||||
name=name,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,11 +12,13 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from monasca.common.repositories import transforms_repository
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.openstack.common import log
|
||||
import peewee
|
||||
import model
|
||||
import peewee
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common.repositories import transforms_repository
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
@ -32,11 +34,14 @@ class Transform(model.Model):
|
|||
updated_at = peewee.DateTimeField()
|
||||
deleted_at = peewee.DateTimeField()
|
||||
|
||||
class TransformsRepository(transforms_repository.TransformsRepository):
|
||||
|
||||
def create_transforms(self, id, tenant_id, name, description, specification, enabled):
|
||||
class TransformsRepository(transforms_repository.TransformsRepository):
|
||||
def create_transforms(self, id, tenant_id, name, description,
|
||||
specification, enabled):
|
||||
try:
|
||||
q = Transform.create(id=id, tenant_id=tenant_id, name=name, description=description, specification=specification, enabled=enabled)
|
||||
q = Transform.create(id=id, tenant_id=tenant_id, name=name,
|
||||
description=description,
|
||||
specification=specification, enabled=enabled)
|
||||
q.save()
|
||||
except Exception as ex:
|
||||
LOG.exception(str(ex))
|
||||
|
@ -49,13 +54,10 @@ class TransformsRepository(transforms_repository.TransformsRepository):
|
|||
|
||||
transforms = []
|
||||
for result in results:
|
||||
transform = {
|
||||
'id': result.id,
|
||||
'name': result.name,
|
||||
'description': result.description,
|
||||
'specification': result.specification,
|
||||
'enabled': result.enabled
|
||||
}
|
||||
transform = {'id': result.id, 'name': result.name,
|
||||
'description': result.description,
|
||||
'specification': result.specification,
|
||||
'enabled': result.enabled}
|
||||
transforms.append(transform)
|
||||
return transforms
|
||||
except Exception as ex:
|
||||
|
@ -66,7 +68,8 @@ class TransformsRepository(transforms_repository.TransformsRepository):
|
|||
num_rows_deleted = 0
|
||||
|
||||
try:
|
||||
q = Transform.delete().where((Transform.tenant_id == tenant_id) & (Transform.id == transform_id))
|
||||
q = Transform.delete().where((Transform.tenant_id == tenant_id) & (
|
||||
Transform.id == transform_id))
|
||||
num_rows_deleted = q.execute()
|
||||
except Exception as ex:
|
||||
LOG.exception(str(ex))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -13,14 +13,15 @@
|
|||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class TransformsRepository(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_transforms(self, id, tenant_id, name, description, specification, enabled):
|
||||
def create_transforms(self, id, tenant_id, name, description,
|
||||
specification, enabled):
|
||||
return
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
import falcon
|
||||
from falcon import api_helpers
|
||||
from stevedore import driver
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from stevedore import driver
|
||||
|
||||
RESOURCE_METHOD_FLAG = 'fab05a04-b861-4651-bd0c-9cb3eb9a6088'
|
||||
|
||||
|
@ -32,16 +32,14 @@ def init_driver(namespace, driver_name, drv_invoke_args=()):
|
|||
:param driver_name: the driver name (in monasca.conf)
|
||||
:param invoke_args: args to pass to the driver (a tuple)
|
||||
"""
|
||||
mgr = driver.DriverManager(
|
||||
namespace = namespace,
|
||||
name = driver_name,
|
||||
invoke_on_load = True,
|
||||
invoke_args = drv_invoke_args
|
||||
)
|
||||
mgr = driver.DriverManager(namespace=namespace, name=driver_name,
|
||||
invoke_on_load=True,
|
||||
invoke_args=drv_invoke_args)
|
||||
return mgr.driver
|
||||
|
||||
|
||||
class Restify(object):
|
||||
|
||||
def __init__(self, path='', method='GET'):
|
||||
if not path:
|
||||
raise Exception('Path has to be specified.')
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
|
|
|
@ -16,22 +16,13 @@
|
|||
import itertools
|
||||
import sys
|
||||
|
||||
from pyparsing import CaselessLiteral
|
||||
from pyparsing import alphanums
|
||||
from pyparsing import delimitedList
|
||||
from pyparsing import Forward
|
||||
from pyparsing import Group
|
||||
from pyparsing import Literal
|
||||
from pyparsing import nums
|
||||
from pyparsing import opAssoc
|
||||
from pyparsing import operatorPrecedence
|
||||
from pyparsing import Optional
|
||||
from pyparsing import stringEnd
|
||||
from pyparsing import Word
|
||||
import pyparsing
|
||||
|
||||
|
||||
class SubExpr(object):
|
||||
|
||||
def __init__(self, tokens):
|
||||
|
||||
self._sub_expr = tokens
|
||||
self._func = tokens.func
|
||||
self._metric_name = tokens.metric_name
|
||||
|
@ -173,67 +164,70 @@ class BinaryOp(object):
|
|||
|
||||
|
||||
class AndSubExpr(BinaryOp):
|
||||
""" Expand later as needed.
|
||||
"""
|
||||
"""Expand later as needed."""
|
||||
pass
|
||||
|
||||
|
||||
class OrSubExpr(BinaryOp):
|
||||
"""Expand later as needed.
|
||||
"""
|
||||
"""Expand later as needed."""
|
||||
pass
|
||||
|
||||
|
||||
COMMA = Literal(",")
|
||||
LPAREN = Literal("(")
|
||||
RPAREN = Literal(")")
|
||||
EQUAL = Literal("=")
|
||||
LBRACE = Literal("{")
|
||||
RBRACE = Literal("}")
|
||||
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 + alphanums + ".-_#!$%&'*+/:;?@["
|
||||
"\\]^`|~")
|
||||
valid_identifier_chars = (
|
||||
(unicode_printables + pyparsing.alphanums + ".-_#!$%&'*+/:;?@[\\]^`|~"))
|
||||
|
||||
metric_name = Word(valid_identifier_chars, min=1, max=255)("metric_name")
|
||||
dimension_name = Word(valid_identifier_chars, min=1, max=255)
|
||||
dimension_value = Word(valid_identifier_chars, min=1, max=255)
|
||||
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 = Word(nums)
|
||||
decimal_number = Word(nums + ".")
|
||||
integer_number = pyparsing.Word(pyparsing.nums)
|
||||
decimal_number = pyparsing.Word(pyparsing.nums + ".")
|
||||
|
||||
max = CaselessLiteral("max")
|
||||
min = CaselessLiteral("min")
|
||||
avg = CaselessLiteral("avg")
|
||||
count = CaselessLiteral("count")
|
||||
sum = CaselessLiteral("sum")
|
||||
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 = (CaselessLiteral("<") | CaselessLiteral("lt"))
|
||||
less_than_eq_op = (CaselessLiteral("<=") | CaselessLiteral("lte"))
|
||||
greater_than_op = (CaselessLiteral(">") | CaselessLiteral("gt"))
|
||||
greater_than_eq_op = (CaselessLiteral(">=") | CaselessLiteral("gte"))
|
||||
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 = CaselessLiteral("and") | CaselessLiteral("&&")
|
||||
OR = CaselessLiteral("or") | CaselessLiteral("||")
|
||||
AND = pyparsing.CaselessLiteral("and") | pyparsing.CaselessLiteral("&&")
|
||||
OR = pyparsing.CaselessLiteral("or") | pyparsing.CaselessLiteral("||")
|
||||
logical_op = (AND | OR)("logical_op")
|
||||
|
||||
times = CaselessLiteral("times")
|
||||
times = pyparsing.CaselessLiteral("times")
|
||||
|
||||
dimension = Group(dimension_name + EQUAL + dimension_value)
|
||||
dimension = pyparsing.Group(dimension_name + EQUAL + dimension_value)
|
||||
|
||||
# Cannot have any whitespace after the comma delimiter.
|
||||
dimension_list = Group(Optional(
|
||||
LBRACE + delimitedList(dimension, delim=',', combine=True)(
|
||||
dimension_list = pyparsing.Group(pyparsing.Optional(
|
||||
LBRACE + pyparsing.delimitedList(dimension, delim=',', combine=True)(
|
||||
"dimensions_list") + RBRACE))
|
||||
|
||||
metric = metric_name + dimension_list("dimensions")
|
||||
|
@ -241,17 +235,18 @@ period = integer_number("period")
|
|||
threshold = decimal_number("threshold")
|
||||
periods = integer_number("periods")
|
||||
|
||||
expression = Forward()
|
||||
expression = pyparsing.Forward()
|
||||
|
||||
sub_expression = (func + LPAREN + metric + Optional(
|
||||
COMMA + period) + RPAREN + relational_op + threshold + Optional(
|
||||
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 = operatorPrecedence(sub_expression,
|
||||
[(AND, 2, opAssoc.LEFT, AndSubExpr),
|
||||
(OR, 2, opAssoc.LEFT, OrSubExpr)])
|
||||
expression = (
|
||||
pyparsing.operatorPrecedence(sub_expression,
|
||||
[(AND, 2, pyparsing.opAssoc.LEFT, AndSubExpr),
|
||||
(OR, 2, pyparsing.opAssoc.LEFT, OrSubExpr)]))
|
||||
|
||||
|
||||
class AlarmExprParser(object):
|
||||
|
@ -262,37 +257,37 @@ class AlarmExprParser(object):
|
|||
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 + stringEnd).parseString(
|
||||
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. """
|
||||
"""Used for development and testing."""
|
||||
|
||||
expr0 = "max(-_.千幸福的笑脸{घोड़ा=馬, dn2=dv2}, 60) gte 100 times 3 && " \
|
||||
"(min(ເຮືອນ{dn3=dv3,家=дом}) < 10 or sum(biz{dn5=dv5}) > 99 and " \
|
||||
"count(fizzle) lt 0 or count(baz) > 1)".decode('utf8')
|
||||
expr0 = ("max(-_.千幸福的笑脸{घोड़ा=馬, dn2=dv2}, 60) 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')
|
||||
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'))
|
||||
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
|
||||
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__":
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
|
||||
|
||||
class MockAuthFilter(object):
|
||||
'''
|
||||
"""Authorization filter.
|
||||
|
||||
This authorization filter doesn't do any authentication, it just copies the
|
||||
auth token to the tenant ID and supplies the 'admin' role and is meant for
|
||||
testing purposes only.
|
||||
'''
|
||||
"""
|
||||
|
||||
def __init__(self, app, conf):
|
||||
self.app = app
|
||||
self.conf = conf
|
||||
|
|
|
@ -1,87 +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 logging
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import fixtures
|
||||
import testtools
|
||||
|
||||
_TRUE_VALUES = ('True', 'true', '1', 'yes')
|
||||
_LOG_FORMAT = "%(levelname)8s [%(name)s] %(message)s"
|
||||
|
||||
|
||||
class BaseTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTestCase, self).setUp()
|
||||
self._set_timeout()
|
||||
self._fake_output()
|
||||
self._fake_logs()
|
||||
self.useFixture(fixtures.NestedTempfile())
|
||||
self.useFixture(fixtures.TempHomeDir())
|
||||
self.tempdirs = []
|
||||
|
||||
def _set_timeout(self):
|
||||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
|
||||
try:
|
||||
test_timeout = int(test_timeout)
|
||||
except ValueError:
|
||||
# If timeout value is invalid do not set a timeout.
|
||||
test_timeout = 0
|
||||
if test_timeout > 0:
|
||||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
|
||||
|
||||
def _fake_output(self):
|
||||
if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
|
||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
||||
if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
def _fake_logs(self):
|
||||
if os.environ.get('OS_DEBUG') in _TRUE_VALUES:
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = logging.INFO
|
||||
capture_logs = os.environ.get('OS_LOG_CAPTURE') in _TRUE_VALUES
|
||||
if capture_logs:
|
||||
self.useFixture(
|
||||
fixtures.FakeLogger(
|
||||
format=_LOG_FORMAT,
|
||||
level=level,
|
||||
nuke_handlers=capture_logs,
|
||||
)
|
||||
)
|
||||
else:
|
||||
logging.basicConfig(format=_LOG_FORMAT, level=level)
|
||||
|
||||
def create_tempfiles(self, files, ext='.conf'):
|
||||
tempfiles = []
|
||||
for (basename, contents) in files:
|
||||
if not os.path.isabs(basename):
|
||||
(fd, path) = tempfile.mkstemp(prefix=basename, suffix=ext)
|
||||
else:
|
||||
path = basename + ext
|
||||
fd = os.open(path, os.O_CREAT | os.O_WRONLY)
|
||||
tempfiles.append(path)
|
||||
try:
|
||||
os.write(fd, contents)
|
||||
finally:
|
||||
os.close(fd)
|
||||
return tempfiles
|
|
@ -0,0 +1,21 @@
|
|||
# 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 unittest
|
||||
|
||||
|
||||
class Test_first(unittest.TestCase):
|
||||
|
||||
def test_first(self):
|
||||
assert 1 == 1
|
|
@ -12,8 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema, Length, Optional
|
||||
from voluptuous import Required, Any, All
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
@ -22,20 +21,26 @@ from monasca.v2.common.schemas import exceptions
|
|||
LOG = log.getLogger(__name__)
|
||||
|
||||
alarm_definition_schema = {
|
||||
Required('name'): All(Any(str, unicode), Length(max=250)),
|
||||
Required('expression'): All(Any(str, unicode), Length(max=4096)),
|
||||
Optional('description'): All(Any(str, unicode), Length(max=250)),
|
||||
Optional('severity'): All(
|
||||
Any('low', 'medium', 'high', 'critical', 'LOW', "MEDIUM", 'HIGH',
|
||||
'CRITICAL')),
|
||||
Optional('match_by'): All(Any([unicode], [str]), Length(max=255)),
|
||||
Optional('ok_actions'): All(Any([str], [unicode]), Length(max=400)),
|
||||
Optional('alarm_actions'): All(Any([str], [unicode]), Length(max=400)),
|
||||
Optional('undetermined_actions'): All(Any([str], [unicode]),
|
||||
Length(max=400))}
|
||||
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))}
|
||||
|
||||
request_body_schema = Schema(alarm_definition_schema, required=True,
|
||||
extra=True)
|
||||
request_body_schema = voluptuous.Schema(alarm_definition_schema, required=True,
|
||||
extra=True)
|
||||
|
||||
|
||||
def validate(msg):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,15 +12,17 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema
|
||||
from voluptuous import Any, All, Length
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
dimensions_schema = Schema({All(Any(str, unicode), Length(max=255)):
|
||||
All(Any(str, unicode), Length(max=255))})
|
||||
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):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,17 +12,17 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema
|
||||
from voluptuous import Any, All, Length
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# TODO: Add regex to validate key/values don't use any excluded characters.
|
||||
event_schema_request_body = Schema({All(Any(str, unicode), Length(max=255)):
|
||||
All(Any(None, str, unicode, bool, int,
|
||||
float, dict, []))})
|
||||
event_schema_request_body = voluptuous.Schema({
|
||||
voluptuous.All(voluptuous.Any(str, unicode),
|
||||
voluptuous.Length(max=255)): voluptuous.All(
|
||||
voluptuous.Any(None, str, unicode, bool, int, float, dict, []))})
|
||||
|
||||
|
||||
def validate(body):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,14 +12,15 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema
|
||||
from voluptuous import Any, All, Length
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
metric_name_schema = Schema(All(Any(str, unicode), Length(max=64)))
|
||||
metric_name_schema = voluptuous.Schema(
|
||||
voluptuous.All(voluptuous.Any(str, unicode), voluptuous.Length(max=64)))
|
||||
|
||||
|
||||
def validate(name):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,23 +12,24 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema
|
||||
from voluptuous import Required, Any, All, Range, Optional
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import metric_name_schema
|
||||
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 = {
|
||||
Required('name'): metric_name_schema.metric_name_schema,
|
||||
Optional('dimensions'): dimensions_schema.dimensions_schema,
|
||||
Required('timestamp'): All(Any(int, float), Range(min=0)),
|
||||
Required('value'): Any(int, float)
|
||||
}
|
||||
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 = Schema(Any(metric_schema, [metric_schema]))
|
||||
request_body_schema = voluptuous.Schema(
|
||||
voluptuous.Any(metric_schema, [metric_schema]))
|
||||
|
||||
|
||||
def validate(msg):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,20 +12,24 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema
|
||||
from voluptuous import Optional, Required, Any, All, Length
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
notification_schema = {
|
||||
Required('name'): Schema(All(Any(str, unicode), Length(max=250))),
|
||||
Required('type'): Schema(Any("EMAIL", "email")),
|
||||
Required('address'): Schema(All(Any(str, unicode), Length(max=100)))
|
||||
}
|
||||
voluptuous.Required('name'): voluptuous.Schema(
|
||||
voluptuous.All(voluptuous.Any(str, unicode),
|
||||
voluptuous.Length(max=250))),
|
||||
voluptuous.Required('type'): voluptuous.Schema(
|
||||
voluptuous.Any("EMAIL", "email")),
|
||||
voluptuous.Required('address'): voluptuous.Schema(
|
||||
voluptuous.All(voluptuous.Any(str, unicode),
|
||||
voluptuous.Length(max=100)))}
|
||||
|
||||
request_body_schema = Schema(Any(notification_schema))
|
||||
request_body_schema = voluptuous.Schema(voluptuous.Any(notification_schema))
|
||||
|
||||
|
||||
def validate(msg):
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
@ -12,22 +12,26 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from voluptuous import Schema
|
||||
from voluptuous import Optional, Required, Any, All, Length
|
||||
import voluptuous
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import exceptions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
transform_schema = {
|
||||
Required('name'): Schema(All(Any(str, unicode), Length(max=64))),
|
||||
Required('description'): Schema(All(Any(str, unicode), Length(max=250))),
|
||||
Required('specification'):
|
||||
Schema(All(Any(str, unicode), Length(max=64536))),
|
||||
Optional('enabled'): bool
|
||||
}
|
||||
voluptuous.Required('name'): voluptuous.Schema(
|
||||
voluptuous.All(voluptuous.Any(str, unicode),
|
||||
voluptuous.Length(max=64))),
|
||||
voluptuous.Required('description'): voluptuous.Schema(
|
||||
voluptuous.All(voluptuous.Any(str, unicode),
|
||||
voluptuous.Length(max=250))),
|
||||
voluptuous.Required('specification'): voluptuous.Schema(
|
||||
voluptuous.All(voluptuous.Any(str, unicode),
|
||||
voluptuous.Length(max=64536))),
|
||||
voluptuous.Optional('enabled'): bool}
|
||||
|
||||
request_body_schema = Schema(Any(transform_schema))
|
||||
request_body_schema = voluptuous.Schema(voluptuous.Any(transform_schema))
|
||||
|
||||
|
||||
def validate(msg):
|
||||
|
|
|
@ -11,21 +11,24 @@
|
|||
# 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 re
|
||||
from pyparsing import ParseException
|
||||
|
||||
import falcon
|
||||
from oslo.config import cfg
|
||||
import pyparsing
|
||||
|
||||
from monasca.api.alarm_definitions_api_v2 import AlarmDefinitionsV2API
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common import resource_api
|
||||
from monasca.api.alarm_definitions_api_v2 import AlarmDefinitionsV2API
|
||||
from monasca.expression_parser.alarm_expr_parser import AlarmExprParser
|
||||
import monasca.expression_parser.alarm_expr_parser
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.common.schemas import alarm_definition_request_body_schema as schema_alarms
|
||||
from monasca.v2.common.schemas import (alarm_definition_request_body_schema
|
||||
as schema_alarms)
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.reference.alarming import Alarming
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.reference.helpers import read_json_msg_body
|
||||
from monasca.v2.reference.resource import resource_try_catch_block
|
||||
|
||||
|
@ -43,13 +46,13 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
|
||||
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._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',
|
||||
|
@ -134,9 +137,8 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
@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)
|
||||
alarm_definition_row = (
|
||||
self._alarm_definitions_repo.get_alarm_definition(tenant_id, id))
|
||||
|
||||
match_by = get_comma_separated_str_as_list(
|
||||
alarm_definition_row.match_by)
|
||||
|
@ -168,9 +170,8 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
@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)
|
||||
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(
|
||||
|
@ -189,9 +190,9 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
@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)
|
||||
alarm_definition_rows = (
|
||||
self._alarm_definitions_repo.get_alarm_definitions(tenant_id, name,
|
||||
dimensions))
|
||||
|
||||
result = []
|
||||
for alarm_definition_row in alarm_definition_rows:
|
||||
|
@ -227,7 +228,6 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
|
||||
return result
|
||||
|
||||
|
||||
def _validate_alarm_definition(self, alarm_definition):
|
||||
|
||||
try:
|
||||
|
@ -243,20 +243,29 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
ok_actions):
|
||||
try:
|
||||
|
||||
sub_expr_list = AlarmExprParser(expression).sub_expr_list
|
||||
sub_expr_list = (
|
||||
monasca.expression_parser.alarm_expr_parser.
|
||||
AlarmExprParser(expression).sub_expr_list)
|
||||
|
||||
except ParseException as ex:
|
||||
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('utf'))
|
||||
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)
|
||||
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,
|
||||
|
@ -334,6 +343,7 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
|||
|
||||
self._send_event(alarm_definition_created_event_msg)
|
||||
|
||||
|
||||
def get_query_alarm_definition_name(alarm_definition):
|
||||
try:
|
||||
if 'name' in alarm_definition:
|
||||
|
@ -407,6 +417,7 @@ def get_query_ok_actions(alarm_definition):
|
|||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_comma_separated_str_as_list(comma_separated_str):
|
||||
|
||||
if not comma_separated_str:
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
# 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
|
||||
from monasca.common import resource_api
|
||||
import monasca.expression_parser.alarm_expr_parser
|
||||
from monasca.openstack.common import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
@ -33,10 +35,9 @@ class Alarming(object):
|
|||
|
||||
super(Alarming, self).__init__()
|
||||
|
||||
self._message_queue \
|
||||
= resource_api.init_driver('monasca.messaging',
|
||||
cfg.CONF.messaging.driver,
|
||||
(['events']))
|
||||
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):
|
||||
|
@ -52,15 +53,17 @@ class Alarming(object):
|
|||
else:
|
||||
sub_alarm_dict[sub_alarm_row.alarm_id] = [sub_alarm_row]
|
||||
|
||||
# Forward declaration.
|
||||
alarm_deleted_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_deleted_event_msg = \
|
||||
self._build_sub_alarm_deleted_event_msg(
|
||||
sub_alarm_dict, prev_alarm_id)
|
||||
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]
|
||||
u'subAlarms': sub_alarms_deleted_event_msg]
|
||||
self._send_event(alarm_deleted_event_msg)
|
||||
|
||||
alarm_metrics_event_msg = []
|
||||
|
@ -99,7 +102,8 @@ class Alarming(object):
|
|||
|
||||
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]
|
||||
sub_expr = (monasca.expression_parser.alarm_expr_parser.
|
||||
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,
|
||||
|
|
|
@ -11,17 +11,19 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
from falcon.util.uri import parse_query_string
|
||||
import re
|
||||
|
||||
import falcon
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.api.alarms_api_v2 import AlarmsV2API
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.reference.alarming import Alarming
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.reference.resource import resource_try_catch_block
|
||||
|
||||
|
||||
|
@ -38,17 +40,20 @@ class Alarms(AlarmsV2API, Alarming):
|
|||
|
||||
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._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)
|
||||
|
@ -91,7 +96,7 @@ class Alarms(AlarmsV2API, Alarming):
|
|||
helpers.validate_authorization(req, self._default_authorized_roles)
|
||||
tenant_id = helpers.get_tenant_id(req)
|
||||
|
||||
query_parms = parse_query_string(req.query_string)
|
||||
query_parms = falcon.uri.parse_query_string(req.query_string)
|
||||
|
||||
result = self._alarm_list(req.uri, tenant_id, query_parms)
|
||||
|
||||
|
@ -101,6 +106,11 @@ class Alarms(AlarmsV2API, Alarming):
|
|||
@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)
|
||||
|
||||
|
@ -109,6 +119,53 @@ class Alarms(AlarmsV2API, Alarming):
|
|||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||
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)
|
||||
|
||||
result = self._alarm_history_list(tenant_id, start_timestamp,
|
||||
end_timestamp, query_parms)
|
||||
|
||||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||
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)
|
||||
|
||||
result = self._alarm_history(tenant_id, [id])
|
||||
|
||||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||
res.status = falcon.HTTP_200
|
||||
|
||||
@resource_try_catch_block
|
||||
def _alarm_history_list(self, tenant_id, start_timestamp,
|
||||
end_timestamp, query_parms):
|
||||
|
||||
# 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]
|
||||
|
||||
return self._metrics_repo.alarm_history(tenant_id, alarm_id_list,
|
||||
start_timestamp, end_timestamp)
|
||||
|
||||
@resource_try_catch_block
|
||||
def _alarm_history(self, tenant_id, alarm_id):
|
||||
|
||||
return self._metrics_repo.alarm_history(tenant_id, alarm_id)
|
||||
|
||||
@resource_try_catch_block
|
||||
def _alarm_delete(self, tenant_id, id):
|
||||
|
||||
|
@ -171,6 +228,8 @@ class Alarms(AlarmsV2API, Alarming):
|
|||
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:
|
||||
|
|
|
@ -17,37 +17,40 @@ import json
|
|||
import falcon
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.api import monasca_events_api_v2
|
||||
from monasca.common import resource_api
|
||||
from monasca.common.messaging import exceptions as message_queue_exceptions
|
||||
from monasca.common.messaging.message_formats import events_transform_factory
|
||||
from monasca.v2.common import utils
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import (
|
||||
events_request_body_schema as schemas_event)
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import \
|
||||
events_request_body_schema as schemas_event
|
||||
from monasca.v2.common import utils
|
||||
from monasca.v2.reference import helpers
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class Events(monasca_events_api_v2.EventsV2API):
|
||||
|
||||
def __init__(self, global_conf):
|
||||
|
||||
super(Events, self).__init__(global_conf)
|
||||
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._delegate_authorized_roles = \
|
||||
cfg.CONF.security.delegate_authorized_roles
|
||||
self._post_events_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles + \
|
||||
cfg.CONF.security.agent_authorized_roles
|
||||
self._event_transform = \
|
||||
events_transform_factory.create_events_transform()
|
||||
self._message_queue = \
|
||||
self._default_authorized_roles = (
|
||||
cfg.CONF.security.default_authorized_roles)
|
||||
self._delegate_authorized_roles = (
|
||||
cfg.CONF.security.delegate_authorized_roles)
|
||||
self._post_events_authorized_roles = (
|
||||
cfg.CONF.security.default_authorized_roles +
|
||||
cfg.CONF.security.agent_authorized_roles)
|
||||
self._event_transform = (
|
||||
events_transform_factory.create_events_transform())
|
||||
self._message_queue = (
|
||||
resource_api.init_driver('monasca.messaging',
|
||||
cfg.CONF.messaging.driver,
|
||||
['raw-events'])
|
||||
['raw-events']))
|
||||
|
||||
def _validate_event(self, event):
|
||||
"""Validates the event
|
||||
|
|
|
@ -11,25 +11,25 @@
|
|||
# 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 json
|
||||
from urlparse import urlparse
|
||||
import urlparse
|
||||
|
||||
import falcon
|
||||
from falcon.util.uri import parse_query_string
|
||||
import simplejson
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.v2.common.schemas import dimensions_schema
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import metric_name_schema
|
||||
from monasca.v2.common.schemas import dimensions_schema
|
||||
import simplejson
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def read_json_msg_body(req):
|
||||
"""
|
||||
Read the json_msg from the http request body and return them as JSON.
|
||||
"""Read the json_msg from the http request body and return them as JSON.
|
||||
|
||||
:param req: HTTP request object.
|
||||
:return: Returns the metrics as a JSON object.
|
||||
:raises falcon.HTTPBadRequest:
|
||||
|
@ -51,8 +51,7 @@ def validate_json_content_type(req):
|
|||
|
||||
|
||||
def is_in_role(req, authorized_roles):
|
||||
"""Determines if one or more of the X-ROLES is in the supplied
|
||||
authorized_roles.
|
||||
"""Is one or more of the X-ROLES in the supplied authorized_roles.
|
||||
|
||||
:param req: HTTP request object. Must contain "X-ROLES" in the HTTP
|
||||
request header.
|
||||
|
@ -107,7 +106,7 @@ def get_x_tenant_or_tenant_id(req, delegate_authorized_roles):
|
|||
:returns: Returns the cross tenant or tenant ID.
|
||||
"""
|
||||
if is_in_role(req, delegate_authorized_roles):
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
if 'tenant_id' in params:
|
||||
tenant_id = params['tenant_id']
|
||||
return tenant_id
|
||||
|
@ -115,12 +114,12 @@ def get_x_tenant_or_tenant_id(req, delegate_authorized_roles):
|
|||
|
||||
|
||||
def get_query_name(req, name_required=False):
|
||||
"""
|
||||
Returns the query param "name" if supplied.
|
||||
"""Returns the query param "name" if supplied.
|
||||
|
||||
:param req: HTTP request object.
|
||||
"""
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
if 'name' in params:
|
||||
name = params['name']
|
||||
return name
|
||||
|
@ -142,7 +141,7 @@ def get_query_dimensions(req):
|
|||
:raises falcon.HTTPBadRequest: If dimensions are malformed.
|
||||
"""
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
dimensions = {}
|
||||
if 'dimensions' in params:
|
||||
dimensions_str = params['dimensions']
|
||||
|
@ -160,25 +159,31 @@ def get_query_dimensions(req):
|
|||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||
|
||||
|
||||
def get_query_starttime_timestamp(req):
|
||||
def get_query_starttime_timestamp(req, required=True):
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
if 'start_time' in params:
|
||||
return _convert_time_string(params['start_time'])
|
||||
else:
|
||||
raise Exception("Missing start time")
|
||||
if required:
|
||||
raise Exception("Missing start time")
|
||||
else:
|
||||
return None
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||
|
||||
|
||||
def get_query_endtime_timestamp(req):
|
||||
def get_query_endtime_timestamp(req, required=True):
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
if 'end_time' in params:
|
||||
return _convert_time_string(params['end_time'])
|
||||
else:
|
||||
return None
|
||||
if required:
|
||||
raise Exception("Missing end time")
|
||||
else:
|
||||
return None
|
||||
except Exception as ex:
|
||||
LOG.debug(ex)
|
||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||
|
@ -192,7 +197,7 @@ def _convert_time_string(date_time_string):
|
|||
|
||||
def get_query_statistics(req):
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
if 'statistics' in params:
|
||||
statistics = params['statistics'].split(',')
|
||||
statistics = [statistic.lower() for statistic in statistics]
|
||||
|
@ -209,7 +214,7 @@ def get_query_statistics(req):
|
|||
|
||||
def get_query_period(req):
|
||||
try:
|
||||
params = parse_query_string(req.query_string)
|
||||
params = falcon.uri.parse_query_string(req.query_string)
|
||||
if 'period' in params:
|
||||
return params['period']
|
||||
else:
|
||||
|
|
|
@ -16,22 +16,17 @@ import json
|
|||
|
||||
import falcon
|
||||
from oslo.config import cfg
|
||||
from stevedore import driver
|
||||
|
||||
from monasca.openstack.common import log
|
||||
from monasca.api import monasca_api_v2
|
||||
from monasca.common import resource_api
|
||||
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.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import \
|
||||
metrics_request_body_schema as schemas_metrics
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
|
||||
from monasca.v2.reference import helpers
|
||||
from monasca.v2.reference.helpers import read_json_msg_body
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
@ -41,21 +36,23 @@ 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._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)
|
||||
|
||||
|
@ -90,7 +87,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
except message_queue_exceptions.MessageQueueException as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
ex.message, 60)
|
||||
|
||||
if isinstance(metrics, list):
|
||||
for metric in metrics:
|
||||
|
@ -112,7 +109,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
ex.message, 60)
|
||||
|
||||
def _measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp):
|
||||
|
@ -124,7 +121,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
ex.message, 60)
|
||||
|
||||
def _metric_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||
end_timestamp, statistics, period):
|
||||
|
@ -137,7 +134,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||
ex.message)
|
||||
ex.message, 60)
|
||||
|
||||
@resource_api.Restify('/v2.0/metrics/', method='post')
|
||||
def do_post_metrics(self, req, res):
|
||||
|
@ -146,9 +143,9 @@ class Metrics(monasca_api_v2.V2API):
|
|||
self._post_metrics_authorized_roles)
|
||||
metrics = helpers.read_http_resource(req)
|
||||
self._validate_metrics(metrics)
|
||||
tenant_id = \
|
||||
tenant_id = (
|
||||
helpers.get_x_tenant_or_tenant_id(req,
|
||||
self._delegate_authorized_roles)
|
||||
self._delegate_authorized_roles))
|
||||
transformed_metrics = self._metrics_transform(metrics, tenant_id,
|
||||
self._region)
|
||||
self._send_metrics(transformed_metrics)
|
||||
|
@ -175,7 +172,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
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)
|
||||
end_timestamp = helpers.get_query_endtime_timestamp(req, False)
|
||||
result = self._measurement_list(tenant_id, name, dimensions,
|
||||
start_timestamp, end_timestamp)
|
||||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||
|
@ -190,7 +187,7 @@ class Metrics(monasca_api_v2.V2API):
|
|||
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)
|
||||
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,
|
||||
|
|
|
@ -12,22 +12,19 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# TODO: Used simplejson to read the yaml as simplejson transforms to "str"
|
||||
# not "unicode"
|
||||
|
||||
import json
|
||||
|
||||
import falcon
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.api import monasca_notifications_api_v2
|
||||
from monasca.common.repositories import exceptions as repository_exceptions
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
from monasca.openstack.common import uuidutils
|
||||
from monasca.api import monasca_notifications_api_v2
|
||||
from monasca.common import resource_api
|
||||
from monasca.common.repositories import exceptions as repository_exceptions
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import \
|
||||
notifications_request_body_schema as schemas_notifications
|
||||
from monasca.v2.common.schemas import (exceptions as schemas_exceptions)
|
||||
from monasca.v2.common.schemas import (
|
||||
notifications_request_body_schema as schemas_notifications)
|
||||
from monasca.v2.reference import helpers
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
@ -37,8 +34,8 @@ 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._default_authorized_roles = (
|
||||
cfg.CONF.security.default_authorized_roles)
|
||||
self._notifications_repo = resource_api.init_driver(
|
||||
'monasca.repositories', cfg.CONF.repositories.notifications_driver)
|
||||
|
||||
|
@ -66,8 +63,9 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
|||
address = notification['address']
|
||||
if self._notifications_repo.exists(tenant_id, name):
|
||||
raise falcon.HTTPConflict('Conflict', (
|
||||
'Notification Method already exists: tenant_id=%s name=%s' % (
|
||||
tenant_id, name)), code=409)
|
||||
'Notification Method already exists: tenant_id=%s '
|
||||
'name=%s' % (
|
||||
tenant_id, name)), code=409)
|
||||
self._notifications_repo.create_notification(id, tenant_id, name,
|
||||
notification_type,
|
||||
address)
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
# 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 monasca.common.messaging import exceptions
|
||||
from monasca.common.repositories.exceptions import DoesNotExistException
|
||||
|
||||
from monasca.common.repositories import exceptions
|
||||
from monasca.openstack.common import log
|
||||
|
||||
|
||||
|
@ -17,7 +30,7 @@ def resource_try_catch_block(fun):
|
|||
|
||||
except falcon.HTTPNotFound:
|
||||
raise
|
||||
except DoesNotExistException:
|
||||
except exceptions.DoesNotExistException:
|
||||
raise falcon.HTTPNotFound
|
||||
except falcon.HTTPBadRequest:
|
||||
raise
|
||||
|
|
|
@ -12,34 +12,32 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# TODO: Used simplejson to read the yaml as simplejson transforms to "str"
|
||||
# not "unicode"
|
||||
|
||||
import json
|
||||
import simplejson
|
||||
|
||||
import falcon
|
||||
from oslo.config import cfg
|
||||
|
||||
from monasca.api import monasca_transforms_api_v2
|
||||
from monasca.common.repositories import exceptions as repository_exceptions
|
||||
from monasca.common import resource_api
|
||||
from monasca.openstack.common import log
|
||||
from monasca.openstack.common import uuidutils
|
||||
from monasca.api import monasca_transforms_api_v2
|
||||
from monasca.common import resource_api
|
||||
from monasca.common.repositories import exceptions as repository_exceptions
|
||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||
from monasca.v2.common.schemas import \
|
||||
transforms_request_body_schema as schemas_transforms
|
||||
from monasca.v2.common.schemas import (exceptions as schemas_exceptions)
|
||||
from monasca.v2.common.schemas import (
|
||||
transforms_request_body_schema as schemas_transforms)
|
||||
from monasca.v2.reference import helpers
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
||||
def __init__(self, global_conf):
|
||||
|
||||
super(Transforms, self).__init__(global_conf)
|
||||
self._region = cfg.CONF.region
|
||||
self._default_authorized_roles = \
|
||||
cfg.CONF.security.default_authorized_roles
|
||||
self._default_authorized_roles = (
|
||||
cfg.CONF.security.default_authorized_roles)
|
||||
self._transforms_repo = resource_api.init_driver(
|
||||
'monasca.repositories', cfg.CONF.repositories.transforms_driver)
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@ gunicorn>=19.1.0
|
|||
oslo.config>=1.2.1
|
||||
ujson>=1.33
|
||||
Pyparsing>=2.0.3
|
||||
pyodbc>=3.0.7
|
||||
influxdb>=0.1.12
|
||||
|
|
|
@ -9,6 +9,7 @@ pep8<=1.5.6
|
|||
httplib2>=0.7.5
|
||||
mock>=1.0
|
||||
mox>=0.5.3
|
||||
nose
|
||||
# Docs Requirements
|
||||
oslosphinx
|
||||
oslotest
|
||||
|
|
12
tox.ini
12
tox.ini
|
@ -4,14 +4,12 @@ skipsdist = True
|
|||
envlist = py27,py33,pep8
|
||||
|
||||
[testenv]
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
usedevelop = True
|
||||
install_command = pip install -U {opts} {packages}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
install_command = pip install -U --allow-external pytidylib --allow-insecure pytidylib --allow-external netifaces --allow-insecure netifaces {opts} {packages}
|
||||
usedevelop = True
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
commands = python setup.py testr --slowest --testr-args='--concurrency 1 {posargs}'
|
||||
downloadcache = {toxworkdir}/_download
|
||||
whitelist_externals = bash
|
||||
commands = nosetests
|
||||
|
||||
[testenv:cover]
|
||||
setenv = NOSE_WITH_COVERAGE=1
|
||||
|
@ -32,8 +30,6 @@ commands = python setup.py build_sphinx
|
|||
commands = {posargs}
|
||||
|
||||
[flake8]
|
||||
# H305 imports not grouped correctly
|
||||
ignore = H305
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,./monasca/openstack/common,*lib/python*,*egg,tools,build
|
||||
show-source = True
|
||||
|
|
Loading…
Reference in New Issue