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')
|
@resource_api.Restify('/v2.0/alarms/{id}', method='get')
|
||||||
def do_get_alarm_by_id(self, req, res, id):
|
def do_get_alarm_by_id(self, req, res, id):
|
||||||
res.status = '501 Not Implemented'
|
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')
|
@resource_api.Restify('/v2.0/metrics/statistics', method='get')
|
||||||
def do_get_statistics(self, req, res):
|
def do_get_statistics(self, req, res):
|
||||||
res.status = '501 Not Implemented'
|
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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from stevedore import driver
|
|
||||||
import os
|
import os
|
||||||
from monasca.common import resource_api
|
from wsgiref import simple_server
|
||||||
from monasca.openstack.common import log
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
from oslo.config import types
|
from oslo.config import types
|
||||||
from paste.deploy import loadapp
|
import paste.deploy
|
||||||
from wsgiref import simple_server
|
|
||||||
|
from monasca.common import resource_api
|
||||||
|
from monasca.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
METRICS_DISPATCHER_NAMESPACE = 'monasca.metrics_dispatcher'
|
METRICS_DISPATCHER_NAMESPACE = 'monasca.metrics_dispatcher'
|
||||||
ALARM_DEFINITIONS_DISPATCHER_NAMESPACE = 'monasca.alarm_definitions_dispatcher'
|
ALARM_DEFINITIONS_DISPATCHER_NAMESPACE = 'monasca.alarm_definitions_dispatcher'
|
||||||
|
@ -183,6 +185,8 @@ def api_app(conf):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
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 = simple_server.make_server('127.0.0.1', 9000, wsgi_app)
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
import time
|
||||||
|
|
||||||
from kafka import client
|
from kafka import client
|
||||||
from kafka import common
|
from kafka import common
|
||||||
from kafka import consumer
|
from kafka import consumer
|
||||||
from kafka import producer
|
from kafka import producer
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
import time
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
|
@ -12,5 +12,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
class MessageQueueException(Exception):
|
class MessageQueueException(Exception):
|
||||||
pass
|
pass
|
|
@ -11,16 +11,16 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
import time
|
||||||
|
|
||||||
from kafka import client
|
from kafka import client
|
||||||
from kafka import common
|
from kafka import common
|
||||||
from kafka import producer
|
from kafka import producer
|
||||||
from oslo.config import cfg
|
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 exceptions
|
||||||
|
from monasca.common.messaging import publisher
|
||||||
|
from monasca.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
|
@ -12,5 +12,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
def transform(events, tenant_id, region):
|
def transform(events, tenant_id, region):
|
||||||
raise NotImplemented()
|
raise NotImplemented()
|
|
@ -12,5 +12,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
def transform(metrics, tenant_id, region):
|
def transform(metrics, tenant_id, region):
|
||||||
raise NotImplemented()
|
raise NotImplemented()
|
|
@ -13,15 +13,17 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo.config import cfg
|
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.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():
|
def create_events_transform():
|
||||||
message_format = cfg.CONF.messaging.events_message_format
|
message_format = cfg.CONF.messaging.events_message_format
|
||||||
if message_format == 'reference':
|
if message_format == 'reference':
|
||||||
return reference_events.transform
|
return ref_events.transform
|
||||||
elif message_format == 'cadf':
|
elif message_format == 'cadf':
|
||||||
return cadf_events.transform
|
return cadf_events.transform
|
||||||
else:
|
else:
|
||||||
return identity_events.transform
|
return ident_events.transform
|
|
@ -12,5 +12,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
class TransformationException(Exception):
|
class TransformationException(Exception):
|
||||||
pass
|
pass
|
|
@ -12,7 +12,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def transform(events, tenant_id, region):
|
def transform(events, tenant_id, region):
|
||||||
return events
|
return events
|
|
@ -12,7 +12,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def transform(metrics, tenant_id, region):
|
def transform(metrics, tenant_id, region):
|
||||||
return metrics
|
return metrics
|
|
@ -13,15 +13,17 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo.config import cfg
|
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.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():
|
def create_metrics_transform():
|
||||||
metrics_message_format = cfg.CONF.messaging.metrics_message_format
|
metrics_message_format = cfg.CONF.messaging.metrics_message_format
|
||||||
if metrics_message_format == 'reference':
|
if metrics_message_format == 'reference':
|
||||||
return reference_metrics.transform
|
return r_metrics.transform
|
||||||
elif metrics_message_format == 'cadf':
|
elif metrics_message_format == 'cadf':
|
||||||
return cadf_metrics.transform
|
return cadf_metrics.transform
|
||||||
else:
|
else:
|
||||||
return identity_metrics.transform
|
return id_metrics.transform
|
|
@ -12,7 +12,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from datetime import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
def transform(event, tenant_id, region):
|
def transform(event, tenant_id, region):
|
||||||
|
|
|
@ -12,17 +12,13 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from datetime import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
def transform(metrics, tenant_id, region):
|
def transform(metrics, tenant_id, region):
|
||||||
transformed_metric = {
|
transformed_metric = {'metric': {},
|
||||||
'metric': {},
|
'meta': {'tenantId': tenant_id, 'region': region},
|
||||||
'meta': {
|
'creation_time': datetime.now()}
|
||||||
'tenantId': tenant_id,
|
|
||||||
'region': region
|
|
||||||
},
|
|
||||||
'creation_time': datetime.now()
|
|
||||||
}
|
|
||||||
|
|
||||||
if isinstance(metrics, list):
|
if isinstance(metrics, list):
|
||||||
transformed_metrics = []
|
transformed_metrics = []
|
||||||
|
|
|
@ -13,16 +13,16 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class Publisher(object):
|
class Publisher(object):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def send_message(self, message):
|
def send_message(self, message):
|
||||||
'''
|
"""Sends the message using the message queue.
|
||||||
Sends the message using the message queue.
|
|
||||||
:param message: Message to send.
|
:param message: Message to send.
|
||||||
'''
|
"""
|
||||||
return
|
return
|
|
@ -12,20 +12,20 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class AlarmDefinitionsRepository(object):
|
class AlarmDefinitionsRepository(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
super(AlarmDefinitionsRepository, self).__init__()
|
super(AlarmDefinitionsRepository, self).__init__()
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_alarm_definition(self, tenant_id, name,
|
def create_alarm_definition(self, tenant_id, name, expression,
|
||||||
expression, sub_expr_list, description, severity, match_by, alarm_actions,
|
sub_expr_list, description, severity, match_by,
|
||||||
undetermined_actions, ok_action):
|
alarm_actions, undetermined_actions,
|
||||||
|
ok_action):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
|
|
@ -12,9 +12,33 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class AlarmsRepository(object):
|
class AlarmsRepository(object):
|
||||||
|
|
||||||
|
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
|
pass
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,10 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
class RepositoryException(Exception):
|
class RepositoryException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DoesNotExistException(RepositoryException):
|
class DoesNotExistException(RepositoryException):
|
||||||
pass
|
pass
|
|
@ -12,13 +12,12 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
from time import strftime
|
|
||||||
from time import gmtime
|
|
||||||
|
|
||||||
from influxdb import InfluxDBClient
|
from influxdb import client
|
||||||
from influxdb.client import InfluxDBClientError
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
from monasca.common.repositories import exceptions
|
from monasca.common.repositories import exceptions
|
||||||
|
@ -30,11 +29,12 @@ LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MetricsRepository(metrics_repository.MetricsRepository):
|
class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.conf = cfg.CONF
|
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.ip_address, self.conf.influxdb.port,
|
||||||
self.conf.influxdb.user, self.conf.influxdb.password,
|
self.conf.influxdb.user, self.conf.influxdb.password,
|
||||||
self.conf.influxdb.database_name)
|
self.conf.influxdb.database_name)
|
||||||
|
@ -144,8 +144,8 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
|
|
||||||
def _decode_influxdb_serie_name_list(self, series_names):
|
def _decode_influxdb_serie_name_list(self, series_names):
|
||||||
|
|
||||||
"""
|
"""Example series_names from InfluxDB.
|
||||||
Example series_names from InfluxDB.
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"points": [
|
"points": [
|
||||||
|
@ -178,11 +178,11 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
|
|
||||||
return json_metric_list
|
return json_metric_list
|
||||||
|
|
||||||
|
|
||||||
def _decode_influxdb_serie_name(self, serie_name):
|
def _decode_influxdb_serie_name(self, serie_name):
|
||||||
|
|
||||||
"""
|
"""Decodes a serie name from InfluxDB.
|
||||||
Decodes a serie name from InfluxDB. The raw serie name is
|
|
||||||
|
The raw serie name is
|
||||||
formed by url encoding the name, tenant id, region, and dimensions,
|
formed by url encoding the name, tenant id, region, and dimensions,
|
||||||
and concatenating them into a quasi URL query string.
|
and concatenating them into a quasi URL query string.
|
||||||
|
|
||||||
|
@ -227,11 +227,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
|
|
||||||
return metric
|
return metric
|
||||||
|
|
||||||
|
|
||||||
def measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
def measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
||||||
end_timestamp):
|
end_timestamp):
|
||||||
"""
|
"""Example result from InfluxDB.
|
||||||
Example result from InfluxDB.
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"points": [
|
"points": [
|
||||||
|
@ -285,9 +284,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = self.influxdb_client.query(query, 's')
|
result = self.influxdb_client.query(query, 's')
|
||||||
except InfluxDBClientError as ex:
|
except client.InfluxDBClientError as ex:
|
||||||
if ex.code == 400 and ex.content == 'Couldn\'t look up ' \
|
# check for non-existent serie name.
|
||||||
'columns':
|
msg = "Couldn't look up columns"
|
||||||
|
if ex.code == 400 and ex.content == (msg):
|
||||||
return json_measurement_list
|
return json_measurement_list
|
||||||
else:
|
else:
|
||||||
raise ex
|
raise ex
|
||||||
|
@ -307,8 +307,9 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
columns]
|
columns]
|
||||||
|
|
||||||
# format the utc date in the points
|
# format the utc date in the points
|
||||||
fmtd_pts = [[strftime("%Y-%m-%dT%H:%M:%SZ", gmtime(point[0])),
|
fmtd_pts = [[time.strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||||
point[1], point[2]] for point in serie['points']]
|
time.gmtime(point[0])), point[1],
|
||||||
|
point[2]] for point in serie['points']]
|
||||||
|
|
||||||
measurement = {"name": metric['name'],
|
measurement = {"name": metric['name'],
|
||||||
"dimensions": metric['dimensions'],
|
"dimensions": metric['dimensions'],
|
||||||
|
@ -322,7 +323,6 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise exceptions.RepositoryException(ex)
|
raise exceptions.RepositoryException(ex)
|
||||||
|
|
||||||
|
|
||||||
def metrics_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
def metrics_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||||
end_timestamp, statistics, period):
|
end_timestamp, statistics, period):
|
||||||
|
|
||||||
|
@ -336,9 +336,10 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = self.influxdb_client.query(query, 's')
|
result = self.influxdb_client.query(query, 's')
|
||||||
except InfluxDBClientError as ex:
|
except client.InfluxDBClientError as ex:
|
||||||
if ex.code == 400 and ex.content == 'Couldn\'t look up ' \
|
# check for non-existent serie name.
|
||||||
'columns':
|
msg = "Couldn't look up columns"
|
||||||
|
if ex.code == 400 and ex.content == (msg):
|
||||||
return json_statistics_list
|
return json_statistics_list
|
||||||
else:
|
else:
|
||||||
raise ex
|
raise ex
|
||||||
|
@ -357,8 +358,9 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
columns = [column.replace('time', 'timestamp') for column in
|
columns = [column.replace('time', 'timestamp') for column in
|
||||||
columns]
|
columns]
|
||||||
|
|
||||||
fmtd_pts_list_list = [[strftime("%Y-%m-%dT%H:%M:%SZ",
|
fmtd_pts_list_list = [[time.strftime("%Y-%m-%dT%H:%M:%SZ",
|
||||||
gmtime(pts_list[0]))] + pts_list[1:]
|
time.gmtime(pts_list[
|
||||||
|
0]))] + pts_list[1:]
|
||||||
for pts_list in serie['points']]
|
for pts_list in serie['points']]
|
||||||
|
|
||||||
measurement = {"name": metric['name'],
|
measurement = {"name": metric['name'],
|
||||||
|
@ -373,3 +375,118 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise exceptions.RepositoryException(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
|
@abc.abstractmethod
|
||||||
def metrics_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
def metrics_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||||
end_timestamp, statistics):
|
end_timestamp, statistics, period):
|
||||||
pass
|
pass
|
|
@ -13,20 +13,19 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from monasca.common.repositories import alarm_definitions_repository
|
from monasca.common.repositories import alarm_definitions_repository as adr
|
||||||
from monasca.common.repositories.exceptions import DoesNotExistException
|
from monasca.common.repositories import exceptions
|
||||||
from monasca.common.repositories.mysql.mysql_repository import MySQLRepository
|
from monasca.common.repositories.mysql import mysql_repository
|
||||||
from monasca.common.repositories.mysql.mysql_repository import mysql_try_catch_block
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.openstack.common import uuidutils
|
from monasca.openstack.common import uuidutils
|
||||||
from monasca.common.repositories import exceptions
|
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AlarmDefinitionsRepository(MySQLRepository,
|
class AlarmDefinitionsRepository(mysql_repository.MySQLRepository,
|
||||||
alarm_definitions_repository.AlarmDefinitionsRepository):
|
adr.AlarmDefinitionsRepository):
|
||||||
|
|
||||||
base_query = """
|
base_query = """
|
||||||
select ad.id, ad.name, ad.description, ad.expression,
|
select ad.id, ad.name, ad.description, ad.expression,
|
||||||
ad.match_by, ad.severity, ad.actions_enabled,
|
ad.match_by, ad.severity, ad.actions_enabled,
|
||||||
|
@ -56,7 +55,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
super(AlarmDefinitionsRepository, self).__init__()
|
super(AlarmDefinitionsRepository, self).__init__()
|
||||||
|
|
||||||
@mysql_try_catch_block
|
@mysql_repository.mysql_try_catch_block
|
||||||
def get_alarm_definition(self, tenant_id, id):
|
def get_alarm_definition(self, tenant_id, id):
|
||||||
|
|
||||||
parms = [tenant_id, id]
|
parms = [tenant_id, id]
|
||||||
|
@ -72,9 +71,9 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
if rows:
|
if rows:
|
||||||
return rows[0]
|
return rows[0]
|
||||||
else:
|
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):
|
def get_alarm_definitions(self, tenant_id, name, dimensions):
|
||||||
|
|
||||||
parms = [tenant_id]
|
parms = [tenant_id]
|
||||||
|
@ -113,8 +112,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
return self._execute_query(query, parms)
|
return self._execute_query(query, parms)
|
||||||
|
|
||||||
|
@mysql_repository.mysql_try_catch_block
|
||||||
@mysql_try_catch_block
|
|
||||||
def get_sub_alarms(self, tenant_id, alarm_definition_id):
|
def get_sub_alarms(self, tenant_id, alarm_definition_id):
|
||||||
|
|
||||||
parms = [tenant_id, alarm_definition_id]
|
parms = [tenant_id, alarm_definition_id]
|
||||||
|
@ -131,7 +129,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
return self._execute_query(query, parms)
|
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):
|
def get_alarm_metrics(self, tenant_id, alarm_definition_id):
|
||||||
|
|
||||||
parms = [tenant_id, alarm_definition_id]
|
parms = [tenant_id, alarm_definition_id]
|
||||||
|
@ -156,7 +154,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
return self._execute_query(query, parms)
|
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):
|
def delete_alarm_definition(self, tenant_id, alarm_definition_id):
|
||||||
"""Soft delete the alarm definition.
|
"""Soft delete the alarm definition.
|
||||||
|
|
||||||
|
@ -187,7 +185,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@mysql_try_catch_block
|
@mysql_repository.mysql_try_catch_block
|
||||||
def get_sub_alarm_definitions(self, alarm_definition_id):
|
def get_sub_alarm_definitions(self, alarm_definition_id):
|
||||||
|
|
||||||
parms = [alarm_definition_id]
|
parms = [alarm_definition_id]
|
||||||
|
@ -206,7 +204,7 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
return self._execute_query(query, parms)
|
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,
|
def create_alarm_definition(self, tenant_id, name, expression,
|
||||||
sub_expr_list, description, severity, match_by,
|
sub_expr_list, description, severity, match_by,
|
||||||
alarm_actions, undetermined_actions,
|
alarm_actions, undetermined_actions,
|
||||||
|
@ -275,7 +273,6 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
|
|
||||||
return alarm_definition_id
|
return alarm_definition_id
|
||||||
|
|
||||||
|
|
||||||
def _insert_into_alarm_action(self, cursor, alarm_definition_id, actions,
|
def _insert_into_alarm_action(self, cursor, alarm_definition_id, actions,
|
||||||
alarm_state):
|
alarm_state):
|
||||||
for action in actions:
|
for action in actions:
|
||||||
|
@ -293,5 +290,3 @@ class AlarmDefinitionsRepository(MySQLRepository,
|
||||||
action_id)
|
action_id)
|
||||||
values(?,?,?)""", alarm_definition_id,
|
values(?,?,?)""", alarm_definition_id,
|
||||||
alarm_state.encode('utf8'), action.encode('utf8'))
|
alarm_state.encode('utf8'), action.encode('utf8'))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,18 +11,18 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
from monasca.common.repositories.exceptions import DoesNotExistException
|
|
||||||
|
|
||||||
from monasca.common.repositories import alarms_repository
|
from monasca.common.repositories import alarms_repository
|
||||||
from monasca.common.repositories.mysql.mysql_repository import MySQLRepository
|
from monasca.common.repositories import exceptions
|
||||||
from monasca.common.repositories.mysql.mysql_repository import mysql_try_catch_block
|
from monasca.common.repositories.mysql import mysql_repository
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
class AlarmsRepository(mysql_repository.MySQLRepository,
|
||||||
|
alarms_repository.AlarmsRepository):
|
||||||
|
|
||||||
base_query = """
|
base_query = """
|
||||||
select distinct a.id as alarm_id, a.state,
|
select distinct a.id as alarm_id, a.state,
|
||||||
|
@ -47,7 +47,7 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
||||||
|
|
||||||
super(AlarmsRepository, self).__init__()
|
super(AlarmsRepository, self).__init__()
|
||||||
|
|
||||||
@mysql_try_catch_block
|
@mysql_repository.mysql_try_catch_block
|
||||||
def get_alarm_metrics(self, alarm_id):
|
def get_alarm_metrics(self, alarm_id):
|
||||||
|
|
||||||
parms = [alarm_id]
|
parms = [alarm_id]
|
||||||
|
@ -70,7 +70,7 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
||||||
|
|
||||||
return self._execute_query(query, parms)
|
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):
|
def get_sub_alarms(self, tenant_id, alarm_id):
|
||||||
|
|
||||||
parms = [tenant_id, alarm_id]
|
parms = [tenant_id, alarm_id]
|
||||||
|
@ -87,7 +87,7 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
||||||
|
|
||||||
return self._execute_query(query, parms)
|
return self._execute_query(query, parms)
|
||||||
|
|
||||||
@mysql_try_catch_block
|
@mysql_repository.mysql_try_catch_block
|
||||||
def delete_alarm(self, tenant_id, id):
|
def delete_alarm(self, tenant_id, id):
|
||||||
|
|
||||||
parms = [tenant_id, id]
|
parms = [tenant_id, id]
|
||||||
|
@ -109,11 +109,11 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
||||||
cursor.execute(query, parms)
|
cursor.execute(query, parms)
|
||||||
|
|
||||||
if cursor.rowcount < 1:
|
if cursor.rowcount < 1:
|
||||||
raise DoesNotExistException
|
raise exceptions.DoesNotExistException
|
||||||
|
|
||||||
self._commit_close_cnxn(cnxn)
|
self._commit_close_cnxn(cnxn)
|
||||||
|
|
||||||
@mysql_try_catch_block
|
@mysql_repository.mysql_try_catch_block
|
||||||
def get_alarm(self, tenant_id, id):
|
def get_alarm(self, tenant_id, id):
|
||||||
|
|
||||||
parms = [tenant_id, id]
|
parms = [tenant_id, id]
|
||||||
|
@ -128,11 +128,11 @@ class AlarmsRepository(MySQLRepository, alarms_repository.AlarmsRepository):
|
||||||
rows = self._execute_query(query, parms)
|
rows = self._execute_query(query, parms)
|
||||||
|
|
||||||
if not rows:
|
if not rows:
|
||||||
raise DoesNotExistException
|
raise exceptions.DoesNotExistException
|
||||||
else:
|
else:
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
@mysql_try_catch_block
|
@mysql_repository.mysql_try_catch_block
|
||||||
def get_alarms(self, tenant_id, query_parms):
|
def get_alarms(self, tenant_id, query_parms):
|
||||||
|
|
||||||
parms = [tenant_id]
|
parms = [tenant_id]
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from monasca.openstack.common import log
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
|
from monasca.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
db = peewee.MySQLDatabase(cfg.CONF.mysql.database_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
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import datetime
|
|
||||||
import pyodbc
|
|
||||||
from monasca.common.repositories.exceptions import DoesNotExistException
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
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.common.repositories import exceptions
|
||||||
|
from monasca.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MySQLRepository(object):
|
class MySQLRepository(object):
|
||||||
|
|
||||||
database_driver = 'MySQL ODBC 5.3 ANSI Driver'
|
database_driver = 'MySQL ODBC 5.3 ANSI Driver'
|
||||||
database_cnxn_template = 'DRIVER={' \
|
database_cnxn_template = ('DRIVER={'
|
||||||
'%s};Server=%s;CHARSET=UTF8;Database=%s;Uid=%s' \
|
'%s};Server=%s;CHARSET=UTF8;Database=%s;Uid=%s'
|
||||||
';Pwd=%s'
|
';Pwd=%s')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
@ -65,7 +60,6 @@ class MySQLRepository(object):
|
||||||
cnxn.commit()
|
cnxn.commit()
|
||||||
cnxn.close()
|
cnxn.close()
|
||||||
|
|
||||||
|
|
||||||
def _execute_query(self, query, parms):
|
def _execute_query(self, query, parms):
|
||||||
|
|
||||||
cnxn, cursor = self._get_cnxn_cursor_tuple()
|
cnxn, cursor = self._get_cnxn_cursor_tuple()
|
||||||
|
@ -87,7 +81,7 @@ def mysql_try_catch_block(fun):
|
||||||
|
|
||||||
return fun(*args, **kwargs)
|
return fun(*args, **kwargs)
|
||||||
|
|
||||||
except DoesNotExistException:
|
except exceptions.DoesNotExistException:
|
||||||
raise
|
raise
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
|
|
|
@ -13,11 +13,14 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import datetime
|
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 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__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -55,7 +58,7 @@ class NotificationsRepository(
|
||||||
self, id, tenant_id, name, notification_type, address):
|
self, id, tenant_id, name, notification_type, address):
|
||||||
try:
|
try:
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
q = Notification_Method.create(
|
Notification_Method.create(
|
||||||
id=id,
|
id=id,
|
||||||
tenant_id=tenant_id,
|
tenant_id=tenant_id,
|
||||||
name=name,
|
name=name,
|
||||||
|
@ -73,7 +76,6 @@ class NotificationsRepository(
|
||||||
Notification_Method.tenant_id == tenant_id)
|
Notification_Method.tenant_id == tenant_id)
|
||||||
results = q.execute()
|
results = q.execute()
|
||||||
|
|
||||||
notifications = []
|
|
||||||
notifications = [
|
notifications = [
|
||||||
self.notification_from_result(result) for result in results]
|
self.notification_from_result(result) for result in results]
|
||||||
return notifications
|
return notifications
|
||||||
|
@ -82,7 +84,6 @@ class NotificationsRepository(
|
||||||
raise exceptions.RepositoryException(ex)
|
raise exceptions.RepositoryException(ex)
|
||||||
|
|
||||||
def delete_notification(self, tenant_id, notification_id):
|
def delete_notification(self, tenant_id, notification_id):
|
||||||
num_rows_deleted = 0
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
q = Notification_Method.delete().where(
|
q = Notification_Method.delete().where(
|
||||||
|
@ -113,7 +114,6 @@ class NotificationsRepository(
|
||||||
def update_notification(
|
def update_notification(
|
||||||
self, id, tenant_id, name, notification_type, address):
|
self, id, tenant_id, name, notification_type, address):
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
num_rows_updated = 0
|
|
||||||
try:
|
try:
|
||||||
q = Notification_Method.update(
|
q = Notification_Method.update(
|
||||||
name=name,
|
name=name,
|
||||||
|
|
|
@ -12,11 +12,13 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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 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__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -32,11 +34,14 @@ class Transform(model.Model):
|
||||||
updated_at = peewee.DateTimeField()
|
updated_at = peewee.DateTimeField()
|
||||||
deleted_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:
|
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()
|
q.save()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(str(ex))
|
LOG.exception(str(ex))
|
||||||
|
@ -49,13 +54,10 @@ class TransformsRepository(transforms_repository.TransformsRepository):
|
||||||
|
|
||||||
transforms = []
|
transforms = []
|
||||||
for result in results:
|
for result in results:
|
||||||
transform = {
|
transform = {'id': result.id, 'name': result.name,
|
||||||
'id': result.id,
|
|
||||||
'name': result.name,
|
|
||||||
'description': result.description,
|
'description': result.description,
|
||||||
'specification': result.specification,
|
'specification': result.specification,
|
||||||
'enabled': result.enabled
|
'enabled': result.enabled}
|
||||||
}
|
|
||||||
transforms.append(transform)
|
transforms.append(transform)
|
||||||
return transforms
|
return transforms
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
@ -66,7 +68,8 @@ class TransformsRepository(transforms_repository.TransformsRepository):
|
||||||
num_rows_deleted = 0
|
num_rows_deleted = 0
|
||||||
|
|
||||||
try:
|
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()
|
num_rows_deleted = q.execute()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(str(ex))
|
LOG.exception(str(ex))
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,15 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class TransformsRepository(object):
|
class TransformsRepository(object):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@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
|
return
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from falcon import api_helpers
|
from falcon import api_helpers
|
||||||
|
from stevedore import driver
|
||||||
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from stevedore import driver
|
|
||||||
|
|
||||||
RESOURCE_METHOD_FLAG = 'fab05a04-b861-4651-bd0c-9cb3eb9a6088'
|
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 driver_name: the driver name (in monasca.conf)
|
||||||
:param invoke_args: args to pass to the driver (a tuple)
|
:param invoke_args: args to pass to the driver (a tuple)
|
||||||
"""
|
"""
|
||||||
mgr = driver.DriverManager(
|
mgr = driver.DriverManager(namespace=namespace, name=driver_name,
|
||||||
namespace = namespace,
|
invoke_on_load=True,
|
||||||
name = driver_name,
|
invoke_args=drv_invoke_args)
|
||||||
invoke_on_load = True,
|
|
||||||
invoke_args = drv_invoke_args
|
|
||||||
)
|
|
||||||
return mgr.driver
|
return mgr.driver
|
||||||
|
|
||||||
|
|
||||||
class Restify(object):
|
class Restify(object):
|
||||||
|
|
||||||
def __init__(self, path='', method='GET'):
|
def __init__(self, path='', method='GET'):
|
||||||
if not path:
|
if not path:
|
||||||
raise Exception('Path has to be specified.')
|
raise Exception('Path has to be specified.')
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,22 +16,13 @@
|
||||||
import itertools
|
import itertools
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pyparsing import CaselessLiteral
|
import pyparsing
|
||||||
from pyparsing import alphanums
|
|
||||||
from pyparsing import delimitedList
|
|
||||||
from pyparsing import Forward
|
|
||||||
from pyparsing import Group
|
|
||||||
from pyparsing import Literal
|
|
||||||
from pyparsing import nums
|
|
||||||
from pyparsing import opAssoc
|
|
||||||
from pyparsing import operatorPrecedence
|
|
||||||
from pyparsing import Optional
|
|
||||||
from pyparsing import stringEnd
|
|
||||||
from pyparsing import Word
|
|
||||||
|
|
||||||
|
|
||||||
class SubExpr(object):
|
class SubExpr(object):
|
||||||
|
|
||||||
def __init__(self, tokens):
|
def __init__(self, tokens):
|
||||||
|
|
||||||
self._sub_expr = tokens
|
self._sub_expr = tokens
|
||||||
self._func = tokens.func
|
self._func = tokens.func
|
||||||
self._metric_name = tokens.metric_name
|
self._metric_name = tokens.metric_name
|
||||||
|
@ -173,67 +164,70 @@ class BinaryOp(object):
|
||||||
|
|
||||||
|
|
||||||
class AndSubExpr(BinaryOp):
|
class AndSubExpr(BinaryOp):
|
||||||
""" Expand later as needed.
|
"""Expand later as needed."""
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OrSubExpr(BinaryOp):
|
class OrSubExpr(BinaryOp):
|
||||||
"""Expand later as needed.
|
"""Expand later as needed."""
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
COMMA = Literal(",")
|
COMMA = pyparsing.Literal(",")
|
||||||
LPAREN = Literal("(")
|
LPAREN = pyparsing.Literal("(")
|
||||||
RPAREN = Literal(")")
|
RPAREN = pyparsing.Literal(")")
|
||||||
EQUAL = Literal("=")
|
EQUAL = pyparsing.Literal("=")
|
||||||
LBRACE = Literal("{")
|
LBRACE = pyparsing.Literal("{")
|
||||||
RBRACE = Literal("}")
|
RBRACE = pyparsing.Literal("}")
|
||||||
|
|
||||||
# Initialize non-ascii unicode code points in the Basic Multilingual Plane.
|
# Initialize non-ascii unicode code points in the Basic Multilingual Plane.
|
||||||
unicode_printables = u''.join(
|
unicode_printables = u''.join(
|
||||||
unichr(c) for c in xrange(128, 65536) if not unichr(c).isspace())
|
unichr(c) for c in xrange(128, 65536) if not unichr(c).isspace())
|
||||||
|
|
||||||
# Does not like comma. No Literals from above allowed.
|
# 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")
|
metric_name = (
|
||||||
dimension_name = Word(valid_identifier_chars, min=1, max=255)
|
pyparsing.Word(valid_identifier_chars, min=1, max=255)("metric_name"))
|
||||||
dimension_value = Word(valid_identifier_chars, min=1, max=255)
|
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)
|
integer_number = pyparsing.Word(pyparsing.nums)
|
||||||
decimal_number = Word(nums + ".")
|
decimal_number = pyparsing.Word(pyparsing.nums + ".")
|
||||||
|
|
||||||
max = CaselessLiteral("max")
|
max = pyparsing.CaselessLiteral("max")
|
||||||
min = CaselessLiteral("min")
|
min = pyparsing.CaselessLiteral("min")
|
||||||
avg = CaselessLiteral("avg")
|
avg = pyparsing.CaselessLiteral("avg")
|
||||||
count = CaselessLiteral("count")
|
count = pyparsing.CaselessLiteral("count")
|
||||||
sum = CaselessLiteral("sum")
|
sum = pyparsing.CaselessLiteral("sum")
|
||||||
func = (max | min | avg | count | sum)("func")
|
func = (max | min | avg | count | sum)("func")
|
||||||
|
|
||||||
less_than_op = (CaselessLiteral("<") | CaselessLiteral("lt"))
|
less_than_op = (
|
||||||
less_than_eq_op = (CaselessLiteral("<=") | CaselessLiteral("lte"))
|
(pyparsing.CaselessLiteral("<") | pyparsing.CaselessLiteral("lt")))
|
||||||
greater_than_op = (CaselessLiteral(">") | CaselessLiteral("gt"))
|
less_than_eq_op = (
|
||||||
greater_than_eq_op = (CaselessLiteral(">=") | CaselessLiteral("gte"))
|
(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.
|
# Order is important. Put longer prefix first.
|
||||||
relational_op = (
|
relational_op = (
|
||||||
less_than_eq_op | less_than_op | greater_than_eq_op | greater_than_op)(
|
less_than_eq_op | less_than_op | greater_than_eq_op | greater_than_op)(
|
||||||
"relational_op")
|
"relational_op")
|
||||||
|
|
||||||
AND = CaselessLiteral("and") | CaselessLiteral("&&")
|
AND = pyparsing.CaselessLiteral("and") | pyparsing.CaselessLiteral("&&")
|
||||||
OR = CaselessLiteral("or") | CaselessLiteral("||")
|
OR = pyparsing.CaselessLiteral("or") | pyparsing.CaselessLiteral("||")
|
||||||
logical_op = (AND | OR)("logical_op")
|
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.
|
# Cannot have any whitespace after the comma delimiter.
|
||||||
dimension_list = Group(Optional(
|
dimension_list = pyparsing.Group(pyparsing.Optional(
|
||||||
LBRACE + delimitedList(dimension, delim=',', combine=True)(
|
LBRACE + pyparsing.delimitedList(dimension, delim=',', combine=True)(
|
||||||
"dimensions_list") + RBRACE))
|
"dimensions_list") + RBRACE))
|
||||||
|
|
||||||
metric = metric_name + dimension_list("dimensions")
|
metric = metric_name + dimension_list("dimensions")
|
||||||
|
@ -241,17 +235,18 @@ period = integer_number("period")
|
||||||
threshold = decimal_number("threshold")
|
threshold = decimal_number("threshold")
|
||||||
periods = integer_number("periods")
|
periods = integer_number("periods")
|
||||||
|
|
||||||
expression = Forward()
|
expression = pyparsing.Forward()
|
||||||
|
|
||||||
sub_expression = (func + LPAREN + metric + Optional(
|
sub_expression = (func + LPAREN + metric + pyparsing.Optional(
|
||||||
COMMA + period) + RPAREN + relational_op + threshold + Optional(
|
COMMA + period) + RPAREN + relational_op + threshold + pyparsing.Optional(
|
||||||
times + periods) | LPAREN + expression + RPAREN)
|
times + periods) | LPAREN + expression + RPAREN)
|
||||||
|
|
||||||
sub_expression.setParseAction(SubExpr)
|
sub_expression.setParseAction(SubExpr)
|
||||||
|
|
||||||
expression = operatorPrecedence(sub_expression,
|
expression = (
|
||||||
[(AND, 2, opAssoc.LEFT, AndSubExpr),
|
pyparsing.operatorPrecedence(sub_expression,
|
||||||
(OR, 2, opAssoc.LEFT, OrSubExpr)])
|
[(AND, 2, pyparsing.opAssoc.LEFT, AndSubExpr),
|
||||||
|
(OR, 2, pyparsing.opAssoc.LEFT, OrSubExpr)]))
|
||||||
|
|
||||||
|
|
||||||
class AlarmExprParser(object):
|
class AlarmExprParser(object):
|
||||||
|
@ -262,37 +257,37 @@ class AlarmExprParser(object):
|
||||||
def sub_expr_list(self):
|
def sub_expr_list(self):
|
||||||
# Remove all spaces before parsing. Simple, quick fix for whitespace
|
# Remove all spaces before parsing. Simple, quick fix for whitespace
|
||||||
# issue with dimension list not allowing whitespace after comma.
|
# issue with dimension list not allowing whitespace after comma.
|
||||||
parseResult = (expression + stringEnd).parseString(
|
parseResult = (expression + pyparsing.stringEnd).parseString(
|
||||||
self._expr.replace(' ', ''))
|
self._expr.replace(' ', ''))
|
||||||
sub_expr_list = parseResult[0].operands_list
|
sub_expr_list = parseResult[0].operands_list
|
||||||
return sub_expr_list
|
return sub_expr_list
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
""" Used for development and testing. """
|
"""Used for development and testing."""
|
||||||
|
|
||||||
expr0 = "max(-_.千幸福的笑脸{घोड़ा=馬, dn2=dv2}, 60) gte 100 times 3 && " \
|
expr0 = ("max(-_.千幸福的笑脸{घोड़ा=馬, dn2=dv2}, 60) gte 100 times 3 && "
|
||||||
"(min(ເຮືອນ{dn3=dv3,家=дом}) < 10 or sum(biz{dn5=dv5}) > 99 and " \
|
"(min(ເຮືອນ{dn3=dv3,家=дом}) < 10 or sum(biz{dn5=dv5}) >9 9and "
|
||||||
"count(fizzle) lt 0 or count(baz) > 1)".decode('utf8')
|
"count(fizzle) lt 0 or count(baz) > 1)".decode('utf8'))
|
||||||
|
|
||||||
expr1 = "max(foo{hostname=mini-mon,千=千}, 120) > 100 and (max(bar)>100 \
|
expr1 = ("max(foo{hostname=mini-mon,千=千}, 120) > 100 and (max(bar)>100 "
|
||||||
or max(biz)>100)".decode('utf8')
|
" or max(biz)>100)".decode('utf8'))
|
||||||
|
|
||||||
expr2 = "max(foo)>=100"
|
expr2 = "max(foo)>=100"
|
||||||
|
|
||||||
for expr in (expr0, expr1, expr2):
|
for expr in (expr0, expr1, expr2):
|
||||||
print 'orig expr: {}'.format(expr.encode('utf8'))
|
print ('orig expr: {}'.format(expr.encode('utf8')))
|
||||||
alarmExprParser = AlarmExprParser(expr)
|
alarmExprParser = AlarmExprParser(expr)
|
||||||
sub_expr = alarmExprParser.sub_expr_list
|
sub_expr = alarmExprParser.sub_expr_list
|
||||||
for sub_expression in sub_expr:
|
for sub_expression in sub_expr:
|
||||||
print 'sub expr: {}'.format(
|
print ('sub expr: {}'.format(
|
||||||
sub_expression.sub_expr_str.encode('utf8'))
|
sub_expression.sub_expr_str.encode('utf8')))
|
||||||
print 'fmtd sub expr: {}'.format(
|
print ('fmtd sub expr: {}'.format(
|
||||||
sub_expression.fmtd_sub_expr_str.encode('utf8'))
|
sub_expression.fmtd_sub_expr_str.encode('utf8')))
|
||||||
print 'sub_expr dimensions: {}'.format(
|
print ('sub_expr dimensions: {}'.format(
|
||||||
sub_expression.dimensions_str.encode('utf8'))
|
sub_expression.dimensions_str.encode('utf8')))
|
||||||
print
|
print ()
|
||||||
print
|
print ()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -14,11 +14,13 @@
|
||||||
|
|
||||||
|
|
||||||
class MockAuthFilter(object):
|
class MockAuthFilter(object):
|
||||||
'''
|
"""Authorization filter.
|
||||||
|
|
||||||
This authorization filter doesn't do any authentication, it just copies the
|
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
|
auth token to the tenant ID and supplies the 'admin' role and is meant for
|
||||||
testing purposes only.
|
testing purposes only.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, app, conf):
|
def __init__(self, app, conf):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.conf = conf
|
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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema, Length, Optional
|
import voluptuous
|
||||||
from voluptuous import Required, Any, All
|
|
||||||
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
@ -22,19 +21,25 @@ from monasca.v2.common.schemas import exceptions
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
alarm_definition_schema = {
|
alarm_definition_schema = {
|
||||||
Required('name'): All(Any(str, unicode), Length(max=250)),
|
voluptuous.Required('name'): voluptuous.All(voluptuous.Any(str, unicode),
|
||||||
Required('expression'): All(Any(str, unicode), Length(max=4096)),
|
voluptuous.Length(max=250)),
|
||||||
Optional('description'): All(Any(str, unicode), Length(max=250)),
|
voluptuous.Required('expression'): voluptuous.All(
|
||||||
Optional('severity'): All(
|
voluptuous.Any(str, unicode), voluptuous.Length(max=4096)),
|
||||||
Any('low', 'medium', 'high', 'critical', 'LOW', "MEDIUM", 'HIGH',
|
voluptuous.Optional('description'): voluptuous.All(
|
||||||
'CRITICAL')),
|
voluptuous.Any(str, unicode), voluptuous.Length(max=250)),
|
||||||
Optional('match_by'): All(Any([unicode], [str]), Length(max=255)),
|
voluptuous.Optional('severity'): voluptuous.All(
|
||||||
Optional('ok_actions'): All(Any([str], [unicode]), Length(max=400)),
|
voluptuous.Any('low', 'medium', 'high', 'critical', 'LOW', "MEDIUM",
|
||||||
Optional('alarm_actions'): All(Any([str], [unicode]), Length(max=400)),
|
'HIGH', 'CRITICAL')),
|
||||||
Optional('undetermined_actions'): All(Any([str], [unicode]),
|
voluptuous.Optional('match_by'): voluptuous.All(
|
||||||
Length(max=400))}
|
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,
|
request_body_schema = voluptuous.Schema(alarm_definition_schema, required=True,
|
||||||
extra=True)
|
extra=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,17 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema
|
import voluptuous
|
||||||
from voluptuous import Any, All, Length
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
dimensions_schema = Schema({All(Any(str, unicode), Length(max=255)):
|
dimensions_schema = voluptuous.Schema({
|
||||||
All(Any(str, unicode), Length(max=255))})
|
voluptuous.All(voluptuous.Any(str, unicode),
|
||||||
|
voluptuous.Length(max=255)): voluptuous.All(
|
||||||
|
voluptuous.Any(str, unicode), voluptuous.Length(max=255))})
|
||||||
|
|
||||||
|
|
||||||
def validate(dimensions):
|
def validate(dimensions):
|
||||||
|
|
|
@ -12,17 +12,17 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema
|
import voluptuous
|
||||||
from voluptuous import Any, All, Length
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
# TODO: Add regex to validate key/values don't use any excluded characters.
|
event_schema_request_body = voluptuous.Schema({
|
||||||
event_schema_request_body = Schema({All(Any(str, unicode), Length(max=255)):
|
voluptuous.All(voluptuous.Any(str, unicode),
|
||||||
All(Any(None, str, unicode, bool, int,
|
voluptuous.Length(max=255)): voluptuous.All(
|
||||||
float, dict, []))})
|
voluptuous.Any(None, str, unicode, bool, int, float, dict, []))})
|
||||||
|
|
||||||
|
|
||||||
def validate(body):
|
def validate(body):
|
||||||
|
|
|
@ -12,14 +12,15 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema
|
import voluptuous
|
||||||
from voluptuous import Any, All, Length
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
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):
|
def validate(name):
|
||||||
|
|
|
@ -12,23 +12,24 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema
|
import voluptuous
|
||||||
from voluptuous import Required, Any, All, Range, Optional
|
|
||||||
from monasca.openstack.common import log
|
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 dimensions_schema
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
from monasca.v2.common.schemas import metric_name_schema
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
metric_schema = {
|
metric_schema = {
|
||||||
Required('name'): metric_name_schema.metric_name_schema,
|
voluptuous.Required('name'): metric_name_schema.metric_name_schema,
|
||||||
Optional('dimensions'): dimensions_schema.dimensions_schema,
|
voluptuous.Optional('dimensions'): dimensions_schema.dimensions_schema,
|
||||||
Required('timestamp'): All(Any(int, float), Range(min=0)),
|
voluptuous.Required('timestamp'): voluptuous.All(
|
||||||
Required('value'): Any(int, float)
|
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):
|
def validate(msg):
|
||||||
|
|
|
@ -12,20 +12,24 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema
|
import voluptuous
|
||||||
from voluptuous import Optional, Required, Any, All, Length
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
notification_schema = {
|
notification_schema = {
|
||||||
Required('name'): Schema(All(Any(str, unicode), Length(max=250))),
|
voluptuous.Required('name'): voluptuous.Schema(
|
||||||
Required('type'): Schema(Any("EMAIL", "email")),
|
voluptuous.All(voluptuous.Any(str, unicode),
|
||||||
Required('address'): Schema(All(Any(str, unicode), Length(max=100)))
|
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):
|
def validate(msg):
|
||||||
|
|
|
@ -12,22 +12,26 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from voluptuous import Schema
|
import voluptuous
|
||||||
from voluptuous import Optional, Required, Any, All, Length
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.common.schemas import exceptions
|
from monasca.v2.common.schemas import exceptions
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
transform_schema = {
|
transform_schema = {
|
||||||
Required('name'): Schema(All(Any(str, unicode), Length(max=64))),
|
voluptuous.Required('name'): voluptuous.Schema(
|
||||||
Required('description'): Schema(All(Any(str, unicode), Length(max=250))),
|
voluptuous.All(voluptuous.Any(str, unicode),
|
||||||
Required('specification'):
|
voluptuous.Length(max=64))),
|
||||||
Schema(All(Any(str, unicode), Length(max=64536))),
|
voluptuous.Required('description'): voluptuous.Schema(
|
||||||
Optional('enabled'): bool
|
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):
|
def validate(msg):
|
||||||
|
|
|
@ -11,21 +11,24 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from pyparsing import ParseException
|
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
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.repositories import exceptions
|
||||||
from monasca.common import resource_api
|
from monasca.common import resource_api
|
||||||
from monasca.api.alarm_definitions_api_v2 import AlarmDefinitionsV2API
|
import monasca.expression_parser.alarm_expr_parser
|
||||||
from monasca.expression_parser.alarm_expr_parser import AlarmExprParser
|
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.reference import helpers
|
from monasca.v2.common.schemas import (alarm_definition_request_body_schema
|
||||||
from monasca.v2.common.schemas import alarm_definition_request_body_schema as schema_alarms
|
as schema_alarms)
|
||||||
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
from monasca.v2.common.schemas import exceptions as schemas_exceptions
|
||||||
from monasca.v2.reference.alarming import Alarming
|
from monasca.v2.reference.alarming import Alarming
|
||||||
|
from monasca.v2.reference import helpers
|
||||||
from monasca.v2.reference.helpers import read_json_msg_body
|
from monasca.v2.reference.helpers import read_json_msg_body
|
||||||
from monasca.v2.reference.resource import resource_try_catch_block
|
from monasca.v2.reference.resource import resource_try_catch_block
|
||||||
|
|
||||||
|
@ -43,13 +46,13 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
|
|
||||||
self._region = cfg.CONF.region
|
self._region = cfg.CONF.region
|
||||||
|
|
||||||
self._default_authorized_roles = \
|
self._default_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles
|
cfg.CONF.security.default_authorized_roles)
|
||||||
self._delegate_authorized_roles = \
|
self._delegate_authorized_roles = (
|
||||||
cfg.CONF.security.delegate_authorized_roles
|
cfg.CONF.security.delegate_authorized_roles)
|
||||||
self._post_metrics_authorized_roles = \
|
self._post_metrics_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles + \
|
cfg.CONF.security.default_authorized_roles +
|
||||||
cfg.CONF.security.agent_authorized_roles
|
cfg.CONF.security.agent_authorized_roles)
|
||||||
|
|
||||||
self._alarm_definitions_repo = resource_api.init_driver(
|
self._alarm_definitions_repo = resource_api.init_driver(
|
||||||
'monasca.repositories',
|
'monasca.repositories',
|
||||||
|
@ -134,9 +137,8 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
@resource_try_catch_block
|
@resource_try_catch_block
|
||||||
def _alarm_definition_show(self, tenant_id, id):
|
def _alarm_definition_show(self, tenant_id, id):
|
||||||
|
|
||||||
alarm_definition_row = \
|
alarm_definition_row = (
|
||||||
self._alarm_definitions_repo.get_alarm_definition(
|
self._alarm_definitions_repo.get_alarm_definition(tenant_id, id))
|
||||||
tenant_id, id)
|
|
||||||
|
|
||||||
match_by = get_comma_separated_str_as_list(
|
match_by = get_comma_separated_str_as_list(
|
||||||
alarm_definition_row.match_by)
|
alarm_definition_row.match_by)
|
||||||
|
@ -168,9 +170,8 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
@resource_try_catch_block
|
@resource_try_catch_block
|
||||||
def _alarm_definition_delete(self, tenant_id, id):
|
def _alarm_definition_delete(self, tenant_id, id):
|
||||||
|
|
||||||
sub_alarm_definition_rows = \
|
sub_alarm_definition_rows = (
|
||||||
self._alarm_definitions_repo.get_sub_alarm_definitions(
|
self._alarm_definitions_repo.get_sub_alarm_definitions(id))
|
||||||
id)
|
|
||||||
alarm_metric_rows = self._alarm_definitions_repo.get_alarm_metrics(
|
alarm_metric_rows = self._alarm_definitions_repo.get_alarm_metrics(
|
||||||
tenant_id, id)
|
tenant_id, id)
|
||||||
sub_alarm_rows = self._alarm_definitions_repo.get_sub_alarms(
|
sub_alarm_rows = self._alarm_definitions_repo.get_sub_alarms(
|
||||||
|
@ -189,9 +190,9 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
@resource_try_catch_block
|
@resource_try_catch_block
|
||||||
def _alarm_definition_list(self, tenant_id, name, dimensions, req_uri):
|
def _alarm_definition_list(self, tenant_id, name, dimensions, req_uri):
|
||||||
|
|
||||||
alarm_definition_rows = \
|
alarm_definition_rows = (
|
||||||
self._alarm_definitions_repo.get_alarm_definitions(
|
self._alarm_definitions_repo.get_alarm_definitions(tenant_id, name,
|
||||||
tenant_id, name, dimensions)
|
dimensions))
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for alarm_definition_row in alarm_definition_rows:
|
for alarm_definition_row in alarm_definition_rows:
|
||||||
|
@ -227,7 +228,6 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _validate_alarm_definition(self, alarm_definition):
|
def _validate_alarm_definition(self, alarm_definition):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -243,20 +243,29 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
ok_actions):
|
ok_actions):
|
||||||
try:
|
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)
|
LOG.exception(ex)
|
||||||
title = "Invalid alarm expression".encode('utf8')
|
title = "Invalid alarm expression".encode('utf8')
|
||||||
msg = "parser failed on expression '{}' at column {}".format(
|
msg = "parser failed on expression '{}' at column {}".format(
|
||||||
expression.encode('utf8'), str(ex.column).encode('utf'))
|
expression.encode('utf8'), str(ex.column).encode('utf'))
|
||||||
raise falcon.HTTPBadRequest(title, msg)
|
raise falcon.HTTPBadRequest(title, msg)
|
||||||
|
|
||||||
alarm_definition_id = \
|
alarm_definition_id = (
|
||||||
self._alarm_definitions_repo.create_alarm_definition(
|
self._alarm_definitions_repo.
|
||||||
tenant_id, name, expression, sub_expr_list, description,
|
create_alarm_definition(tenant_id,
|
||||||
severity, match_by, alarm_actions, undetermined_actions,
|
name,
|
||||||
ok_actions)
|
expression,
|
||||||
|
sub_expr_list,
|
||||||
|
description,
|
||||||
|
severity,
|
||||||
|
match_by,
|
||||||
|
alarm_actions,
|
||||||
|
undetermined_actions,
|
||||||
|
ok_actions))
|
||||||
|
|
||||||
self._send_alarm_definition_created_event(tenant_id,
|
self._send_alarm_definition_created_event(tenant_id,
|
||||||
alarm_definition_id,
|
alarm_definition_id,
|
||||||
|
@ -334,6 +343,7 @@ class AlarmDefinitions(AlarmDefinitionsV2API, Alarming):
|
||||||
|
|
||||||
self._send_event(alarm_definition_created_event_msg)
|
self._send_event(alarm_definition_created_event_msg)
|
||||||
|
|
||||||
|
|
||||||
def get_query_alarm_definition_name(alarm_definition):
|
def get_query_alarm_definition_name(alarm_definition):
|
||||||
try:
|
try:
|
||||||
if 'name' in alarm_definition:
|
if 'name' in alarm_definition:
|
||||||
|
@ -407,6 +417,7 @@ def get_query_ok_actions(alarm_definition):
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_comma_separated_str_as_list(comma_separated_str):
|
def get_comma_separated_str_as_list(comma_separated_str):
|
||||||
|
|
||||||
if not comma_separated_str:
|
if not comma_separated_str:
|
||||||
|
|
|
@ -12,12 +12,14 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
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.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__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -33,10 +35,9 @@ class Alarming(object):
|
||||||
|
|
||||||
super(Alarming, self).__init__()
|
super(Alarming, self).__init__()
|
||||||
|
|
||||||
self._message_queue \
|
self._message_queue = (
|
||||||
= resource_api.init_driver('monasca.messaging',
|
resource_api.init_driver('monasca.messaging',
|
||||||
cfg.CONF.messaging.driver,
|
cfg.CONF.messaging.driver, (['events'])))
|
||||||
(['events']))
|
|
||||||
|
|
||||||
def _send_alarm_deleted_event(self, tenant_id, alarm_definition_id,
|
def _send_alarm_deleted_event(self, tenant_id, alarm_definition_id,
|
||||||
alarm_metric_rows, sub_alarm_rows):
|
alarm_metric_rows, sub_alarm_rows):
|
||||||
|
@ -52,13 +53,15 @@ class Alarming(object):
|
||||||
else:
|
else:
|
||||||
sub_alarm_dict[sub_alarm_row.alarm_id] = [sub_alarm_row]
|
sub_alarm_dict[sub_alarm_row.alarm_id] = [sub_alarm_row]
|
||||||
|
|
||||||
|
# Forward declaration.
|
||||||
|
alarm_deleted_event_msg = {}
|
||||||
prev_alarm_id = None
|
prev_alarm_id = None
|
||||||
for alarm_metric_row in alarm_metric_rows:
|
for alarm_metric_row in alarm_metric_rows:
|
||||||
if prev_alarm_id != alarm_metric_row.alarm_id:
|
if prev_alarm_id != alarm_metric_row.alarm_id:
|
||||||
if prev_alarm_id is not None:
|
if prev_alarm_id is not None:
|
||||||
sub_alarms_deleted_event_msg = \
|
sub_alarms_deleted_event_msg = (
|
||||||
self._build_sub_alarm_deleted_event_msg(
|
self._build_sub_alarm_deleted_event_msg(sub_alarm_dict,
|
||||||
sub_alarm_dict, prev_alarm_id)
|
prev_alarm_id))
|
||||||
alarm_deleted_event_msg[u'alarm-delete'][
|
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)
|
self._send_event(alarm_deleted_event_msg)
|
||||||
|
@ -99,7 +102,8 @@ class Alarming(object):
|
||||||
|
|
||||||
for sub_alarm in sub_alarm_dict[alarm_id]:
|
for sub_alarm in sub_alarm_dict[alarm_id]:
|
||||||
# There's only one expr in a sub alarm, so just take the first.
|
# 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 = {}
|
dimensions = {}
|
||||||
sub_alarms_deleted_event_msg[sub_alarm.sub_alarm_id] = {
|
sub_alarms_deleted_event_msg[sub_alarm.sub_alarm_id] = {
|
||||||
u'function': sub_expr.normalized_func,
|
u'function': sub_expr.normalized_func,
|
||||||
|
|
|
@ -11,17 +11,19 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from falcon.util.uri import parse_query_string
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
from monasca.api.alarms_api_v2 import AlarmsV2API
|
from monasca.api.alarms_api_v2 import AlarmsV2API
|
||||||
from monasca.common.repositories import exceptions
|
from monasca.common.repositories import exceptions
|
||||||
from monasca.common import resource_api
|
from monasca.common import resource_api
|
||||||
from monasca.openstack.common import log
|
from monasca.openstack.common import log
|
||||||
from monasca.v2.reference import helpers
|
|
||||||
from monasca.v2.reference.alarming import Alarming
|
from monasca.v2.reference.alarming import Alarming
|
||||||
|
from monasca.v2.reference import helpers
|
||||||
from monasca.v2.reference.resource import resource_try_catch_block
|
from monasca.v2.reference.resource import resource_try_catch_block
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,17 +40,20 @@ class Alarms(AlarmsV2API, Alarming):
|
||||||
|
|
||||||
self._region = cfg.CONF.region
|
self._region = cfg.CONF.region
|
||||||
|
|
||||||
self._default_authorized_roles = \
|
self._default_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles
|
cfg.CONF.security.default_authorized_roles)
|
||||||
self._delegate_authorized_roles = \
|
self._delegate_authorized_roles = (
|
||||||
cfg.CONF.security.delegate_authorized_roles
|
cfg.CONF.security.delegate_authorized_roles)
|
||||||
self._post_metrics_authorized_roles = \
|
self._post_metrics_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles + \
|
cfg.CONF.security.default_authorized_roles +
|
||||||
cfg.CONF.security.agent_authorized_roles
|
cfg.CONF.security.agent_authorized_roles)
|
||||||
|
|
||||||
self._alarms_repo = resource_api.init_driver(
|
self._alarms_repo = resource_api.init_driver(
|
||||||
'monasca.repositories', cfg.CONF.repositories.alarms_driver)
|
'monasca.repositories', cfg.CONF.repositories.alarms_driver)
|
||||||
|
|
||||||
|
self._metrics_repo = resource_api.init_driver(
|
||||||
|
'monasca.repositories', cfg.CONF.repositories.metrics_driver)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise exceptions.RepositoryException(ex)
|
raise exceptions.RepositoryException(ex)
|
||||||
|
@ -91,7 +96,7 @@ class Alarms(AlarmsV2API, Alarming):
|
||||||
helpers.validate_authorization(req, self._default_authorized_roles)
|
helpers.validate_authorization(req, self._default_authorized_roles)
|
||||||
tenant_id = helpers.get_tenant_id(req)
|
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)
|
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')
|
@resource_api.Restify('/v2.0/alarms/{id}', method='get')
|
||||||
def do_get_alarm_by_id(self, req, res, id):
|
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)
|
helpers.validate_authorization(req, self._default_authorized_roles)
|
||||||
tenant_id = helpers.get_tenant_id(req)
|
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.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
||||||
res.status = falcon.HTTP_200
|
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
|
@resource_try_catch_block
|
||||||
def _alarm_delete(self, tenant_id, id):
|
def _alarm_delete(self, tenant_id, id):
|
||||||
|
|
||||||
|
@ -171,6 +228,8 @@ class Alarms(AlarmsV2API, Alarming):
|
||||||
if not alarm_rows:
|
if not alarm_rows:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
# Forward declaration
|
||||||
|
alarm = {}
|
||||||
prev_alarm_id = None
|
prev_alarm_id = None
|
||||||
for alarm_row in alarm_rows:
|
for alarm_row in alarm_rows:
|
||||||
if prev_alarm_id != alarm_row.alarm_id:
|
if prev_alarm_id != alarm_row.alarm_id:
|
||||||
|
|
|
@ -17,37 +17,40 @@ import json
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
from monasca.openstack.common import log
|
|
||||||
from monasca.api import monasca_events_api_v2
|
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 import exceptions as message_queue_exceptions
|
||||||
from monasca.common.messaging.message_formats import events_transform_factory
|
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 exceptions as schemas_exceptions
|
||||||
from monasca.v2.common.schemas import \
|
from monasca.v2.common import utils
|
||||||
events_request_body_schema as schemas_event
|
|
||||||
from monasca.v2.reference import helpers
|
from monasca.v2.reference import helpers
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Events(monasca_events_api_v2.EventsV2API):
|
class Events(monasca_events_api_v2.EventsV2API):
|
||||||
|
|
||||||
def __init__(self, global_conf):
|
def __init__(self, global_conf):
|
||||||
|
|
||||||
super(Events, self).__init__(global_conf)
|
super(Events, self).__init__(global_conf)
|
||||||
|
|
||||||
self._region = cfg.CONF.region
|
self._region = cfg.CONF.region
|
||||||
self._default_authorized_roles = \
|
self._default_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles
|
cfg.CONF.security.default_authorized_roles)
|
||||||
self._delegate_authorized_roles = \
|
self._delegate_authorized_roles = (
|
||||||
cfg.CONF.security.delegate_authorized_roles
|
cfg.CONF.security.delegate_authorized_roles)
|
||||||
self._post_events_authorized_roles = \
|
self._post_events_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles + \
|
cfg.CONF.security.default_authorized_roles +
|
||||||
cfg.CONF.security.agent_authorized_roles
|
cfg.CONF.security.agent_authorized_roles)
|
||||||
self._event_transform = \
|
self._event_transform = (
|
||||||
events_transform_factory.create_events_transform()
|
events_transform_factory.create_events_transform())
|
||||||
self._message_queue = \
|
self._message_queue = (
|
||||||
resource_api.init_driver('monasca.messaging',
|
resource_api.init_driver('monasca.messaging',
|
||||||
cfg.CONF.messaging.driver,
|
cfg.CONF.messaging.driver,
|
||||||
['raw-events'])
|
['raw-events']))
|
||||||
|
|
||||||
def _validate_event(self, event):
|
def _validate_event(self, event):
|
||||||
"""Validates the event
|
"""Validates the event
|
||||||
|
|
|
@ -11,25 +11,25 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
from urlparse import urlparse
|
import urlparse
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from falcon.util.uri import parse_query_string
|
import simplejson
|
||||||
|
|
||||||
from monasca.openstack.common import log
|
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 exceptions as schemas_exceptions
|
||||||
from monasca.v2.common.schemas import metric_name_schema
|
from monasca.v2.common.schemas import metric_name_schema
|
||||||
from monasca.v2.common.schemas import dimensions_schema
|
|
||||||
import simplejson
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def read_json_msg_body(req):
|
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.
|
:param req: HTTP request object.
|
||||||
:return: Returns the metrics as a JSON object.
|
:return: Returns the metrics as a JSON object.
|
||||||
:raises falcon.HTTPBadRequest:
|
:raises falcon.HTTPBadRequest:
|
||||||
|
@ -51,8 +51,7 @@ def validate_json_content_type(req):
|
||||||
|
|
||||||
|
|
||||||
def is_in_role(req, authorized_roles):
|
def is_in_role(req, authorized_roles):
|
||||||
"""Determines if one or more of the X-ROLES is in the supplied
|
"""Is one or more of the X-ROLES in the supplied authorized_roles.
|
||||||
authorized_roles.
|
|
||||||
|
|
||||||
:param req: HTTP request object. Must contain "X-ROLES" in the HTTP
|
:param req: HTTP request object. Must contain "X-ROLES" in the HTTP
|
||||||
request header.
|
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.
|
:returns: Returns the cross tenant or tenant ID.
|
||||||
"""
|
"""
|
||||||
if is_in_role(req, delegate_authorized_roles):
|
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:
|
if 'tenant_id' in params:
|
||||||
tenant_id = params['tenant_id']
|
tenant_id = params['tenant_id']
|
||||||
return 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):
|
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.
|
:param req: HTTP request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
params = parse_query_string(req.query_string)
|
params = falcon.uri.parse_query_string(req.query_string)
|
||||||
if 'name' in params:
|
if 'name' in params:
|
||||||
name = params['name']
|
name = params['name']
|
||||||
return name
|
return name
|
||||||
|
@ -142,7 +141,7 @@ def get_query_dimensions(req):
|
||||||
:raises falcon.HTTPBadRequest: If dimensions are malformed.
|
:raises falcon.HTTPBadRequest: If dimensions are malformed.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
params = parse_query_string(req.query_string)
|
params = falcon.uri.parse_query_string(req.query_string)
|
||||||
dimensions = {}
|
dimensions = {}
|
||||||
if 'dimensions' in params:
|
if 'dimensions' in params:
|
||||||
dimensions_str = params['dimensions']
|
dimensions_str = params['dimensions']
|
||||||
|
@ -160,23 +159,29 @@ def get_query_dimensions(req):
|
||||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||||
|
|
||||||
|
|
||||||
def get_query_starttime_timestamp(req):
|
def get_query_starttime_timestamp(req, required=True):
|
||||||
try:
|
try:
|
||||||
params = parse_query_string(req.query_string)
|
params = falcon.uri.parse_query_string(req.query_string)
|
||||||
if 'start_time' in params:
|
if 'start_time' in params:
|
||||||
return _convert_time_string(params['start_time'])
|
return _convert_time_string(params['start_time'])
|
||||||
else:
|
else:
|
||||||
|
if required:
|
||||||
raise Exception("Missing start time")
|
raise Exception("Missing start time")
|
||||||
|
else:
|
||||||
|
return None
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.debug(ex)
|
LOG.debug(ex)
|
||||||
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
raise falcon.HTTPBadRequest('Bad request', ex.message)
|
||||||
|
|
||||||
|
|
||||||
def get_query_endtime_timestamp(req):
|
def get_query_endtime_timestamp(req, required=True):
|
||||||
try:
|
try:
|
||||||
params = parse_query_string(req.query_string)
|
params = falcon.uri.parse_query_string(req.query_string)
|
||||||
if 'end_time' in params:
|
if 'end_time' in params:
|
||||||
return _convert_time_string(params['end_time'])
|
return _convert_time_string(params['end_time'])
|
||||||
|
else:
|
||||||
|
if required:
|
||||||
|
raise Exception("Missing end time")
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
@ -192,7 +197,7 @@ def _convert_time_string(date_time_string):
|
||||||
|
|
||||||
def get_query_statistics(req):
|
def get_query_statistics(req):
|
||||||
try:
|
try:
|
||||||
params = parse_query_string(req.query_string)
|
params = falcon.uri.parse_query_string(req.query_string)
|
||||||
if 'statistics' in params:
|
if 'statistics' in params:
|
||||||
statistics = params['statistics'].split(',')
|
statistics = params['statistics'].split(',')
|
||||||
statistics = [statistic.lower() for statistic in statistics]
|
statistics = [statistic.lower() for statistic in statistics]
|
||||||
|
@ -209,7 +214,7 @@ def get_query_statistics(req):
|
||||||
|
|
||||||
def get_query_period(req):
|
def get_query_period(req):
|
||||||
try:
|
try:
|
||||||
params = parse_query_string(req.query_string)
|
params = falcon.uri.parse_query_string(req.query_string)
|
||||||
if 'period' in params:
|
if 'period' in params:
|
||||||
return params['period']
|
return params['period']
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -16,22 +16,17 @@ import json
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
from stevedore import driver
|
|
||||||
|
|
||||||
from monasca.openstack.common import log
|
|
||||||
from monasca.api import monasca_api_v2
|
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 import exceptions as message_queue_exceptions
|
||||||
from monasca.common.messaging.message_formats import metrics_transform_factory
|
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 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 import helpers
|
||||||
from monasca.v2.reference.helpers import read_json_msg_body
|
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
@ -41,21 +36,23 @@ class Metrics(monasca_api_v2.V2API):
|
||||||
def __init__(self, global_conf):
|
def __init__(self, global_conf):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
super(Metrics, self).__init__(global_conf)
|
super(Metrics, self).__init__(global_conf)
|
||||||
|
|
||||||
self._region = cfg.CONF.region
|
self._region = cfg.CONF.region
|
||||||
self._default_authorized_roles = \
|
self._default_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles
|
cfg.CONF.security.default_authorized_roles)
|
||||||
self._delegate_authorized_roles = \
|
self._delegate_authorized_roles = (
|
||||||
cfg.CONF.security.delegate_authorized_roles
|
cfg.CONF.security.delegate_authorized_roles)
|
||||||
self._post_metrics_authorized_roles = \
|
self._post_metrics_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles + \
|
cfg.CONF.security.default_authorized_roles +
|
||||||
cfg.CONF.security.agent_authorized_roles
|
cfg.CONF.security.agent_authorized_roles)
|
||||||
self._metrics_transform = \
|
self._metrics_transform = (
|
||||||
metrics_transform_factory.create_metrics_transform()
|
metrics_transform_factory.create_metrics_transform())
|
||||||
self._message_queue = resource_api.init_driver(
|
self._message_queue = (
|
||||||
'monasca.messaging',
|
resource_api.init_driver('monasca.messaging',
|
||||||
cfg.CONF.messaging.driver,
|
cfg.CONF.messaging.driver,
|
||||||
['metrics'])
|
['metrics']))
|
||||||
self._metrics_repo = resource_api.init_driver(
|
self._metrics_repo = resource_api.init_driver(
|
||||||
'monasca.repositories', cfg.CONF.repositories.metrics_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:
|
except message_queue_exceptions.MessageQueueException as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||||
ex.message)
|
ex.message, 60)
|
||||||
|
|
||||||
if isinstance(metrics, list):
|
if isinstance(metrics, list):
|
||||||
for metric in metrics:
|
for metric in metrics:
|
||||||
|
@ -112,7 +109,7 @@ class Metrics(monasca_api_v2.V2API):
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||||
ex.message)
|
ex.message, 60)
|
||||||
|
|
||||||
def _measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
def _measurement_list(self, tenant_id, name, dimensions, start_timestamp,
|
||||||
end_timestamp):
|
end_timestamp):
|
||||||
|
@ -124,7 +121,7 @@ class Metrics(monasca_api_v2.V2API):
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||||
ex.message)
|
ex.message, 60)
|
||||||
|
|
||||||
def _metric_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
def _metric_statistics(self, tenant_id, name, dimensions, start_timestamp,
|
||||||
end_timestamp, statistics, period):
|
end_timestamp, statistics, period):
|
||||||
|
@ -137,7 +134,7 @@ class Metrics(monasca_api_v2.V2API):
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
raise falcon.HTTPServiceUnavailable('Service unavailable',
|
||||||
ex.message)
|
ex.message, 60)
|
||||||
|
|
||||||
@resource_api.Restify('/v2.0/metrics/', method='post')
|
@resource_api.Restify('/v2.0/metrics/', method='post')
|
||||||
def do_post_metrics(self, req, res):
|
def do_post_metrics(self, req, res):
|
||||||
|
@ -146,9 +143,9 @@ class Metrics(monasca_api_v2.V2API):
|
||||||
self._post_metrics_authorized_roles)
|
self._post_metrics_authorized_roles)
|
||||||
metrics = helpers.read_http_resource(req)
|
metrics = helpers.read_http_resource(req)
|
||||||
self._validate_metrics(metrics)
|
self._validate_metrics(metrics)
|
||||||
tenant_id = \
|
tenant_id = (
|
||||||
helpers.get_x_tenant_or_tenant_id(req,
|
helpers.get_x_tenant_or_tenant_id(req,
|
||||||
self._delegate_authorized_roles)
|
self._delegate_authorized_roles))
|
||||||
transformed_metrics = self._metrics_transform(metrics, tenant_id,
|
transformed_metrics = self._metrics_transform(metrics, tenant_id,
|
||||||
self._region)
|
self._region)
|
||||||
self._send_metrics(transformed_metrics)
|
self._send_metrics(transformed_metrics)
|
||||||
|
@ -175,7 +172,7 @@ class Metrics(monasca_api_v2.V2API):
|
||||||
dimensions = helpers.get_query_dimensions(req)
|
dimensions = helpers.get_query_dimensions(req)
|
||||||
helpers.validate_query_dimensions(dimensions)
|
helpers.validate_query_dimensions(dimensions)
|
||||||
start_timestamp = helpers.get_query_starttime_timestamp(req)
|
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,
|
result = self._measurement_list(tenant_id, name, dimensions,
|
||||||
start_timestamp, end_timestamp)
|
start_timestamp, end_timestamp)
|
||||||
res.body = json.dumps(result, ensure_ascii=False).encode('utf8')
|
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)
|
dimensions = helpers.get_query_dimensions(req)
|
||||||
helpers.validate_query_dimensions(dimensions)
|
helpers.validate_query_dimensions(dimensions)
|
||||||
start_timestamp = helpers.get_query_starttime_timestamp(req)
|
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)
|
statistics = helpers.get_query_statistics(req)
|
||||||
period = helpers.get_query_period(req)
|
period = helpers.get_query_period(req)
|
||||||
result = self._metric_statistics(tenant_id, name, dimensions,
|
result = self._metric_statistics(tenant_id, name, dimensions,
|
||||||
|
|
|
@ -12,22 +12,19 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
# TODO: Used simplejson to read the yaml as simplejson transforms to "str"
|
|
||||||
# not "unicode"
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
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 log
|
||||||
from monasca.openstack.common import uuidutils
|
from monasca.openstack.common import uuidutils
|
||||||
from monasca.api import monasca_notifications_api_v2
|
from monasca.v2.common.schemas import (exceptions as schemas_exceptions)
|
||||||
from monasca.common import resource_api
|
from monasca.v2.common.schemas import (
|
||||||
from monasca.common.repositories import exceptions as repository_exceptions
|
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
|
from monasca.v2.reference import helpers
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
@ -37,8 +34,8 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
||||||
def __init__(self, global_conf):
|
def __init__(self, global_conf):
|
||||||
super(Notifications, self).__init__(global_conf)
|
super(Notifications, self).__init__(global_conf)
|
||||||
self._region = cfg.CONF.region
|
self._region = cfg.CONF.region
|
||||||
self._default_authorized_roles = \
|
self._default_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles
|
cfg.CONF.security.default_authorized_roles)
|
||||||
self._notifications_repo = resource_api.init_driver(
|
self._notifications_repo = resource_api.init_driver(
|
||||||
'monasca.repositories', cfg.CONF.repositories.notifications_driver)
|
'monasca.repositories', cfg.CONF.repositories.notifications_driver)
|
||||||
|
|
||||||
|
@ -66,7 +63,8 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API):
|
||||||
address = notification['address']
|
address = notification['address']
|
||||||
if self._notifications_repo.exists(tenant_id, name):
|
if self._notifications_repo.exists(tenant_id, name):
|
||||||
raise falcon.HTTPConflict('Conflict', (
|
raise falcon.HTTPConflict('Conflict', (
|
||||||
'Notification Method already exists: tenant_id=%s name=%s' % (
|
'Notification Method already exists: tenant_id=%s '
|
||||||
|
'name=%s' % (
|
||||||
tenant_id, name)), code=409)
|
tenant_id, name)), code=409)
|
||||||
self._notifications_repo.create_notification(id, tenant_id, name,
|
self._notifications_repo.create_notification(id, tenant_id, name,
|
||||||
notification_type,
|
notification_type,
|
||||||
|
|
|
@ -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
|
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
|
from monasca.openstack.common import log
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +30,7 @@ def resource_try_catch_block(fun):
|
||||||
|
|
||||||
except falcon.HTTPNotFound:
|
except falcon.HTTPNotFound:
|
||||||
raise
|
raise
|
||||||
except DoesNotExistException:
|
except exceptions.DoesNotExistException:
|
||||||
raise falcon.HTTPNotFound
|
raise falcon.HTTPNotFound
|
||||||
except falcon.HTTPBadRequest:
|
except falcon.HTTPBadRequest:
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -12,34 +12,32 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
# TODO: Used simplejson to read the yaml as simplejson transforms to "str"
|
|
||||||
# not "unicode"
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import simplejson
|
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
from oslo.config import cfg
|
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 log
|
||||||
from monasca.openstack.common import uuidutils
|
from monasca.openstack.common import uuidutils
|
||||||
from monasca.api import monasca_transforms_api_v2
|
from monasca.v2.common.schemas import (exceptions as schemas_exceptions)
|
||||||
from monasca.common import resource_api
|
from monasca.v2.common.schemas import (
|
||||||
from monasca.common.repositories import exceptions as repository_exceptions
|
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
|
from monasca.v2.reference import helpers
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
class Transforms(monasca_transforms_api_v2.TransformsV2API):
|
||||||
def __init__(self, global_conf):
|
def __init__(self, global_conf):
|
||||||
|
|
||||||
super(Transforms, self).__init__(global_conf)
|
super(Transforms, self).__init__(global_conf)
|
||||||
self._region = cfg.CONF.region
|
self._region = cfg.CONF.region
|
||||||
self._default_authorized_roles = \
|
self._default_authorized_roles = (
|
||||||
cfg.CONF.security.default_authorized_roles
|
cfg.CONF.security.default_authorized_roles)
|
||||||
self._transforms_repo = resource_api.init_driver(
|
self._transforms_repo = resource_api.init_driver(
|
||||||
'monasca.repositories', cfg.CONF.repositories.transforms_driver)
|
'monasca.repositories', cfg.CONF.repositories.transforms_driver)
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,4 @@ gunicorn>=19.1.0
|
||||||
oslo.config>=1.2.1
|
oslo.config>=1.2.1
|
||||||
ujson>=1.33
|
ujson>=1.33
|
||||||
Pyparsing>=2.0.3
|
Pyparsing>=2.0.3
|
||||||
pyodbc>=3.0.7
|
influxdb>=0.1.12
|
||||||
|
|
|
@ -9,6 +9,7 @@ pep8<=1.5.6
|
||||||
httplib2>=0.7.5
|
httplib2>=0.7.5
|
||||||
mock>=1.0
|
mock>=1.0
|
||||||
mox>=0.5.3
|
mox>=0.5.3
|
||||||
|
nose
|
||||||
# Docs Requirements
|
# Docs Requirements
|
||||||
oslosphinx
|
oslosphinx
|
||||||
oslotest
|
oslotest
|
||||||
|
|
12
tox.ini
12
tox.ini
|
@ -4,14 +4,12 @@ skipsdist = True
|
||||||
envlist = py27,py33,pep8
|
envlist = py27,py33,pep8
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
|
usedevelop = True
|
||||||
|
install_command = pip install -U {opts} {packages}
|
||||||
deps = -r{toxinidir}/requirements.txt
|
deps = -r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/test-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}
|
commands = nosetests
|
||||||
usedevelop = True
|
|
||||||
setenv = VIRTUAL_ENV={envdir}
|
|
||||||
commands = python setup.py testr --slowest --testr-args='--concurrency 1 {posargs}'
|
|
||||||
downloadcache = {toxworkdir}/_download
|
|
||||||
whitelist_externals = bash
|
|
||||||
|
|
||||||
[testenv:cover]
|
[testenv:cover]
|
||||||
setenv = NOSE_WITH_COVERAGE=1
|
setenv = NOSE_WITH_COVERAGE=1
|
||||||
|
@ -32,8 +30,6 @@ commands = python setup.py build_sphinx
|
||||||
commands = {posargs}
|
commands = {posargs}
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
# H305 imports not grouped correctly
|
|
||||||
ignore = H305
|
|
||||||
builtins = _
|
builtins = _
|
||||||
exclude=.venv,.git,.tox,dist,doc,./monasca/openstack/common,*lib/python*,*egg,tools,build
|
exclude=.venv,.git,.tox,dist,doc,./monasca/openstack/common,*lib/python*,*egg,tools,build
|
||||||
show-source = True
|
show-source = True
|
||||||
|
|
Loading…
Reference in New Issue