kiloeyes/kiloeyes/v2/elasticsearch/alarmdefinitions.py

352 lines
14 KiB
Python
Executable File

# Copyright 2015 Carnegie Mellon University
#
# 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 ast
import falcon
from oslo_config import cfg
from stevedore import driver
import uuid
from kiloeyes.common import alarm_expr_parser
from kiloeyes.common import alarm_expr_validator
from kiloeyes.common import es_conn
from kiloeyes.common import namespace
from kiloeyes.common import resource_api
from oslo_log import log
try:
import ujson as json
except ImportError:
import json
alarmdefinitions_opts = [
cfg.StrOpt('doc_type', default='alarmdefinitions',
help='The doc_type that alarm definitions will be saved to.'),
cfg.StrOpt('index_strategy', default='fixed',
help='The index strategy used to create index name.'),
cfg.StrOpt('index_prefix', default='data_',
help='The index prefix where metrics were saved to.'),
cfg.IntOpt('size', default=1000,
help=('The query result limit. Any result set more than '
'the limit will be discarded.')),
]
cfg.CONF.register_opts(alarmdefinitions_opts, group='alarmdefinitions')
STATES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']
LOG = log.getLogger(__name__)
class AlarmDefinitionUtil(object):
@staticmethod
def severityparsing(msg):
try:
severity = msg["severity"]
if severity in STATES:
return msg
else:
msg["severity"] = "LOW"
return msg
except Exception:
return msg
class AlarmDefinitionDispatcher(object):
def __init__(self, global_conf):
LOG.debug('Initializing AlarmDefinition V2API!')
super(AlarmDefinitionDispatcher, self).__init__()
self.doc_type = cfg.CONF.alarmdefinitions.doc_type
self.size = cfg.CONF.alarmdefinitions.size
# load index strategy
if cfg.CONF.alarmdefinitions.index_strategy:
self.index_strategy = driver.DriverManager(
namespace.STRATEGY_NS,
cfg.CONF.alarmdefinitions.index_strategy,
invoke_on_load=True,
invoke_kwds={}).driver
LOG.debug(self.index_strategy)
else:
self.index_strategy = None
self.index_prefix = cfg.CONF.alarmdefinitions.index_prefix
self._es_conn = es_conn.ESConnection(
self.doc_type, self.index_strategy, self.index_prefix)
def _get_alarm_definitions_response(self, res):
if res and res.status_code == 200:
obj = res.json()
if obj:
return obj.get('hits')
return None
def _get_alarm_definitions_helper(self, query_string):
query = {}
queries = []
field_string = 'alarmdefinitions.expression_data.dimensions.'
if query_string:
params = query_string.split('&')
for current_param in params:
current_param_split = current_param.split('=')
if current_param_split[0] == 'dimensions':
current_dimension_split = (
current_param_split[1].split(','))
for current_dimension in current_dimension_split:
current_dimen_data = current_dimension.split(':')
queries.append({
'query_string': {
'default_field': (field_string +
current_dimen_data[0]),
'query': current_dimen_data[1]
}
})
elif current_param_split[0] in ['limit', 'offset']:
# ignore the limit and offset for now.
pass
else:
queries.append({
'query_string': {
'default_field': current_param_split[0],
'query': current_param_split[1]
}
})
LOG.debug(queries)
query = {
'query': {
'bool': {
'must': queries
}
}
}
LOG.debug('Parsed Query: %s' % query)
return query
@resource_api.Restify('/v2.0/alarm-definitions/', method='post')
def do_post_alarm_definitions(self, req, res):
LOG.debug('Creating the alarm definitions')
msg = req.stream.read()
LOG.debug("Message: %s" % msg)
post_msg = ast.literal_eval(msg)
# random uuid generation for alarm definition
id = str(uuid.uuid4())
post_msg["id"] = id
post_msg = AlarmDefinitionUtil.severityparsing(post_msg)
post_msg_json = json.dumps(post_msg)
LOG.debug("Validating Alarm Definition Data: %s" % post_msg_json)
if alarm_expr_validator.is_valid_alarm_definition(post_msg_json):
LOG.debug("Post Alarm Definition method: %s" % post_msg)
try:
expression_parsed = (
alarm_expr_parser.AlarmExprParser(post_msg["expression"]))
expression_data = expression_parsed.sub_alarm_expressions
expression_data_list = []
for temp in expression_data:
expression_data_list.append(expression_data[temp])
post_msg["expression_data"] = expression_data_list
LOG.debug(post_msg)
es_res = self._es_conn.post_messages(json.dumps(post_msg), id)
LOG.debug('Query to ElasticSearch returned Status: %s' %
es_res)
res.status = getattr(falcon, 'HTTP_%s' % es_res)
except Exception:
LOG.exception('Error occurred while handling '
'Alarm Definition Post Request.')
res.status = getattr(falcon, 'HTTP_400')
else:
LOG.error('Alarm definition is not valid.')
res.status = getattr(falcon, 'HTTP_400')
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='get')
def do_get_alarm_definitions_by_id(self, req, res, id):
LOG.debug('The alarm definitions GET request is received!')
LOG.debug(id)
es_res = self._es_conn.get_message_by_id(id)
res.status = getattr(falcon, 'HTTP_%s' % es_res.status_code)
LOG.debug('Query to ElasticSearch returned Status: %s' %
es_res.status_code)
es_res = self._get_alarm_definitions_response(es_res)
LOG.debug('Query to ElasticSearch returned: %s' % es_res)
res.body = ''
try:
if es_res["hits"]:
res_data = es_res["hits"][0]
if res_data:
res.body = json.dumps({
"id": id,
"links": [{"rel": "self",
"href": req.uri}],
"name": res_data["_source"]["name"],
"description": res_data["_source"]["description"],
"expression": res_data["_source"]["expression"],
"expression_data":
res_data["_source"]["expression_data"],
"severity": res_data["_source"]["severity"],
"match_by": res_data["_source"]["match_by"],
"alarm_actions": res_data["_source"]["alarm_actions"],
"ok_actions": res_data["_source"]["ok_actions"],
"undetermined_actions": res_data["_source"]
["undetermined_actions"]})
res.content_type = 'application/json;charset=utf-8'
except Exception:
LOG.exception('Error occurred while handling Alarm Definition '
'Get Request.')
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='put')
def do_put_alarm_definitions(self, req, res, id):
LOG.debug("Put the alarm definitions with id: %s" % id)
es_res = self._es_conn.get_message_by_id(id)
LOG.debug('Query to ElasticSearch returned Status: %s' %
es_res.status_code)
es_res = self._get_alarm_definitions_response(es_res)
LOG.debug('Query to ElasticSearch returned: %s' % es_res)
original_data = {}
try:
if es_res["hits"]:
res_data = es_res["hits"][0]
if res_data:
original_data = json.dumps({
"id": id,
"name": res_data["_source"]["name"],
"description": res_data["_source"]["description"],
"expression": res_data["_source"]["expression"],
"expression_data":
res_data["_source"]["expression_data"],
"severity": res_data["_source"]["severity"],
"match_by": res_data["_source"]["match_by"],
"alarm_actions": res_data["_source"]["alarm_actions"],
"ok_actions": res_data["_source"]["ok_actions"],
"undetermined_actions": res_data["_source"]
["undetermined_actions"]})
msg = req.stream.read()
put_msg = ast.literal_eval(msg)
put_msg = AlarmDefinitionUtil.severityparsing(put_msg)
expression_parsed = (
alarm_expr_parser.AlarmExprParser(put_msg["expression"])
)
expression_data = expression_parsed.sub_alarm_expressions
expression_data_list = []
for temp in expression_data:
expression_data_list.append(expression_data[temp])
put_msg["expression_data"] = expression_data_list
put_msg_json = json.dumps(put_msg)
LOG.debug("Alarm Definition Put Data: %s" % put_msg_json)
if alarm_expr_validator.is_valid_update_alarm_definition(
original_data, put_msg_json):
es_res = self._es_conn.put_messages(put_msg_json, id)
LOG.debug('Query to ElasticSearch returned Status: %s' %
es_res)
res.status = getattr(falcon, 'HTTP_%s' % es_res)
else:
res.status = getattr(falcon, 'HTTP_400')
LOG.debug("Validating Alarm Definition Failed !!")
except Exception:
res.status = getattr(falcon, 'HTTP_400')
LOG.exception('Error occurred while handling Alarm '
'Definition Put Request.')
@resource_api.Restify('/v2.0/alarm-definitions/{id}', method='delete')
def do_delete_alarm_definitions(self, req, res, id):
LOG.debug("Delete the alarm definitions with id: %s" % id)
try:
es_res = self._es_conn.del_messages(id)
LOG.debug('Query to ElasticSearch returned Status: %s' %
es_res)
res.status = getattr(falcon, 'HTTP_%s' % es_res)
except Exception:
res.status = getattr(falcon, 'HTTP_400')
LOG.exception('Error occurred while handling Alarm '
'Definition Delete Request.')
@resource_api.Restify('/v2.0/alarm-definitions/', method='get')
def do_get_alarm_definitions_filtered(self, req, res):
LOG.debug('The alarm definitions GET request is received!')
query_string = req.query_string
LOG.debug('Request Query String: %s' % query_string)
params = self._get_alarm_definitions_helper(query_string)
LOG.debug('Query Data: %s' % params)
es_res = self._es_conn.get_messages(params)
res.status = getattr(falcon, 'HTTP_%s' % es_res.status_code)
LOG.debug('Query to ElasticSearch returned Status: %s' %
es_res.status_code)
es_res = self._get_alarm_definitions_response(es_res)
LOG.debug('Query to ElasticSearch returned: %s' % es_res)
res.body = ''
result_elements = []
try:
if es_res["hits"]:
res_data = es_res["hits"]
for current_alarm in res_data:
if current_alarm:
result_elements.append({
"id": current_alarm["_source"]["id"],
"links": [{"rel": "self",
"href": req.uri}],
"name": current_alarm["_source"]["name"],
"description":
current_alarm["_source"]["description"],
"expression":
current_alarm["_source"]["expression"],
"expression_data":
current_alarm["_source"]["expression_data"],
"severity":
current_alarm["_source"]["severity"],
"match_by":
current_alarm["_source"]["match_by"],
"alarm_actions":
current_alarm["_source"]["alarm_actions"],
"ok_actions":
current_alarm["_source"]["ok_actions"],
"undetermined_actions":
current_alarm["_source"]
["undetermined_actions"]})
res.body = json.dumps({
"links": [{"rel": "self", "href": req.uri}],
"elements": result_elements
})
else:
res.body = ""
res.content_type = 'application/json;charset=utf-8'
except Exception:
res.status = getattr(falcon, 'HTTP_400')
LOG.exception('Error occurred while handling Alarm '
'Definitions Get Request.')