1 # -*- coding: utf-8 -*-
2 # pylint: disable=no-member
4 # Copyright 2018 Whitestack, LLC
5 # *************************************************************
7 # This file is part of OSM Monitoring module
8 # All Rights Reserved to Whitestack, LLC
10 # Licensed under the Apache License, Version 2.0 (the "License"); you may
11 # not use this file except in compliance with the License. You may obtain
12 # a copy of the License at
14 # http://www.apache.org/licenses/LICENSE-2.0
16 # Unless required by applicable law or agreed to in writing, software
17 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
19 # License for the specific language governing permissions and limitations
22 # For those usages not covered by the Apache License, Version 2.0 please
23 # contact: bdiaz@whitestack.com or glavado@whitestack.com
32 from requests
.exceptions
import ConnectionError
, RequestException
34 from osm_policy_module
.common
.common_db_client
import CommonDbClient
35 from osm_policy_module
.common
.lcm_client
import LcmClient
36 from osm_policy_module
.common
.mon_client
import MonClient
37 from osm_policy_module
.core
import database
38 from osm_policy_module
.core
.config
import Config
39 from osm_policy_module
.core
.database
import (
42 AlarmActionRepository
,
44 from osm_policy_module
.core
.exceptions
import VdurNotFound
46 log
= logging
.getLogger(__name__
)
49 class AlarmingService
:
50 def __init__(self
, config
: Config
, loop
=None):
53 loop
= asyncio
.get_event_loop()
55 self
.db_client
= CommonDbClient(config
)
56 self
.mon_client
= MonClient(config
, loop
=self
.loop
)
57 self
.lcm_client
= LcmClient(config
, loop
=self
.loop
)
59 async def configure_vnf_alarms(self
, nsr_id
: str, vnf_member_index
=None):
60 log
.info("Configuring vnf alarms for network service %s", nsr_id
)
64 with database
.db
.atomic():
65 if vnf_member_index
is None:
66 vnfrs
= self
.db_client
.get_vnfrs(nsr_id
)
69 vnfr
= self
.db_client
.get_vnfr(nsr_id
, vnf_member_index
)
71 # vnfrs = self.db_client.get_vnfrs(nsr_id)
73 log
.debug("Processing vnfr: %s", vnfr
)
74 vnfd
= self
.db_client
.get_vnfd(vnfr
["vnfd-id"])
75 for vdur
in vnfr
["vdur"]:
78 lambda vdu
: vdu
["id"] == vdur
["vdu-id-ref"], vnfd
["vdu"]
82 alarm_descriptors
= vdu
["alarm"]
83 for alarm_descriptor
in alarm_descriptors
:
85 VnfAlarmRepository
.get(
87 == alarm_descriptor
["alarm-id"],
88 VnfAlarm
.vnf_member_index
89 == vnfr
["member-vnf-index-ref"],
90 VnfAlarm
.vdu_name
== vdur
["name"],
91 VnfAlarm
.nsr_id
== nsr_id
,
94 "vdu %s already has an alarm configured with same id %s",
96 alarm_descriptor
["alarm-id"],
99 except VnfAlarm
.DoesNotExist
:
101 vnf_monitoring_param
= next(
103 lambda param
: param
["id"]
104 == alarm_descriptor
["vnf-monitoring-param-ref"],
105 vdu
.get("monitoring-parameter", []),
109 metric_name
= self
._get
_metric
_name
(
112 alarm_action
= dict()
113 for action_type
in ["ok", "insufficient-data", "alarm"]:
115 "actions" in alarm_descriptor
116 and action_type
in alarm_descriptor
["actions"]
118 for url
in alarm_descriptor
["actions"][
121 if "webhook" in alarm_action
:
122 alarm_action
["webhook"].append(
126 alarm_action
["webhook"] = [url
["url"]]
127 alarm_uuid
= await self
.mon_client
.create_alarm(
128 metric_name
=metric_name
,
130 vdu_name
=vdur
["name"],
131 vnf_member_index
=vnfr
["member-vnf-index-ref"],
132 threshold
=alarm_descriptor
["value"],
133 operation
=alarm_descriptor
["operation"],
134 action
=str(alarm_action
),
136 alarm
= VnfAlarmRepository
.create(
137 alarm_id
=alarm_descriptor
["alarm-id"],
138 alarm_uuid
=alarm_uuid
,
140 vnf_member_index
=vnfr
["member-vnf-index-ref"],
141 vdu_name
=vdur
["name"],
142 last_action
="insufficient-data",
147 for action_type
in ["ok", "insufficient-data", "alarm"]:
149 "actions" in alarm_descriptor
150 and action_type
in alarm_descriptor
["actions"]
152 for url
in alarm_descriptor
["actions"][
155 AlarmActionRepository
.create(
160 alarms_created
.append(alarm
)
162 except Exception as e
:
163 log
.exception("Error configuring VNF alarms:")
164 if len(alarms_created
) > 0:
165 log
.debug("Cleaning alarm resources in MON")
166 for alarm
in alarms_created
:
168 await self
.mon_client
.delete_alarm(
170 alarm
.vnf_member_index
,
176 "Error deleting alarm in MON %s", alarm
.alarm_uuid
182 async def delete_orphaned_alarms(self
, nsr_id
):
183 # TODO: Review as it seems this code is never called
184 log
.info("Deleting orphaned vnf alarms for network service %s", nsr_id
)
185 database
.db
.connect()
187 with database
.db
.atomic():
188 for alarm
in VnfAlarmRepository
.list(VnfAlarm
.nsr_id
== nsr_id
):
190 self
.db_client
.get_vdur(
191 nsr_id
, alarm
.vnf_member_index
, alarm
.vdu_name
194 log
.debug("Deleting orphaned alarm %s", alarm
.alarm_uuid
)
196 await self
.mon_client
.delete_alarm(
198 alarm
.vnf_member_index
,
204 "Error deleting alarm in MON %s", alarm
.alarm_uuid
206 alarm
.delete_instance()
207 except Exception as e
:
208 log
.exception("Error deleting orphaned alarms:")
213 async def delete_vnf_alarms(self
, nsr_id
, vnf_member_index
=None):
214 log
.info("Deleting vnf alarms for network service %s", nsr_id
)
215 database
.db
.connect()
217 with database
.db
.atomic():
218 if vnf_member_index
is None:
219 alarm_conditions
= VnfAlarm
.nsr_id
== nsr_id
222 VnfAlarm
.nsr_id
== nsr_id
,
223 VnfAlarm
.vnf_member_index
== vnf_member_index
,
225 alarm_conditions
= functools
.reduce(operator
.and_
, query_list
)
226 for alarm
in VnfAlarmRepository
.list(alarm_conditions
):
227 log
.debug("Deleting vnf alarm %s", alarm
.alarm_uuid
)
229 await self
.mon_client
.delete_alarm(
231 alarm
.vnf_member_index
,
237 "Error deleting alarm in MON %s", alarm
.alarm_uuid
239 alarm
.delete_instance()
241 except Exception as e
:
242 log
.exception("Error deleting vnf alarms:")
247 async def handle_alarm(self
, alarm_uuid
: str, status
: str, payload
: dict):
248 alert_timeout
= int(self
.conf
.get("alert", "timeout"))
249 database
.db
.connect()
251 with database
.db
.atomic():
252 alarm
= VnfAlarmRepository
.get(VnfAlarm
.alarm_uuid
== alarm_uuid
)
254 "Handling vnf alarm %s with status %s", alarm
.alarm_id
, status
256 for action
in alarm
.actions
:
258 Compares the current status with the last_action status.
259 If both the status are 'alarm', it avoid sending repetitive alarm notification.
260 If both the status are 'ok', it avoid sending repetitive ok notification.
262 if action
.type == status
:
263 if bool(self
.conf
.get("alert", "enhanced_alarms")):
266 or (status
== "ok" and alarm
.ok_ack
is False)
269 or (status
== "alarm" and alarm
.alarm_ack
is False)
272 "Executing request to url %s for vnf alarm %s with status %s",
278 if status
== "alarm" and alarm
.last_action
== "ok":
281 if status
== "ok" and alarm
.last_action
== "alarm":
282 alarm
.alarm_ack
= False
283 alarm
.last_action
= status
285 except Exception as e
:
288 payload
["notify_details"][
291 headers
= {"content-type": "application/json"}
293 resp
= requests
.post(
295 data
=json
.dumps(payload
),
298 timeout
=alert_timeout
,
300 log
.info("Response %s", resp
)
301 if resp
.status_code
== 200:
305 if status
== "alarm":
306 alarm
.alarm_ack
= True
308 if status
== "insufficient-data":
309 alarm
.alarm_ack
= False
312 except RequestException
as e
:
314 "Error: RequestException while connecting to url %s",
317 log
.debug("RequestException %s", e
)
319 except ConnectionError
:
321 "Error connecting to url %s", action
.url
325 "Executing request to url %s for vnf alarm %s with status %s",
333 json
=json
.dumps(payload
),
334 timeout
=alert_timeout
,
336 except RequestException
as e
:
338 "Error: RequestException while connecting to url %s",
341 log
.debug("RequestException %s", e
)
342 except ConnectionError
:
343 log
.exception("Error connecting to url %s", action
.url
)
345 except VnfAlarm
.DoesNotExist
:
347 "There is no alarming action configured for alarm %s.", alarm_uuid
352 def _get_metric_name(self
, vnf_monitoring_param
: dict):
353 if "performance-metric" in vnf_monitoring_param
:
354 return vnf_monitoring_param
["performance-metric"]
356 "No metric name found for vnf_monitoring_param %s"
357 % vnf_monitoring_param
["id"]