X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=osm_policy_module%2Falarming%2Fservice.py;h=f5a5d9eb96808b7b650cfa8b5af412d9bb109e99;hb=0d4d67da510e7f9c1169ba36178e8f699bb81b42;hp=37fa6a1f0bc78f957c81fc13775cbc0231bfbe4f;hpb=4584f8e86a492d67d120bfea1195eff1475c0a65;p=osm%2FPOL.git diff --git a/osm_policy_module/alarming/service.py b/osm_policy_module/alarming/service.py index 37fa6a1..f5a5d9e 100644 --- a/osm_policy_module/alarming/service.py +++ b/osm_policy_module/alarming/service.py @@ -22,12 +22,13 @@ # For those usages not covered by the Apache License, Version 2.0 please # contact: bdiaz@whitestack.com or glavado@whitestack.com ## -import asyncio import json import logging +import operator +import functools import requests -from requests.exceptions import ConnectionError +from requests.exceptions import ConnectionError, RequestException from osm_policy_module.common.common_db_client import CommonDbClient from osm_policy_module.common.lcm_client import LcmClient @@ -45,22 +46,25 @@ log = logging.getLogger(__name__) class AlarmingService: - def __init__(self, config: Config, loop=None): + def __init__(self, config: Config): self.conf = config - if not loop: - loop = asyncio.get_event_loop() - self.loop = loop self.db_client = CommonDbClient(config) - self.mon_client = MonClient(config, loop=self.loop) - self.lcm_client = LcmClient(config, loop=self.loop) + self.mon_client = MonClient(config) + self.lcm_client = LcmClient(config) - async def configure_vnf_alarms(self, nsr_id: str): + async def configure_vnf_alarms(self, nsr_id: str, vnf_member_index=None): log.info("Configuring vnf alarms for network service %s", nsr_id) alarms_created = [] database.db.connect() try: with database.db.atomic(): - vnfrs = self.db_client.get_vnfrs(nsr_id) + if vnf_member_index is None: + vnfrs = self.db_client.get_vnfrs(nsr_id) + else: + vnfrs = [] + vnfr = self.db_client.get_vnfr(nsr_id, vnf_member_index) + vnfrs.append(vnfr) + # vnfrs = self.db_client.get_vnfrs(nsr_id) for vnfr in vnfrs: log.debug("Processing vnfr: %s", vnfr) vnfd = self.db_client.get_vnfd(vnfr["vnfd-id"]) @@ -101,6 +105,21 @@ class AlarmingService: metric_name = self._get_metric_name( vnf_monitoring_param ) + alarm_action = dict() + for action_type in ["ok", "insufficient-data", "alarm"]: + if ( + "actions" in alarm_descriptor + and action_type in alarm_descriptor["actions"] + ): + for url in alarm_descriptor["actions"][ + action_type + ]: + if "webhook" in alarm_action: + alarm_action["webhook"].append( + url["url"] + ) + else: + alarm_action["webhook"] = [url["url"]] alarm_uuid = await self.mon_client.create_alarm( metric_name=metric_name, ns_id=nsr_id, @@ -108,6 +127,7 @@ class AlarmingService: vnf_member_index=vnfr["member-vnf-index-ref"], threshold=alarm_descriptor["value"], operation=alarm_descriptor["operation"], + action=str(alarm_action), ) alarm = VnfAlarmRepository.create( alarm_id=alarm_descriptor["alarm-id"], @@ -115,6 +135,10 @@ class AlarmingService: nsr_id=nsr_id, vnf_member_index=vnfr["member-vnf-index-ref"], vdu_name=vdur["name"], + last_action="insufficient-data", + id_suffix=0, + ok_ack=False, + alarm_ack=False, ) for action_type in ["ok", "insufficient-data", "alarm"]: if ( @@ -182,12 +206,20 @@ class AlarmingService: finally: database.db.close() - async def delete_vnf_alarms(self, nsr_id): + async def delete_vnf_alarms(self, nsr_id, vnf_member_index=None): log.info("Deleting vnf alarms for network service %s", nsr_id) database.db.connect() try: with database.db.atomic(): - for alarm in VnfAlarmRepository.list(VnfAlarm.nsr_id == nsr_id): + if vnf_member_index is None: + alarm_conditions = VnfAlarm.nsr_id == nsr_id + else: + query_list = [ + VnfAlarm.nsr_id == nsr_id, + VnfAlarm.vnf_member_index == vnf_member_index, + ] + alarm_conditions = functools.reduce(operator.and_, query_list) + for alarm in VnfAlarmRepository.list(alarm_conditions): log.debug("Deleting vnf alarm %s", alarm.alarm_uuid) try: await self.mon_client.delete_alarm( @@ -209,6 +241,7 @@ class AlarmingService: database.db.close() async def handle_alarm(self, alarm_uuid: str, status: str, payload: dict): + alert_timeout = int(self.conf.get("alert", "timeout")) database.db.connect() try: with database.db.atomic(): @@ -217,17 +250,92 @@ class AlarmingService: "Handling vnf alarm %s with status %s", alarm.alarm_id, status ) for action in alarm.actions: + """ + Compares the current status with the last_action status. + If both the status are 'alarm', it avoid sending repetitive alarm notification. + If both the status are 'ok', it avoid sending repetitive ok notification. + """ if action.type == status: - log.info( - "Executing request to url %s for vnf alarm %s with status %s", - action.url, - alarm.alarm_id, - status, - ) - try: - requests.post(url=action.url, json=json.dumps(payload)) - except ConnectionError: - log.exception("Error connecting to url %s", action.url) + if bool(self.conf.get("alert", "enhanced_alarms")): + if ( + status != "ok" + or (status == "ok" and alarm.ok_ack is False) + ) and ( + status != "alarm" + or (status == "alarm" and alarm.alarm_ack is False) + ): + log.info( + "Executing request to url %s for vnf alarm %s with status %s", + action.url, + alarm.alarm_id, + status, + ) + try: + if status == "alarm" and alarm.last_action == "ok": + alarm.id_suffix += 1 + alarm.ok_ack = False + if status == "ok" and alarm.last_action == "alarm": + alarm.alarm_ack = False + alarm.last_action = status + alarm.save() + except Exception as e: + log.exception(e) + + payload["notify_details"][ + "alarm_number" + ] = alarm.id_suffix + headers = {"content-type": "application/json"} + try: + resp = requests.post( + url=action.url, + data=json.dumps(payload), + headers=headers, + timeout=alert_timeout, + ) + log.info("Response %s", resp) + if resp.status_code == 200: + if status == "ok": + alarm.ok_ack = True + alarm.save() + if status == "alarm": + alarm.alarm_ack = True + alarm.save() + if status == "insufficient-data": + alarm.alarm_ack = False + alarm.ok_ack = False + alarm.save() + except ConnectionError: + log.exception( + "Error connecting to url %s", action.url + ) + except RequestException as e: + log.info( + "Error: RequestException while connecting to url %s", + action.url, + ) + log.debug("RequestException %s", e) + + else: + log.info( + "Executing request to url %s for vnf alarm %s with status %s", + action.url, + alarm.alarm_id, + status, + ) + try: + requests.post( + url=action.url, + json=json.dumps(payload), + timeout=alert_timeout, + ) + except ConnectionError: + log.exception("Error connecting to url %s", action.url) + except RequestException as e: + log.info( + "Error: RequestException while connecting to url %s", + action.url, + ) + log.debug("RequestException %s", e) except VnfAlarm.DoesNotExist: log.debug(