Reformat POL to standardized format
[osm/POL.git] / osm_policy_module / alarming / service.py
1 # -*- coding: utf-8 -*-
2 # pylint: disable=no-member
3
4 # Copyright 2018 Whitestack, LLC
5 # *************************************************************
6
7 # This file is part of OSM Monitoring module
8 # All Rights Reserved to Whitestack, LLC
9
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
13
14 # http://www.apache.org/licenses/LICENSE-2.0
15
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
20 # under the License.
21
22 # For those usages not covered by the Apache License, Version 2.0 please
23 # contact: bdiaz@whitestack.com or glavado@whitestack.com
24 ##
25 import asyncio
26 import json
27 import logging
28
29 import requests
30 from requests.exceptions import ConnectionError
31
32 from osm_policy_module.common.common_db_client import CommonDbClient
33 from osm_policy_module.common.lcm_client import LcmClient
34 from osm_policy_module.common.mon_client import MonClient
35 from osm_policy_module.core import database
36 from osm_policy_module.core.config import Config
37 from osm_policy_module.core.database import (
38 VnfAlarm,
39 VnfAlarmRepository,
40 AlarmActionRepository,
41 )
42 from osm_policy_module.core.exceptions import VdurNotFound
43
44 log = logging.getLogger(__name__)
45
46
47 class AlarmingService:
48 def __init__(self, config: Config, loop=None):
49 self.conf = config
50 if not loop:
51 loop = asyncio.get_event_loop()
52 self.loop = loop
53 self.db_client = CommonDbClient(config)
54 self.mon_client = MonClient(config, loop=self.loop)
55 self.lcm_client = LcmClient(config, loop=self.loop)
56
57 async def configure_vnf_alarms(self, nsr_id: str):
58 log.info("Configuring vnf alarms for network service %s", nsr_id)
59 alarms_created = []
60 database.db.connect()
61 try:
62 with database.db.atomic():
63 vnfrs = self.db_client.get_vnfrs(nsr_id)
64 for vnfr in vnfrs:
65 log.debug("Processing vnfr: %s", vnfr)
66 vnfd = self.db_client.get_vnfd(vnfr["vnfd-id"])
67 for vdur in vnfr["vdur"]:
68 vdu = next(
69 filter(
70 lambda vdu: vdu["id"] == vdur["vdu-id-ref"], vnfd["vdu"]
71 )
72 )
73 if "alarm" in vdu:
74 alarm_descriptors = vdu["alarm"]
75 for alarm_descriptor in alarm_descriptors:
76 try:
77 VnfAlarmRepository.get(
78 VnfAlarm.alarm_id
79 == alarm_descriptor["alarm-id"],
80 VnfAlarm.vnf_member_index
81 == vnfr["member-vnf-index-ref"],
82 VnfAlarm.vdu_name == vdur["name"],
83 VnfAlarm.nsr_id == nsr_id,
84 )
85 log.debug(
86 "vdu %s already has an alarm configured with same id %s",
87 vdur["name"],
88 alarm_descriptor["alarm-id"],
89 )
90 continue
91 except VnfAlarm.DoesNotExist:
92 pass
93 vnf_monitoring_param = next(
94 filter(
95 lambda param: param["id"]
96 == alarm_descriptor["vnf-monitoring-param-ref"],
97 vdu.get("monitoring-parameter", []),
98 ),
99 {},
100 )
101 metric_name = self._get_metric_name(
102 vnf_monitoring_param
103 )
104 alarm_uuid = await self.mon_client.create_alarm(
105 metric_name=metric_name,
106 ns_id=nsr_id,
107 vdu_name=vdur["name"],
108 vnf_member_index=vnfr["member-vnf-index-ref"],
109 threshold=alarm_descriptor["value"],
110 operation=alarm_descriptor["operation"],
111 )
112 alarm = VnfAlarmRepository.create(
113 alarm_id=alarm_descriptor["alarm-id"],
114 alarm_uuid=alarm_uuid,
115 nsr_id=nsr_id,
116 vnf_member_index=vnfr["member-vnf-index-ref"],
117 vdu_name=vdur["name"],
118 )
119 for action_type in ["ok", "insufficient-data", "alarm"]:
120 if (
121 "actions" in alarm_descriptor
122 and action_type in alarm_descriptor["actions"]
123 ):
124 for url in alarm_descriptor["actions"][
125 action_type
126 ]:
127 AlarmActionRepository.create(
128 type=action_type,
129 url=url["url"],
130 alarm=alarm,
131 )
132 alarms_created.append(alarm)
133
134 except Exception as e:
135 log.exception("Error configuring VNF alarms:")
136 if len(alarms_created) > 0:
137 log.debug("Cleaning alarm resources in MON")
138 for alarm in alarms_created:
139 try:
140 await self.mon_client.delete_alarm(
141 alarm.nsr_id,
142 alarm.vnf_member_index,
143 alarm.vdu_name,
144 alarm.alarm_uuid,
145 )
146 except ValueError:
147 log.exception(
148 "Error deleting alarm in MON %s", alarm.alarm_uuid
149 )
150 raise e
151 finally:
152 database.db.close()
153
154 async def delete_orphaned_alarms(self, nsr_id):
155 # TODO: Review as it seems this code is never called
156 log.info("Deleting orphaned vnf alarms for network service %s", nsr_id)
157 database.db.connect()
158 try:
159 with database.db.atomic():
160 for alarm in VnfAlarmRepository.list(VnfAlarm.nsr_id == nsr_id):
161 try:
162 self.db_client.get_vdur(
163 nsr_id, alarm.vnf_member_index, alarm.vdu_name
164 )
165 except VdurNotFound:
166 log.debug("Deleting orphaned alarm %s", alarm.alarm_uuid)
167 try:
168 await self.mon_client.delete_alarm(
169 alarm.nsr_id,
170 alarm.vnf_member_index,
171 alarm.vdu_name,
172 alarm.alarm_uuid,
173 )
174 except ValueError:
175 log.exception(
176 "Error deleting alarm in MON %s", alarm.alarm_uuid
177 )
178 alarm.delete_instance()
179 except Exception as e:
180 log.exception("Error deleting orphaned alarms:")
181 raise e
182 finally:
183 database.db.close()
184
185 async def delete_vnf_alarms(self, nsr_id):
186 log.info("Deleting vnf alarms for network service %s", nsr_id)
187 database.db.connect()
188 try:
189 with database.db.atomic():
190 for alarm in VnfAlarmRepository.list(VnfAlarm.nsr_id == nsr_id):
191 log.debug("Deleting vnf alarm %s", alarm.alarm_uuid)
192 try:
193 await self.mon_client.delete_alarm(
194 alarm.nsr_id,
195 alarm.vnf_member_index,
196 alarm.vdu_name,
197 alarm.alarm_uuid,
198 )
199 except ValueError:
200 log.exception(
201 "Error deleting alarm in MON %s", alarm.alarm_uuid
202 )
203 alarm.delete_instance()
204
205 except Exception as e:
206 log.exception("Error deleting vnf alarms:")
207 raise e
208 finally:
209 database.db.close()
210
211 async def handle_alarm(self, alarm_uuid: str, status: str, payload: dict):
212 database.db.connect()
213 try:
214 with database.db.atomic():
215 alarm = VnfAlarmRepository.get(VnfAlarm.alarm_uuid == alarm_uuid)
216 log.debug(
217 "Handling vnf alarm %s with status %s", alarm.alarm_id, status
218 )
219 for action in alarm.actions:
220 if action.type == status:
221 log.info(
222 "Executing request to url %s for vnf alarm %s with status %s",
223 action.url,
224 alarm.alarm_id,
225 status,
226 )
227 try:
228 requests.post(url=action.url, json=json.dumps(payload))
229 except ConnectionError:
230 log.exception("Error connecting to url %s", action.url)
231
232 except VnfAlarm.DoesNotExist:
233 log.debug(
234 "There is no alarming action configured for alarm %s.", alarm_uuid
235 )
236 finally:
237 database.db.close()
238
239 def _get_metric_name(self, vnf_monitoring_param: dict):
240 if "performance-metric" in vnf_monitoring_param:
241 return vnf_monitoring_param["performance-metric"]
242 raise ValueError(
243 "No metric name found for vnf_monitoring_param %s"
244 % vnf_monitoring_param["id"]
245 )