From 2bdf4023aa0e0c4d61af6af969fb8c90522e2fe0 Mon Sep 17 00:00:00 2001 From: Benjamin Diaz Date: Wed, 6 Mar 2019 15:53:56 -0300 Subject: [PATCH] Adds support for multiple alarm statuses Requirement for Feature 6373 Change-Id: I5440c6cdd8e4b3ad12bcf8949871c67a74f31500 Signed-off-by: Benjamin Diaz --- osm_mon/collector/vnf_collectors/openstack.py | 9 ++- osm_mon/core/common_db.py | 4 +- osm_mon/core/database.py | 75 ++++++++++--------- osm_mon/evaluator/evaluator.py | 40 +++++++--- 4 files changed, 79 insertions(+), 49 deletions(-) diff --git a/osm_mon/collector/vnf_collectors/openstack.py b/osm_mon/collector/vnf_collectors/openstack.py index 4cf798f..33d6299 100644 --- a/osm_mon/collector/vnf_collectors/openstack.py +++ b/osm_mon/collector/vnf_collectors/openstack.py @@ -115,7 +115,14 @@ class OpenstackCollector(BaseVimCollector): for param in vdu['monitoring-param']: metric_name = param['nfvi-metric'] openstack_metric_name = METRIC_MAPPINGS[metric_name] - resource_id = self._get_resource_uuid(nsr_id, vnf_member_index, vdur['name']) + try: + resource_id = self._get_resource_uuid(nsr_id, vnf_member_index, vdur['name']) + except ValueError: + log.warning( + "Could not find resource_uuid for vdur %s, vnf_member_index %s, nsr_id %s. " + "Was it recently deleted?".format( + vdur['name'], vnf_member_index, nsr_id)) + continue if self.backend == 'ceilometer': measures = self.client.samples.list(meter_name=openstack_metric_name, limit=1, q=[ {'field': 'resource_id', 'op': 'eq', 'value': resource_id}]) diff --git a/osm_mon/core/common_db.py b/osm_mon/core/common_db.py index 2d31f6c..12c15dc 100644 --- a/osm_mon/core/common_db.py +++ b/osm_mon/core/common_db.py @@ -74,8 +74,8 @@ class CommonDbClient: for vdur in vnfr['vdur']: if vdur['name'] == vdur_name: return vdur - raise ValueError('vdur not found for nsr-id %s, member_index %s and vdur_name %s', nsr_id, member_index, - vdur_name) + raise ValueError('vdur not found for nsr-id {}, member_index {} and vdur_name {}'.format(nsr_id, member_index, + vdur_name)) def decrypt_vim_password(self, vim_password: str, schema_version: str, vim_id: str): return self.common_db.decrypt(vim_password, schema_version, vim_id) diff --git a/osm_mon/core/database.py b/osm_mon/core/database.py index 3b601b2..d1c2e6b 100644 --- a/osm_mon/core/database.py +++ b/osm_mon/core/database.py @@ -22,10 +22,10 @@ # contact: bdiaz@whitestack.com or glavado@whitestack.com ## +import json import logging import os import uuid -import json from peewee import CharField, TextField, FloatField, Model, AutoField, Proxy from peewee_migrate import Router @@ -83,51 +83,59 @@ class DatabaseManager: def get_credentials(self, vim_uuid: str = None) -> VimCredentials: db.connect() - with db.atomic(): - vim_credentials = VimCredentials.get_or_none(VimCredentials.uuid == vim_uuid) - db.close() - return vim_credentials + try: + with db.atomic(): + vim_credentials = VimCredentials.get_or_none(VimCredentials.uuid == vim_uuid) + return vim_credentials + finally: + db.close() def save_credentials(self, vim_credentials) -> VimCredentials: """Saves vim credentials. If a record with same uuid exists, overwrite it.""" db.connect() - with db.atomic(): - exists = VimCredentials.get_or_none(VimCredentials.uuid == vim_credentials.uuid) - if exists: - vim_credentials.id = exists.id - vim_credentials.save() - db.close() - return vim_credentials + try: + with db.atomic(): + exists = VimCredentials.get_or_none(VimCredentials.uuid == vim_credentials.uuid) + if exists: + vim_credentials.id = exists.id + vim_credentials.save() + return vim_credentials + finally: + db.close() def get_alarm(self, alarm_id) -> Alarm: db.connect() - with db.atomic(): - alarm = (Alarm.select() - .where(Alarm.alarm_id == alarm_id) - .get()) - db.close() - return alarm + try: + with db.atomic(): + alarm = (Alarm.select() + .where(Alarm.alarm_id == alarm_id) + .get()) + return alarm + finally: + db.close() def save_alarm(self, name, threshold, operation, severity, statistic, metric_name, vdur_name, vnf_member_index, nsr_id) -> Alarm: """Saves alarm.""" # TODO: Add uuid optional param and check if exists to handle updates (see self.save_credentials) db.connect() - with db.atomic(): - alarm = Alarm() - alarm.uuid = str(uuid.uuid4()) - alarm.name = name - alarm.threshold = threshold - alarm.operation = operation - alarm.severity = severity - alarm.statistic = statistic - alarm.monitoring_param = metric_name - alarm.vdur_name = vdur_name - alarm.vnf_member_index = vnf_member_index - alarm.nsr_id = nsr_id - alarm.save() - db.close() - return alarm + try: + with db.atomic(): + alarm = Alarm() + alarm.uuid = str(uuid.uuid4()) + alarm.name = name + alarm.threshold = threshold + alarm.operation = operation + alarm.severity = severity + alarm.statistic = statistic + alarm.monitoring_param = metric_name + alarm.vdur_name = vdur_name + alarm.vnf_member_index = vnf_member_index + alarm.nsr_id = nsr_id + alarm.save() + return alarm + finally: + db.close() def delete_alarm(self, alarm_uuid) -> None: db.connect() @@ -140,7 +148,6 @@ class DatabaseManager: def get_vim_type(self, vim_account_id) -> str: """Get the vim type that is required by the message.""" - vim_type = None credentials = self.get_credentials(vim_account_id) config = json.loads(credentials.config) if 'vim_type' in config: diff --git a/osm_mon/evaluator/evaluator.py b/osm_mon/evaluator/evaluator.py index 76881b9..90c0c17 100644 --- a/osm_mon/evaluator/evaluator.py +++ b/osm_mon/evaluator/evaluator.py @@ -24,6 +24,7 @@ import asyncio import logging import multiprocessing import time +from enum import Enum import peewee import requests @@ -39,7 +40,14 @@ from osm_mon.core.response import ResponseBuilder log = logging.getLogger(__name__) +class AlarmStatus(Enum): + ALARM = 'alarm' + OK = 'ok' + INSUFFICIENT = 'insufficient-data' + + class Evaluator: + def __init__(self, config: Config, loop=None): self.conf = config if not loop: @@ -74,12 +82,18 @@ class Evaluator: log.info("Metric value: %s", metric_value) if alarm.operation.upper() == 'GT': if metric_value > alarm.threshold: - self.queue.put(alarm) + self.queue.put((alarm, AlarmStatus.ALARM)) + else: + self.queue.put((alarm, AlarmStatus.OK)) elif alarm.operation.upper() == 'LT': if metric_value < alarm.threshold: - self.queue.put(alarm) + self.queue.put((alarm, AlarmStatus.ALARM)) + else: + self.queue.put((alarm, AlarmStatus.OK)) else: log.warning("No metric result for alarm %s", alarm.id) + self.queue.put((alarm, AlarmStatus.INSUFFICIENT)) + else: log.warning("Prometheus response is not success. Got status %s", json_response['status']) else: @@ -155,20 +169,24 @@ class Evaluator: for process in processes: process.join(timeout=10) - triggered_alarms = [] + alarms_tuples = [] while not self.queue.empty(): - triggered_alarms.append(self.queue.get()) - for alarm in triggered_alarms: + alarms_tuples.append(self.queue.get()) + for alarm, status in alarms_tuples: p = multiprocessing.Process(target=self.notify_alarm, - args=(alarm,)) + args=(alarm, status)) p.start() - def notify_alarm(self, alarm: Alarm): + def notify_alarm(self, alarm: Alarm, status: AlarmStatus): log.debug("notify_alarm") + resp_message = self._build_alarm_response(alarm, status) + log.info("Sent alarm notification: %s", resp_message) + self.loop.run_until_complete(self.msg_bus.aiowrite('alarm_response', 'notify_alarm', resp_message)) + + def _build_alarm_response(self, alarm: Alarm, status: AlarmStatus): response = ResponseBuilder() now = time.strftime("%d-%m-%Y") + " " + time.strftime("%X") - # Generate and send response - resp_message = response.generate_response( + return response.generate_response( 'notify_alarm', alarm_id=alarm.uuid, vdu_name=alarm.vdur_name, @@ -178,7 +196,5 @@ class Evaluator: operation=alarm.operation, threshold_value=alarm.threshold, sev=alarm.severity, - status='alarm', + status=status.value, date=now) - self.loop.run_until_complete(self.msg_bus.aiowrite('alarm_response', 'notify_alarm', resp_message)) - log.info("Sent alarm notification: %s", resp_message) -- 2.17.1