"Fossies" - the Fresh Open Source Software Archive

Member "monasca-api-3.1.0/monasca_api/v2/reference/alarming.py" (27 Sep 2019, 7619 Bytes) of package /linux/misc/openstack/monasca-api-3.1.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "alarming.py" see the Fossies "Dox" file reference documentation.

    1 # Copyright 2014,2016 Hewlett Packard Enterprise Development Company, L.P.
    2 #
    3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
    4 # not use this file except in compliance with the License. You may obtain
    5 # a copy of the License at
    6 #
    7 # http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 # Unless required by applicable law or agreed to in writing, software
   10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   12 # License for the specific language governing permissions and limitations
   13 # under the License.
   14 
   15 import falcon
   16 from monasca_common.simport import simport
   17 from oslo_config import cfg
   18 from oslo_log import log
   19 
   20 from monasca_api.common.messaging import (
   21     exceptions as message_queue_exceptions)
   22 import monasca_api.expression_parser.alarm_expr_parser
   23 from monasca_api.v2.reference import helpers
   24 
   25 LOG = log.getLogger(__name__)
   26 
   27 
   28 class Alarming(object):
   29     """Super class for Alarms and AlarmDefinitions.
   30 
   31     Shared attributes and methods for classes Alarms and AlarmDefinitions.
   32     """
   33 
   34     def __init__(self):
   35 
   36         super(Alarming, self).__init__()
   37 
   38         self.events_message_queue = simport.load(
   39             cfg.CONF.messaging.driver)(cfg.CONF.kafka.events_topic)
   40 
   41         self.alarm_state_transitions_message_queue = simport.load(
   42             cfg.CONF.messaging.driver)(cfg.CONF.kafka.alarm_state_transitions_topic)
   43 
   44     def _send_alarm_transitioned_event(self, tenant_id, alarm_id,
   45                                        alarm_definition_row,
   46                                        alarm_metric_rows,
   47                                        old_state, new_state,
   48                                        link, lifecycle_state,
   49                                        time_ms):
   50 
   51         # This is a change via the API, so there is no SubAlarm info to add
   52         sub_alarms = []
   53         metrics = []
   54         alarm_transitioned_event_msg = {u'alarm-transitioned': {
   55             u'tenantId': tenant_id,
   56             u'alarmId': alarm_id,
   57             u'alarmDefinitionId': alarm_definition_row['id'],
   58             u'alarmName': alarm_definition_row['name'],
   59             u'alarmDescription': alarm_definition_row['description'],
   60             u'actionsEnabled': alarm_definition_row['actions_enabled'] == 1,
   61             u'stateChangeReason': 'Alarm state updated via API',
   62             u'severity': alarm_definition_row['severity'],
   63             u'link': link,
   64             u'lifecycleState': lifecycle_state,
   65             u'oldState': old_state,
   66             u'newState': new_state,
   67             u'timestamp': time_ms,
   68             u'subAlarms': sub_alarms,
   69             u'metrics': metrics}
   70         }
   71 
   72         for alarm_metric_row in alarm_metric_rows:
   73             metric = self._build_metric(alarm_metric_row)
   74             metrics.append(metric)
   75 
   76         self.send_event(self.alarm_state_transitions_message_queue,
   77                         alarm_transitioned_event_msg)
   78 
   79     def _build_metric(self, alarm_metric_row):
   80 
   81         dimensions = {}
   82 
   83         metric = {u'name': alarm_metric_row['name'],
   84                   u'dimensions': dimensions}
   85 
   86         if alarm_metric_row['dimensions']:
   87             for dimension in alarm_metric_row['dimensions'].split(','):
   88                 parsed_dimension = dimension.split('=')
   89                 dimensions[parsed_dimension[0]] = parsed_dimension[1]
   90 
   91         return metric
   92 
   93     def _send_alarm_event(self, event_type, tenant_id, alarm_definition_id,
   94                           alarm_metric_rows, sub_alarm_rows, link, lifecycle_state,
   95                           extra_info=None):
   96 
   97         if not alarm_metric_rows:
   98             return
   99 
  100         # Build a dict mapping alarm id -> list of sub alarms.
  101         sub_alarm_dict = {}
  102         for sub_alarm_row in sub_alarm_rows:
  103             if sub_alarm_row['alarm_id'] in sub_alarm_dict:
  104                 sub_alarm_dict[sub_alarm_row['alarm_id']] += [sub_alarm_row]
  105             else:
  106                 sub_alarm_dict[sub_alarm_row['alarm_id']] = [sub_alarm_row]
  107 
  108         # Forward declaration.
  109         alarm_event_msg = {}
  110         prev_alarm_id = None
  111         for alarm_metric_row in alarm_metric_rows:
  112             if prev_alarm_id != alarm_metric_row['alarm_id']:
  113                 if prev_alarm_id is not None:
  114                     sub_alarms_event_msg = (
  115                         self._build_sub_alarm_event_msg(sub_alarm_dict,
  116                                                         prev_alarm_id))
  117                     alarm_event_msg[event_type][u'subAlarms'] = sub_alarms_event_msg
  118                     self.send_event(self.events_message_queue,
  119                                     alarm_event_msg)
  120 
  121                 alarm_metrics_event_msg = []
  122                 alarm_event_msg = {event_type: {u'tenantId': tenant_id,
  123                                                 u'alarmDefinitionId':
  124                                                     alarm_definition_id,
  125                                                 u'alarmId': alarm_metric_row[
  126                                                     'alarm_id'],
  127                                                 u'link': link,
  128                                                 u'lifecycleState': lifecycle_state,
  129                                                 u'alarmMetrics':
  130                                                     alarm_metrics_event_msg}}
  131                 if extra_info:
  132                     alarm_event_msg[event_type].update(extra_info)
  133 
  134                 prev_alarm_id = alarm_metric_row['alarm_id']
  135 
  136             metric = self._build_metric(alarm_metric_row)
  137             alarm_metrics_event_msg.append(metric)
  138 
  139         # Finish last alarm
  140         sub_alarms_event_msg = self._build_sub_alarm_event_msg(sub_alarm_dict,
  141                                                                prev_alarm_id)
  142         alarm_event_msg[event_type][u'subAlarms'] = sub_alarms_event_msg
  143 
  144         self.send_event(self.events_message_queue,
  145                         alarm_event_msg)
  146 
  147     def _build_sub_alarm_event_msg(self, sub_alarm_dict, alarm_id):
  148 
  149         sub_alarms_event_msg = {}
  150 
  151         if alarm_id not in sub_alarm_dict:
  152             return sub_alarms_event_msg
  153 
  154         for sub_alarm in sub_alarm_dict[alarm_id]:
  155             # There's only one expr in a sub alarm, so just take the first.
  156             sub_expr = (
  157                 monasca_api.expression_parser.alarm_expr_parser.
  158                 AlarmExprParser(sub_alarm['expression']).sub_expr_list[0])
  159             dimensions = {}
  160             sub_alarms_event_msg[sub_alarm['sub_alarm_id']] = {
  161                 u'function': sub_expr.normalized_func,
  162                 u'metricDefinition': {u'name': sub_expr.metric_name,
  163                                       u'dimensions': dimensions},
  164                 u'operator': sub_expr.normalized_operator,
  165                 u'threshold': sub_expr.threshold, u'period': sub_expr.period,
  166                 u'periods': sub_expr.periods,
  167                 u'expression': sub_expr.fmtd_sub_expr_str}
  168 
  169             for dimension in sub_expr.dimensions_as_list:
  170                 parsed_dimension = dimension.split('=')
  171                 dimensions[parsed_dimension[0]] = parsed_dimension[1]
  172 
  173         return sub_alarms_event_msg
  174 
  175     def send_event(self, message_queue, event_msg):
  176         try:
  177             message_queue.send_message(helpers.to_json(event_msg))
  178         except message_queue_exceptions.MessageQueueException as ex:
  179             LOG.exception(ex)
  180             raise falcon.HTTPInternalServerError(
  181                 'Message queue service unavailable'.encode('utf8'),
  182                 str(ex).encode('utf8'))