From 9148fa8f9cca2631e50fff145db15df9ab140c30 Mon Sep 17 00:00:00 2001 From: garciadeblas Date: Tue, 30 May 2023 12:51:14 +0200 Subject: [PATCH] Support of VDU alarms in new SA architecture Change-Id: I6cbce6267804763063f92a2d9c45c10f4542f9c7 Signed-off-by: garciadeblas --- osm_lcm/ns.py | 122 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 10 deletions(-) diff --git a/osm_lcm/ns.py b/osm_lcm/ns.py index 83705d4..6ec52c8 100644 --- a/osm_lcm/ns.py +++ b/osm_lcm/ns.py @@ -135,6 +135,14 @@ class NsLcm(LcmBase): SUBOPERATION_STATUS_SKIP = -3 EE_TLS_NAME = "ee-tls" task_name_deploy_vca = "Deploying VCA" + rel_operation_types = { + "GE": ">=", + "LE": "<=", + "GT": ">", + "LT": "<", + "EQ": "==", + "NE": "!=", + } def __init__(self, msg, lcm_tasks, config: LcmCfg): """ @@ -2382,14 +2390,6 @@ class NsLcm(LcmBase): df = vnfd.get("df", [{}])[0] # Checking for auto-scaling configuration if "scaling-aspect" in df: - rel_operation_types = { - "GE": ">=", - "LE": "<=", - "GT": ">", - "LT": "<", - "EQ": "==", - "NE": "!=", - } scaling_aspects = df["scaling-aspect"] all_vnfd_monitoring_params = {} for ivld in vnfd.get("int-virtual-link-desc", ()): @@ -2465,7 +2465,9 @@ class NsLcm(LcmBase): operation = scaling_criteria[ "scale-in-relational-operation" ] - rel_operator = rel_operation_types.get(operation, "<=") + rel_operator = self.rel_operation_types.get( + operation, "<=" + ) metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}' expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})" labels = { @@ -2506,7 +2508,9 @@ class NsLcm(LcmBase): operation = scaling_criteria[ "scale-out-relational-operation" ] - rel_operator = rel_operation_types.get(operation, "<=") + rel_operator = self.rel_operation_types.get( + operation, "<=" + ) metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}' expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})" labels = { @@ -2542,6 +2546,100 @@ class NsLcm(LcmBase): alerts.append(alert) return alerts + def _gather_vnfr_alarm_alerts(self, vnfr, vnfd): + alerts = [] + nsr_id = vnfr["nsr-id-ref"] + vnf_member_index = vnfr["member-vnf-index-ref"] + + # Checking for VNF alarm configuration + for vdur in vnfr["vdur"]: + vdu_id = vdur["vdu-id-ref"] + vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"])) + if "alarm" in vdu: + # Get VDU monitoring params, since alerts are based on them + vdu_monitoring_params = {} + for mp in vdu.get("monitoring-parameter", []): + vdu_monitoring_params[mp.get("id")] = mp + if not vdu_monitoring_params: + self.logger.error( + "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU" + ) + continue + # Get alarms in the VDU + alarm_descriptors = vdu["alarm"] + # Create VDU alarms for each alarm in the VDU + for alarm_descriptor in alarm_descriptors: + # Check that the VDU alarm refers to a proper monitoring param + alarm_monitoring_param = alarm_descriptor.get( + "vnf-monitoring-param-ref", "" + ) + vdu_specific_monitoring_param = vdu_monitoring_params.get( + alarm_monitoring_param, {} + ) + if not vdu_specific_monitoring_param: + self.logger.error( + "VDU alarm refers to a VDU monitoring param not present in the VDU" + ) + continue + metric_name = vdu_specific_monitoring_param.get( + "performance-metric" + ) + if not metric_name: + self.logger.error( + "VDU alarm refers to a VDU monitoring param that has no associated performance-metric" + ) + continue + # Set params of the alarm to be created in Prometheus + metric_name = f"osm_{metric_name}" + metric_threshold = alarm_descriptor.get("value") + uuid = str(uuid4()) + alert_name = f"vdu_alarm_{uuid}" + operation = alarm_descriptor["operation"] + rel_operator = self.rel_operation_types.get(operation, "<=") + metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}' + expression = ( + f"avg({metric_selector}) {rel_operator} {metric_threshold}" + ) + labels = { + "ns_id": nsr_id, + "vnf_member_index": vnf_member_index, + "vdu_id": vdu_id, + } + prom_cfg = { + "alert": alert_name, + "expr": expression, + "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param + "labels": labels, + } + 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"]] + + alert = { + "uuid": uuid, + "name": alert_name, + "metric": metric_name, + "tags": { + "ns_id": nsr_id, + "vnf_member_index": vnf_member_index, + "vdu_id": vdu_id, + }, + "alarm_status": "ok", + "action_type": "vdu_alarm", + "action": alarm_action, + "prometheus_config": prom_cfg, + } + alerts.append(alert) + return alerts + def update_nsrs_with_pla_result(self, params): try: nslcmop_id = deep_get(params, ("placement", "nslcmopId")) @@ -3095,6 +3193,10 @@ class NsLcm(LcmBase): self.logger.info(f"Storing scaling alert in MongoDB: {alert}") self.db.create("alerts", alert) + alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd) + for alert in alarm_alerts: + self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}") + self.db.create("alerts", alert) if db_nsr: self._write_ns_status( nsr_id=nsr_id, -- 2.25.1