blob: 8906e2a80933e7070045448169a8e219d34ecdf2 [file] [log] [blame]
tierno59d22d22018-09-25 18:10:19 +02001# -*- coding: utf-8 -*-
2
tierno2e215512018-11-28 09:37:52 +00003##
4# Copyright 2018 Telefonica S.A.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17##
18
tierno59d22d22018-09-25 18:10:19 +020019import asyncio
aticigdffa6212022-04-12 15:27:53 +030020import shutil
David Garcia444bf962021-11-11 16:35:26 +010021from typing import Any, Dict, List
tierno59d22d22018-09-25 18:10:19 +020022import yaml
23import logging
24import logging.handlers
tierno59d22d22018-09-25 18:10:19 +020025import traceback
rahul72d90d92023-08-30 14:48:01 +053026import ipaddress
David Garciad4816682019-12-09 14:57:43 +010027import json
garciadeblas5697b8b2021-03-24 09:17:02 +010028from jinja2 import (
29 Environment,
30 TemplateError,
31 TemplateNotFound,
32 StrictUndefined,
33 UndefinedError,
garciadeblasef91e082022-08-02 15:12:18 +020034 select_autoescape,
garciadeblas5697b8b2021-03-24 09:17:02 +010035)
tierno59d22d22018-09-25 18:10:19 +020036
tierno77677d92019-08-22 13:46:35 +000037from osm_lcm import ROclient
Luis Vegaa27dc532022-11-11 20:10:49 +000038from osm_lcm.data_utils.lcm_config import LcmCfg
David Garciab4ebcd02021-10-28 02:00:43 +020039from osm_lcm.data_utils.nsr import (
40 get_deployed_kdu,
41 get_deployed_vca,
42 get_deployed_vca_list,
43 get_nsd,
44)
45from osm_lcm.data_utils.vca import (
46 DeployedComponent,
47 DeployedK8sResource,
48 DeployedVCA,
49 EELevel,
50 Relation,
51 EERelation,
52 safe_get_ee_relation,
53)
tierno69f0d382020-05-07 13:08:09 +000054from osm_lcm.ng_ro import NgRoClient, NgRoException
garciadeblas5697b8b2021-03-24 09:17:02 +010055from osm_lcm.lcm_utils import (
56 LcmException,
garciadeblas5697b8b2021-03-24 09:17:02 +010057 LcmBase,
58 deep_get,
59 get_iterable,
60 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030061 check_juju_bundle_existence,
62 get_charm_artifact_path,
Gabriel Cubae539a8d2022-10-10 11:34:51 -050063 get_ee_id_parts,
Gabriel Cubac7737442023-02-14 13:09:18 -050064 vld_to_ro_ip_profile,
garciadeblas5697b8b2021-03-24 09:17:02 +010065)
David Garciab4ebcd02021-10-28 02:00:43 +020066from osm_lcm.data_utils.nsd import (
67 get_ns_configuration_relation_list,
68 get_vnf_profile,
69 get_vnf_profiles,
70)
garciadeblas5697b8b2021-03-24 09:17:02 +010071from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020072 get_kdu,
73 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020074 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010075 get_vdu_list,
76 get_vdu_profile,
77 get_ee_sorted_initial_config_primitive_list,
78 get_ee_sorted_terminate_config_primitive_list,
79 get_kdu_list,
80 get_virtual_link_profiles,
81 get_vdu,
82 get_configuration,
83 get_vdu_index,
84 get_scaling_aspect,
85 get_number_of_instances,
86 get_juju_ee_ref,
jegan99448902024-12-06 07:19:34 +000087 get_helm_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020088 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030089 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050090 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010091)
bravof922c4172020-11-24 21:21:43 -030092from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030093from osm_lcm.data_utils.vnfr import (
94 get_osm_params,
95 get_vdur_index,
96 get_kdur,
97 get_volumes_from_instantiation_params,
98)
bravof922c4172020-11-24 21:21:43 -030099from osm_lcm.data_utils.dict_utils import parse_yaml_strings
100from osm_lcm.data_utils.database.vim_account import VimAccountDB
almagiacdd20ae2024-12-13 09:45:45 +0100101from osm_lcm.n2vc.definitions import RelationEndpoint
102from osm_lcm.n2vc.k8s_helm3_conn import K8sHelm3Connector
103from osm_lcm.n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200104
tierno27246d82018-09-27 15:59:09 +0200105from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200106from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200107
bravof922c4172020-11-24 21:21:43 -0300108from osm_lcm.data_utils.database.database import Database
109from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000110from osm_lcm.data_utils.wim import (
111 get_sdn_ports,
112 get_target_wim_attrs,
113 select_feasible_wim_account,
114)
bravof922c4172020-11-24 21:21:43 -0300115
almagiacdd20ae2024-12-13 09:45:45 +0100116from osm_lcm.n2vc.n2vc_juju_conn import N2VCJujuConnector
117from osm_lcm.n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200118
tierno588547c2020-07-01 15:30:20 +0000119from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200120from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400121from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000122
tierno27246d82018-09-27 15:59:09 +0200123from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200124from time import time
tierno27246d82018-09-27 15:59:09 +0200125from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000126
k4.rahulcf47a3b2023-04-27 12:08:48 +0530127from random import SystemRandom
tierno59d22d22018-09-25 18:10:19 +0200128
tierno69f0d382020-05-07 13:08:09 +0000129__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200130
131
132class NsLcm(LcmBase):
kuuseac3a8882019-10-03 10:48:06 +0200133 SUBOPERATION_STATUS_NOT_FOUND = -1
134 SUBOPERATION_STATUS_NEW = -2
135 SUBOPERATION_STATUS_SKIP = -3
Gabriel Cubaeb585dd2023-04-25 16:48:41 -0500136 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000137 task_name_deploy_vca = "Deploying VCA"
garciadeblas9148fa82023-05-30 12:51:14 +0200138 rel_operation_types = {
139 "GE": ">=",
140 "LE": "<=",
141 "GT": ">",
142 "LT": "<",
143 "EQ": "==",
144 "NE": "!=",
145 }
kuuseac3a8882019-10-03 10:48:06 +0200146
Gabriel Cubae7898982023-05-11 01:57:21 -0500147 def __init__(self, msg, lcm_tasks, config: LcmCfg):
tierno59d22d22018-09-25 18:10:19 +0200148 """
149 Init, Connect to database, filesystem storage, and messaging
150 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
151 :return: None
152 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100153 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200154
bravof922c4172020-11-24 21:21:43 -0300155 self.db = Database().instance.db
156 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200157 self.lcm_tasks = lcm_tasks
Luis Vegaa27dc532022-11-11 20:10:49 +0000158 self.timeout = config.timeout
159 self.ro_config = config.RO
160 self.vca_config = config.VCA
Rahul Kumar54671c52024-05-09 15:34:01 +0530161 self.service_kpi = config.servicekpi
tierno59d22d22018-09-25 18:10:19 +0200162
quilesj7e13aeb2019-10-08 13:34:55 +0200163 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100164 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200165 log=self.logger,
bravof922c4172020-11-24 21:21:43 -0300166 on_update_db=self._on_update_n2vc_db,
167 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100168 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200169 )
quilesj7e13aeb2019-10-08 13:34:55 +0200170
tierno588547c2020-07-01 15:30:20 +0000171 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000172 log=self.logger,
tierno588547c2020-07-01 15:30:20 +0000173 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100174 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000175 )
176
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000177 self.k8sclusterhelm3 = K8sHelm3Connector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000178 kubectl_command=self.vca_config.kubectlpath,
179 helm_command=self.vca_config.helm3path,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000180 fs=self.fs,
181 log=self.logger,
182 db=self.db,
183 on_update_db=None,
184 )
185
Adam Israelbaacc302019-12-01 12:41:39 -0500186 self.k8sclusterjuju = K8sJujuConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000187 kubectl_command=self.vca_config.kubectlpath,
188 juju_command=self.vca_config.jujupath,
Adam Israelbaacc302019-12-01 12:41:39 -0500189 log=self.logger,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530190 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300191 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100192 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500193 )
194
tiernoa2143262020-03-27 16:20:40 +0000195 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000196 "helm-chart-v3": self.k8sclusterhelm3,
197 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000198 "juju-bundle": self.k8sclusterjuju,
199 "juju": self.k8sclusterjuju,
200 }
tierno588547c2020-07-01 15:30:20 +0000201
202 self.vca_map = {
203 "lxc_proxy_charm": self.n2vc,
204 "native_charm": self.n2vc,
205 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000206 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100207 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000208 }
209
quilesj7e13aeb2019-10-08 13:34:55 +0200210 # create RO client
Gabriel Cubae7898982023-05-11 01:57:21 -0500211 self.RO = NgRoClient(**self.ro_config.to_dict())
tierno59d22d22018-09-25 18:10:19 +0200212
garciadeblas07f4e4c2022-06-09 09:42:58 +0200213 self.op_status_map = {
214 "instantiation": self.RO.status,
215 "termination": self.RO.status,
216 "migrate": self.RO.status,
217 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000218 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000219 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200220 }
221
tierno2357f4e2020-10-19 16:38:59 +0000222 @staticmethod
223 def increment_ip_mac(ip_mac, vm_index=1):
224 if not isinstance(ip_mac, str):
225 return ip_mac
226 try:
rahul72d90d92023-08-30 14:48:01 +0530227 next_ipv6 = None
228 next_ipv4 = None
229 dual_ip = ip_mac.split(";")
230 if len(dual_ip) == 2:
231 for ip in dual_ip:
232 if ipaddress.ip_address(ip).version == 6:
233 ipv6 = ipaddress.IPv6Address(ip)
234 next_ipv6 = str(ipaddress.IPv6Address(int(ipv6) + 1))
235 elif ipaddress.ip_address(ip).version == 4:
236 ipv4 = ipaddress.IPv4Address(ip)
237 next_ipv4 = str(ipaddress.IPv4Address(int(ipv4) + 1))
238 return [next_ipv4, next_ipv6]
tierno2357f4e2020-10-19 16:38:59 +0000239 # try with ipv4 look for last dot
240 i = ip_mac.rfind(".")
241 if i > 0:
242 i += 1
243 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
244 # try with ipv6 or mac look for last colon. Operate in hex
245 i = ip_mac.rfind(":")
246 if i > 0:
247 i += 1
248 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100249 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
250 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
251 )
tierno2357f4e2020-10-19 16:38:59 +0000252 except Exception:
253 pass
254 return None
255
David Garciac1fe90a2021-03-31 19:12:02 +0200256 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000257 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100258 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000259 path = path[:-1]
260
quilesj3655ae02019-12-12 16:08:35 +0000261 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
262 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000263 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100264 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000265
266 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100267 nsr = self.db.get_one(table="nsrs", q_filter=filter)
268 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000269
3697083243632024-06-07 05:44:08 +0000270 # First, we need to verify if the current vcaStatus is null, because if that is the case,
271 # MongoDB will not be able to create the fields used within the update key in the database
272 if not nsr.get("vcaStatus"):
273 # Write an empty dictionary to the vcaStatus field, it its value is null
274 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
275
276 # Get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100277 status_dict = await self.n2vc.get_status(
278 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
279 )
quilesj3655ae02019-12-12 16:08:35 +0000280
3697083243632024-06-07 05:44:08 +0000281 # Update the vcaStatus
282 db_key = f"vcaStatus.{nsr_id}.VNF"
quilesj3655ae02019-12-12 16:08:35 +0000283 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000284
285 db_dict[db_key] = status_dict[nsr_id]
286 await self.n2vc.update_vca_status(db_dict[db_key], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000287
288 # update configurationStatus for this VCA
289 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100290 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000291
garciadeblas5697b8b2021-03-24 09:17:02 +0100292 vca_list = deep_get(
293 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
294 )
295 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000296
garciadeblas5697b8b2021-03-24 09:17:02 +0100297 configuration_status_list = nsr.get("configurationStatus")
298 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000299
garciadeblas5697b8b2021-03-24 09:17:02 +0100300 if config_status == "BROKEN" and vca_status != "failed":
301 db_dict["configurationStatus"][vca_index] = "READY"
302 elif config_status != "BROKEN" and vca_status == "failed":
303 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000304 except Exception as e:
305 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100306 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000307
308 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
309 # if nsState = 'DEGRADED' check if all is OK
310 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100311 if current_ns_status in ("READY", "DEGRADED"):
312 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000313 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100314 if status_dict.get("machines"):
315 for machine_id in status_dict.get("machines"):
316 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000317 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100318 if machine.get("agent-status"):
319 s = machine.get("agent-status").get("status")
320 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000321 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100322 error_description += (
323 "machine {} agent-status={} ; ".format(
324 machine_id, s
325 )
326 )
quilesj3655ae02019-12-12 16:08:35 +0000327 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100328 if machine.get("instance-status"):
329 s = machine.get("instance-status").get("status")
330 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000331 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100332 error_description += (
333 "machine {} instance-status={} ; ".format(
334 machine_id, s
335 )
336 )
quilesj3655ae02019-12-12 16:08:35 +0000337 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100338 if status_dict.get("applications"):
339 for app_id in status_dict.get("applications"):
340 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000341 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100342 if app.get("status"):
343 s = app.get("status").get("status")
344 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000345 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100346 error_description += (
347 "application {} status={} ; ".format(app_id, s)
348 )
quilesj3655ae02019-12-12 16:08:35 +0000349
350 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100351 db_dict["errorDescription"] = error_description
352 if current_ns_status == "READY" and is_degraded:
353 db_dict["nsState"] = "DEGRADED"
354 if current_ns_status == "DEGRADED" and not is_degraded:
355 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000356
357 # write to database
358 self.update_db_2("nsrs", nsr_id, db_dict)
359
tierno51183952020-04-03 15:48:18 +0000360 except (asyncio.CancelledError, asyncio.TimeoutError):
361 raise
quilesj3655ae02019-12-12 16:08:35 +0000362 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100363 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200364
garciadeblas5697b8b2021-03-24 09:17:02 +0100365 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100366 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100367 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530368 """
369 Updating vca status in NSR record
370 :param cluster_uuid: UUID of a k8s cluster
371 :param kdu_instance: The unique name of the KDU instance
372 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100373 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530374 :return: none
375 """
376
377 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
378 # .format(cluster_uuid, kdu_instance, filter))
379
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100380 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530381 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100382 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
383 cluster_uuid=cluster_uuid,
384 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200385 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100386 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200387 vca_id=vca_id,
388 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100389
3697083243632024-06-07 05:44:08 +0000390 # First, we need to verify if the current vcaStatus is null, because if that is the case,
391 # MongoDB will not be able to create the fields used within the update key in the database
392 nsr = self.db.get_one(table="nsrs", q_filter=filter)
393 if not nsr.get("vcaStatus"):
394 # Write an empty dictionary to the vcaStatus field, it its value is null
395 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
396
397 # Update the vcaStatus
398 db_key = f"vcaStatus.{nsr_id}.KNF"
ksaikiranr656b6dd2021-02-19 10:25:18 +0530399 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000400
401 db_dict[db_key] = vca_status
402
403 if cluster_type in ("juju-bundle", "juju"):
404 # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA
405 # status in a similar way between Juju Bundles and Helm Charts on this side
406 await self.k8sclusterjuju.update_vca_status(
407 db_dict[db_key],
408 kdu_instance,
409 vca_id=vca_id,
410 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530411
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100412 self.logger.debug(
413 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200414 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530415
416 # write to database
417 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530418 except (asyncio.CancelledError, asyncio.TimeoutError):
419 raise
420 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100421 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530422
tierno72ef84f2020-10-06 08:22:07 +0000423 @staticmethod
424 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
425 try:
garciadeblasef91e082022-08-02 15:12:18 +0200426 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000427 undefined=StrictUndefined,
428 autoescape=select_autoescape(default_for_string=True, default=True),
429 )
tierno72ef84f2020-10-06 08:22:07 +0000430 template = env.from_string(cloud_init_text)
431 return template.render(additional_params or {})
432 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100433 raise LcmException(
434 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
435 "file, must be provided in the instantiation parameters inside the "
436 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
437 )
tierno72ef84f2020-10-06 08:22:07 +0000438 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100439 raise LcmException(
440 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
441 vnfd_id, vdu_id, e
442 )
443 )
tierno72ef84f2020-10-06 08:22:07 +0000444
bravof922c4172020-11-24 21:21:43 -0300445 def _get_vdu_cloud_init_content(self, vdu, vnfd):
446 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000447 try:
tierno72ef84f2020-10-06 08:22:07 +0000448 if vdu.get("cloud-init-file"):
449 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300450 if base_folder["pkg-dir"]:
451 cloud_init_file = "{}/{}/cloud_init/{}".format(
452 base_folder["folder"],
453 base_folder["pkg-dir"],
454 vdu["cloud-init-file"],
455 )
456 else:
457 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
458 base_folder["folder"],
459 vdu["cloud-init-file"],
460 )
tierno72ef84f2020-10-06 08:22:07 +0000461 with self.fs.file_open(cloud_init_file, "r") as ci_file:
462 cloud_init_content = ci_file.read()
463 elif vdu.get("cloud-init"):
464 cloud_init_content = vdu["cloud-init"]
465
466 return cloud_init_content
467 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100468 raise LcmException(
469 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
470 vnfd["id"], vdu["id"], cloud_init_file, e
471 )
472 )
tierno72ef84f2020-10-06 08:22:07 +0000473
tierno72ef84f2020-10-06 08:22:07 +0000474 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100475 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300476 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100477 )
tierno72ef84f2020-10-06 08:22:07 +0000478 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300479 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000480
tierno2357f4e2020-10-19 16:38:59 +0000481 @staticmethod
482 def ip_profile_2_RO(ip_profile):
483 RO_ip_profile = deepcopy(ip_profile)
484 if "dns-server" in RO_ip_profile:
485 if isinstance(RO_ip_profile["dns-server"], list):
486 RO_ip_profile["dns-address"] = []
487 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100488 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000489 else:
490 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
491 if RO_ip_profile.get("ip-version") == "ipv4":
492 RO_ip_profile["ip-version"] = "IPv4"
493 if RO_ip_profile.get("ip-version") == "ipv6":
494 RO_ip_profile["ip-version"] = "IPv6"
495 if "dhcp-params" in RO_ip_profile:
496 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
497 return RO_ip_profile
498
tierno2357f4e2020-10-19 16:38:59 +0000499 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000500 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000501 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000502 db_update = {"_admin.modified": time()}
503 if vdu_create:
504 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100505 vdur = next(
506 (
507 vdur
508 for vdur in reversed(db_vnfr["vdur"])
509 if vdur["vdu-id-ref"] == vdu_id
510 ),
511 None,
512 )
tierno2357f4e2020-10-19 16:38:59 +0000513 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000514 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300515 self.logger.debug(
516 "No vdur in the database. Using the vdur-template to scale"
517 )
vegall8d625f12022-03-22 16:23:30 +0000518 vdur_template = db_vnfr.get("vdur-template")
519 if not vdur_template:
520 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300521 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
522 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000523 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100524 )
vegall8d625f12022-03-22 16:23:30 +0000525 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300526 # Delete a template from the database after using it
527 self.db.set_one(
528 "vnfrs",
529 {"_id": db_vnfr["_id"]},
530 None,
531 pull={"vdur-template": {"_id": vdur["_id"]}},
532 )
tierno2357f4e2020-10-19 16:38:59 +0000533 for count in range(vdu_count):
534 vdur_copy = deepcopy(vdur)
535 vdur_copy["status"] = "BUILD"
536 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100537 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000538 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000539 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100540 vdur_copy["id"] = "{}-{}".format(
541 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
542 )
tierno2357f4e2020-10-19 16:38:59 +0000543 vdur_copy.pop("vim_info", None)
544 for iface in vdur_copy["interfaces"]:
545 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100546 iface["ip-address"] = self.increment_ip_mac(
547 iface["ip-address"], count + 1
548 )
tierno2357f4e2020-10-19 16:38:59 +0000549 else:
550 iface.pop("ip-address", None)
551 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100552 iface["mac-address"] = self.increment_ip_mac(
553 iface["mac-address"], count + 1
554 )
tierno2357f4e2020-10-19 16:38:59 +0000555 else:
556 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000557 if db_vnfr["vdur"]:
558 iface.pop(
559 "mgmt_vnf", None
560 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000561 db_vdu_push_list.append(vdur_copy)
562 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200563 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000564 if len(db_vnfr["vdur"]) == 1:
565 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300566 self.logger.debug(
567 "Scaling to 0 !, creating the template with the last vdur"
568 )
vegall8d625f12022-03-22 16:23:30 +0000569 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000570 for vdu_id, vdu_count in vdu_delete.items():
571 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100572 indexes_to_delete = [
573 iv[0]
574 for iv in enumerate(db_vnfr["vdur"])
575 if iv[1]["vdu-id-ref"] == vdu_id
576 ]
577 db_update.update(
578 {
579 "vdur.{}.status".format(i): "DELETING"
580 for i in indexes_to_delete[-vdu_count:]
581 }
582 )
tierno2357f4e2020-10-19 16:38:59 +0000583 else:
584 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100585 vdus_to_delete = [
586 v
587 for v in reversed(db_vnfr["vdur"])
588 if v["vdu-id-ref"] == vdu_id
589 ]
tierno2357f4e2020-10-19 16:38:59 +0000590 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100591 self.db.set_one(
592 "vnfrs",
593 {"_id": db_vnfr["_id"]},
594 None,
595 pull={"vdur": {"_id": vdu["_id"]}},
596 )
vegall8d625f12022-03-22 16:23:30 +0000597 db_push = {}
598 if db_vdu_push_list:
599 db_push["vdur"] = db_vdu_push_list
600 if template_vdur:
601 db_push["vdur-template"] = template_vdur
602 if not db_push:
603 db_push = None
604 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000605 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
606 # modify passed dictionary db_vnfr
607 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
608 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200609
tiernof578e552018-11-08 19:07:20 +0100610 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
611 """
612 Updates database nsr with the RO info for the created vld
613 :param ns_update_nsr: dictionary to be filled with the updated info
614 :param db_nsr: content of db_nsr. This is also modified
615 :param nsr_desc_RO: nsr descriptor from RO
616 :return: Nothing, LcmException is raised on errors
617 """
618
619 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
620 for net_RO in get_iterable(nsr_desc_RO, "nets"):
621 if vld["id"] != net_RO.get("ns_net_osm_id"):
622 continue
623 vld["vim-id"] = net_RO.get("vim_net_id")
624 vld["name"] = net_RO.get("vim_name")
625 vld["status"] = net_RO.get("status")
626 vld["status-detailed"] = net_RO.get("error_msg")
627 ns_update_nsr["vld.{}".format(vld_index)] = vld
628 break
629 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100630 raise LcmException(
631 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
632 )
tiernof578e552018-11-08 19:07:20 +0100633
tiernoe876f672020-02-13 14:34:48 +0000634 def set_vnfr_at_error(self, db_vnfrs, error_text):
635 try:
636 for db_vnfr in db_vnfrs.values():
637 vnfr_update = {"status": "ERROR"}
638 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
639 if "status" not in vdur:
640 vdur["status"] = "ERROR"
641 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
642 if error_text:
643 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100644 vnfr_update[
645 "vdur.{}.status-detailed".format(vdu_index)
646 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000647 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
648 except DbException as e:
649 self.logger.error("Cannot update vnf. {}".format(e))
650
tierno5ee02052019-12-05 19:55:02 +0000651 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000652 """
653 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000654 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000655 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
656 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
657 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
658 """
tierno5ee02052019-12-05 19:55:02 +0000659 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
660 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000661 mapping = {}
662 ns_config_info = {"osm-config-mapping": mapping}
663 for vca in vca_deployed_list:
664 if not vca["member-vnf-index"]:
665 continue
666 if not vca["vdu_id"]:
667 mapping[vca["member-vnf-index"]] = vca["application"]
668 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100669 mapping[
670 "{}.{}.{}".format(
671 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
672 )
673 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000674 return ns_config_info
675
garciadeblas5697b8b2021-03-24 09:17:02 +0100676 async def _instantiate_ng_ro(
677 self,
678 logging_text,
679 nsr_id,
680 nsd,
681 db_nsr,
682 db_nslcmop,
683 db_vnfrs,
684 db_vnfds,
685 n2vc_key_list,
686 stage,
687 start_deploy,
688 timeout_ns_deploy,
689 ):
tierno2357f4e2020-10-19 16:38:59 +0000690 db_vims = {}
691
692 def get_vim_account(vim_account_id):
Anirudh Gupta77b50a02025-05-13 05:53:38 +0000693 # nonlocal db_vims
tierno2357f4e2020-10-19 16:38:59 +0000694 if vim_account_id in db_vims:
695 return db_vims[vim_account_id]
696 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
697 db_vims[vim_account_id] = db_vim
698 return db_vim
699
700 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100701 def parse_vld_instantiation_params(
702 target_vim, target_vld, vld_params, target_sdn
703 ):
tierno2357f4e2020-10-19 16:38:59 +0000704 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500705 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
706 vld_params["ip-profile"]
707 )
tierno2357f4e2020-10-19 16:38:59 +0000708 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100709 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
710 "provider-network"
711 ]
tierno2357f4e2020-10-19 16:38:59 +0000712 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100713 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
714 "provider-network"
715 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000716
717 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
718 # if wim_account_id is specified in vld_params, validate if it is feasible.
719 wim_account_id, db_wim = select_feasible_wim_account(
720 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
721 )
722
723 if wim_account_id:
724 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
725 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
726 # update vld_params with correct WIM account Id
727 vld_params["wimAccountId"] = wim_account_id
728
729 target_wim = "wim:{}".format(wim_account_id)
730 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
731 sdn_ports = get_sdn_ports(vld_params, db_wim)
732 if len(sdn_ports) > 0:
733 target_vld["vim_info"][target_wim] = target_wim_attrs
734 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
735
736 self.logger.debug(
737 "Target VLD with WIM data: {:s}".format(str(target_vld))
738 )
739
tierno2357f4e2020-10-19 16:38:59 +0000740 for param in ("vim-network-name", "vim-network-id"):
741 if vld_params.get(param):
742 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300743 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300744 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100745 populate_dict(
746 target_vld["vim_info"],
747 (other_target_vim, param.replace("-", "_")),
748 vim_net,
749 )
tierno2357f4e2020-10-19 16:38:59 +0000750 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100751 target_vld["vim_info"][target_vim][
752 param.replace("-", "_")
753 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300754 if vld_params.get("common_id"):
755 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000756
aticig15db6142022-01-24 12:51:26 +0300757 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
758 def update_ns_vld_target(target, ns_params):
759 for vnf_params in ns_params.get("vnf", ()):
760 if vnf_params.get("vimAccountId"):
761 target_vnf = next(
762 (
763 vnfr
764 for vnfr in db_vnfrs.values()
765 if vnf_params["member-vnf-index"]
766 == vnfr["member-vnf-index-ref"]
767 ),
768 None,
769 )
770 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100771 if not vdur:
Pedro Escaleira556f5c72023-04-20 15:22:16 +0100772 continue
aticig15db6142022-01-24 12:51:26 +0300773 for a_index, a_vld in enumerate(target["ns"]["vld"]):
774 target_vld = find_in_list(
775 get_iterable(vdur, "interfaces"),
776 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
777 )
aticig84bd9a72022-06-14 03:01:36 +0300778
779 vld_params = find_in_list(
780 get_iterable(ns_params, "vld"),
781 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
782 )
aticig15db6142022-01-24 12:51:26 +0300783 if target_vld:
784 if vnf_params.get("vimAccountId") not in a_vld.get(
785 "vim_info", {}
786 ):
aticig84bd9a72022-06-14 03:01:36 +0300787 target_vim_network_list = [
788 v for _, v in a_vld.get("vim_info").items()
789 ]
790 target_vim_network_name = next(
791 (
792 item.get("vim_network_name", "")
793 for item in target_vim_network_list
794 ),
795 "",
796 )
797
aticig15db6142022-01-24 12:51:26 +0300798 target["ns"]["vld"][a_index].get("vim_info").update(
799 {
800 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300801 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300802 }
803 }
804 )
805
aticig84bd9a72022-06-14 03:01:36 +0300806 if vld_params:
807 for param in ("vim-network-name", "vim-network-id"):
808 if vld_params.get(param) and isinstance(
809 vld_params[param], dict
810 ):
811 for vim, vim_net in vld_params[
812 param
813 ].items():
814 other_target_vim = "vim:" + vim
815 populate_dict(
816 target["ns"]["vld"][a_index].get(
817 "vim_info"
818 ),
819 (
820 other_target_vim,
821 param.replace("-", "_"),
822 ),
823 vim_net,
824 )
825
tierno69f0d382020-05-07 13:08:09 +0000826 nslcmop_id = db_nslcmop["_id"]
827 target = {
828 "name": db_nsr["name"],
829 "ns": {"vld": []},
830 "vnf": [],
831 "image": deepcopy(db_nsr["image"]),
832 "flavor": deepcopy(db_nsr["flavor"]),
833 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000834 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000835 }
836 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000837 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000838 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000839 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000840 if db_nsr.get("shared-volumes"):
841 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
842 for shared_volumes in target["shared-volumes"]:
843 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100844 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100845 target["affinity-or-anti-affinity-group"] = deepcopy(
846 db_nsr["affinity-or-anti-affinity-group"]
847 )
848 for affinity_or_anti_affinity_group in target[
849 "affinity-or-anti-affinity-group"
850 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100851 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000852
tierno2357f4e2020-10-19 16:38:59 +0000853 if db_nslcmop.get("lcmOperationType") != "instantiate":
854 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100855 db_nslcmop_instantiate = self.db.get_list(
856 "nslcmops",
857 {
858 "nsInstanceId": db_nslcmop["nsInstanceId"],
859 "lcmOperationType": "instantiate",
860 },
861 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000862 ns_params = db_nslcmop_instantiate.get("operationParams")
863 else:
864 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300865 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
866 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000867
868 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000869 for vld_index, vld in enumerate(db_nsr.get("vld")):
870 target_vim = "vim:{}".format(ns_params["vimAccountId"])
871 target_vld = {
872 "id": vld["id"],
873 "name": vld["name"],
874 "mgmt-network": vld.get("mgmt-network", False),
875 "type": vld.get("type"),
876 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300877 target_vim: {
878 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100879 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -0300880 }
garciadeblas5697b8b2021-03-24 09:17:02 +0100881 },
tierno2357f4e2020-10-19 16:38:59 +0000882 }
883 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000884 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +0000885 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +0300886 if vim_config := db_vim.get("config"):
887 if sdnc_id := vim_config.get("sdn-controller"):
888 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
889 target_sdn = "sdn:{}".format(sdnc_id)
890 target_vld["vim_info"][target_sdn] = {
891 "sdn": True,
892 "target_vim": target_vim,
893 "vlds": [sdn_vld],
894 "type": vld.get("type"),
895 }
tierno2357f4e2020-10-19 16:38:59 +0000896
bravof922c4172020-11-24 21:21:43 -0300897 nsd_vnf_profiles = get_vnf_profiles(nsd)
898 for nsd_vnf_profile in nsd_vnf_profiles:
899 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
900 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100901 cp2target[
902 "member_vnf:{}.{}".format(
903 cp["constituent-cpd-id"][0][
904 "constituent-base-element-id"
905 ],
906 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
907 )
908 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000909
910 # check at nsd descriptor, if there is an ip-profile
911 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +0000912 nsd_vlp = find_in_list(
913 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100914 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
915 == vld["id"],
916 )
917 if (
918 nsd_vlp
919 and nsd_vlp.get("virtual-link-protocol-data")
920 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
921 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500922 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100923 "l3-protocol-data"
924 ]
bravof922c4172020-11-24 21:21:43 -0300925
tierno2357f4e2020-10-19 16:38:59 +0000926 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +0100927 vld_instantiation_params = find_in_list(
928 get_iterable(ns_params, "vld"),
929 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
930 )
tierno2357f4e2020-10-19 16:38:59 +0000931 if vld_instantiation_params:
932 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300933 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000934 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +0300935 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
936 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -0300937
tierno69f0d382020-05-07 13:08:09 +0000938 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +0100939 vnfd = find_in_list(
940 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
941 )
942 vnf_params = find_in_list(
943 get_iterable(ns_params, "vnf"),
944 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
945 )
tierno69f0d382020-05-07 13:08:09 +0000946 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000947 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000948 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000949 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +0100950 vnf_cp = find_in_list(
951 vnfd.get("int-virtual-link-desc", ()),
952 lambda cpd: cpd.get("id") == vld["id"],
953 )
tierno69f0d382020-05-07 13:08:09 +0000954 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +0100955 ns_cp = "member_vnf:{}.{}".format(
956 vnfr["member-vnf-index-ref"], vnf_cp["id"]
957 )
tierno69f0d382020-05-07 13:08:09 +0000958 if cp2target.get(ns_cp):
959 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300960
garciadeblas5697b8b2021-03-24 09:17:02 +0100961 vld["vim_info"] = {
962 target_vim: {"vim_network_name": vld.get("vim-network-name")}
963 }
tierno2357f4e2020-10-19 16:38:59 +0000964 # check if this network needs SDN assist
965 target_sdn = None
966 if vld.get("pci-interfaces"):
967 db_vim = get_vim_account(vnfr["vim-account-id"])
968 sdnc_id = db_vim["config"].get("sdn-controller")
969 if sdnc_id:
970 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
971 target_sdn = "sdn:{}".format(sdnc_id)
972 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +0100973 "sdn": True,
974 "target_vim": target_vim,
975 "vlds": [sdn_vld],
976 "type": vld.get("type"),
977 }
tierno69f0d382020-05-07 13:08:09 +0000978
tierno2357f4e2020-10-19 16:38:59 +0000979 # check at vnfd descriptor, if there is an ip-profile
980 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300981 vnfd_vlp = find_in_list(
982 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100983 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -0300984 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100985 if (
986 vnfd_vlp
987 and vnfd_vlp.get("virtual-link-protocol-data")
988 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
989 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500990 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100991 "l3-protocol-data"
992 ]
tierno2357f4e2020-10-19 16:38:59 +0000993 # update vld_params with instantiation params
994 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +0100995 vld_instantiation_params = find_in_list(
996 get_iterable(vnf_params, "internal-vld"),
997 lambda i_vld: i_vld["name"] == vld["id"],
998 )
tierno2357f4e2020-10-19 16:38:59 +0000999 if vld_instantiation_params:
1000 vld_params.update(vld_instantiation_params)
1001 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1002
1003 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001004 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001005 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1006 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001007 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001008
bravof922c4172020-11-24 21:21:43 -03001009 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1010
1011 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001012 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1013 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001014 if (
1015 vdu_configuration
1016 and vdu_configuration.get("config-access")
1017 and vdu_configuration.get("config-access").get("ssh-access")
1018 ):
bravof922c4172020-11-24 21:21:43 -03001019 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001020 vdur["ssh-access-required"] = vdu_configuration[
1021 "config-access"
1022 ]["ssh-access"]["required"]
1023 elif (
1024 vnf_configuration
1025 and vnf_configuration.get("config-access")
1026 and vnf_configuration.get("config-access").get("ssh-access")
1027 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1028 ):
bravof922c4172020-11-24 21:21:43 -03001029 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001030 vdur["ssh-access-required"] = vnf_configuration[
1031 "config-access"
1032 ]["ssh-access"]["required"]
1033 elif ssh_keys_instantiation and find_in_list(
1034 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1035 ):
bravof922c4172020-11-24 21:21:43 -03001036 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001037
bravof922c4172020-11-24 21:21:43 -03001038 self.logger.debug("NS > vdur > {}".format(vdur))
1039
1040 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001041 # cloud-init
1042 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001043 vdur["cloud-init"] = "{}:file:{}".format(
1044 vnfd["_id"], vdud.get("cloud-init-file")
1045 )
tierno2357f4e2020-10-19 16:38:59 +00001046 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1047 if vdur["cloud-init"] not in target["cloud_init_content"]:
1048 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001049 if base_folder["pkg-dir"]:
1050 cloud_init_file = "{}/{}/cloud_init/{}".format(
1051 base_folder["folder"],
1052 base_folder["pkg-dir"],
1053 vdud.get("cloud-init-file"),
1054 )
1055 else:
1056 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1057 base_folder["folder"],
1058 vdud.get("cloud-init-file"),
1059 )
tierno2357f4e2020-10-19 16:38:59 +00001060 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001061 target["cloud_init_content"][
1062 vdur["cloud-init"]
1063 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001064 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001065 vdur["cloud-init"] = "{}:vdu:{}".format(
1066 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1067 )
tierno2357f4e2020-10-19 16:38:59 +00001068 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001069 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1070 "cloud-init"
1071 ]
tierno2357f4e2020-10-19 16:38:59 +00001072 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001073 deploy_params_vdu = self._format_additional_params(
1074 vdur.get("additionalParams") or {}
1075 )
1076 deploy_params_vdu["OSM"] = get_osm_params(
1077 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1078 )
jegan932741c2024-04-01 10:54:53 +00001079 for vdu, value in deploy_params_vdu["OSM"]["vdu"].items():
1080 for interface, address in value["interfaces"].items():
1081 if address.get("mac_address"):
1082 address.pop("mac_address")
tierno2357f4e2020-10-19 16:38:59 +00001083 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001084
1085 # flavor
1086 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001087 if target_vim not in ns_flavor["vim_info"]:
1088 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001089
1090 # deal with images
1091 # in case alternative images are provided we must check if they should be applied
1092 # for the vim_type, modify the vim_type taking into account
1093 ns_image_id = int(vdur["ns-image-id"])
1094 if vdur.get("alt-image-ids"):
1095 db_vim = get_vim_account(vnfr["vim-account-id"])
1096 vim_type = db_vim["vim_type"]
1097 for alt_image_id in vdur.get("alt-image-ids"):
1098 ns_alt_image = target["image"][int(alt_image_id)]
1099 if vim_type == ns_alt_image.get("vim-type"):
1100 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001101 self.logger.debug(
1102 "use alternative image id: {}".format(alt_image_id)
1103 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001104 ns_image_id = alt_image_id
1105 vdur["ns-image-id"] = ns_image_id
1106 break
1107 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001108 if target_vim not in ns_image["vim_info"]:
1109 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001110
Alexis Romero305b5c42022-03-11 15:29:18 +01001111 # Affinity groups
1112 if vdur.get("affinity-or-anti-affinity-group-id"):
1113 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1114 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1115 if target_vim not in ns_ags["vim_info"]:
1116 ns_ags["vim_info"][target_vim] = {}
1117
vegall63162192023-03-06 14:19:16 +00001118 # shared-volumes
1119 if vdur.get("shared-volumes-id"):
1120 for sv_id in vdur["shared-volumes-id"]:
1121 ns_sv = find_in_list(
1122 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1123 )
1124 if ns_sv:
1125 ns_sv["vim_info"][target_vim] = {}
1126
tierno2357f4e2020-10-19 16:38:59 +00001127 vdur["vim_info"] = {target_vim: {}}
1128 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001129 if vnf_params:
1130 vdu_instantiation_params = find_in_list(
1131 get_iterable(vnf_params, "vdu"),
1132 lambda i_vdu: i_vdu["id"] == vdud["id"],
1133 )
1134 if vdu_instantiation_params:
1135 # Parse the vdu_volumes from the instantiation params
1136 vdu_volumes = get_volumes_from_instantiation_params(
1137 vdu_instantiation_params, vdud
1138 )
1139 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001140 vdur["additionalParams"]["OSM"][
1141 "vim_flavor_id"
1142 ] = vdu_instantiation_params.get("vim-flavor-id")
kayal20011028e362024-06-27 08:23:36 +05301143 vdur["additionalParams"]["OSM"][
kayal2001de102fe2024-11-28 10:51:52 +05301144 "vim_flavor_name"
1145 ] = vdu_instantiation_params.get("vim-flavor-name")
1146 vdur["additionalParams"]["OSM"][
kayal20011028e362024-06-27 08:23:36 +05301147 "instance_name"
1148 ] = vdu_instantiation_params.get("instance_name")
kayal2001ed6528c2024-11-28 11:31:56 +05301149 vdur["additionalParams"]["OSM"][
1150 "security-group-name"
1151 ] = vdu_instantiation_params.get("security-group-name")
tierno2357f4e2020-10-19 16:38:59 +00001152 vdur_list.append(vdur)
1153 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001154 target["vnf"].append(target_vnf)
1155
garciadeblas07f4e4c2022-06-09 09:42:58 +02001156 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001157 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001158 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001159 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001160 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001161 nsr_id,
1162 action_id,
1163 nslcmop_id,
1164 start_deploy,
1165 timeout_ns_deploy,
1166 stage,
1167 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001168 )
tierno69f0d382020-05-07 13:08:09 +00001169
1170 # Updating NSR
1171 db_nsr_update = {
1172 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001173 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001174 }
1175 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1176 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1177 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001178 self.logger.debug(
1179 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1180 )
tierno69f0d382020-05-07 13:08:09 +00001181 return
1182
garciadeblas5697b8b2021-03-24 09:17:02 +01001183 async def _wait_ng_ro(
1184 self,
1185 nsr_id,
1186 action_id,
1187 nslcmop_id=None,
1188 start_time=None,
1189 timeout=600,
1190 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001191 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001192 ):
tierno69f0d382020-05-07 13:08:09 +00001193 detailed_status_old = None
1194 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001195 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001196 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001197 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001198 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001199 if desc_status["status"] == "FAILED":
1200 raise NgRoException(desc_status["details"])
1201 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001202 if stage:
1203 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001204 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001205 if stage:
1206 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001207 break
1208 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001209 assert False, "ROclient.check_ns_status returns unknown {}".format(
1210 desc_status["status"]
1211 )
tierno2357f4e2020-10-19 16:38:59 +00001212 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001213 detailed_status_old = stage[2]
1214 db_nsr_update["detailed-status"] = " ".join(stage)
1215 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1216 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001217 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001218 else: # timeout_ns_deploy
1219 raise NgRoException("Timeout waiting ns to deploy")
1220
jegan76777192024-07-01 16:47:53 +00001221 def rollback_scaling(self, nsr_id, nslcmop_id):
1222 try:
1223 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
1224 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1225 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
1226 "scaleByStepData"
1227 ]["member-vnf-index"]
1228 db_vnfr = self.db.get_one(
1229 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
1230 )
1231 vim_id = "vim:{}".format(db_vnfr["vim-account-id"])
1232 db_vnfr_update = {"vdur": db_vnfr["vdur"]}
1233 counter = len(db_vnfr_update["vdur"])
1234 updated_db_vnfr = []
1235 for index, vdur in enumerate(db_vnfr_update["vdur"]):
1236 if vdur["vim_info"][vim_id].get("vim_status") == "ACTIVE":
1237 updated_db_vnfr.append(vdur)
1238 db_vnfr_update["vdur"] = updated_db_vnfr
1239 self.update_db_2("vnfrs", db_vnfr["_id"], db_vnfr_update)
1240 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
1241 "scaleByStepData"
1242 ]["scaling-group-descriptor"]
1243 counter -= len(updated_db_vnfr)
1244 db_nsr_update = {
1245 "_admin.scaling-group": db_nsr["_admin"].get("scaling-group")
1246 }
1247 if db_nsr["_admin"].get("scaling-group"):
1248 for index, group in enumerate(db_nsr_update["_admin.scaling-group"]):
1249 if (
1250 group["name"] == scaling_group
1251 and group["vnf_index"] == vnf_index
1252 ):
1253 group["nb-scale-op"] -= counter
1254 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1255 except Exception as e:
1256 self.logger.info(f"There is an error in updating the database. Error {e}")
1257
garciadeblas5697b8b2021-03-24 09:17:02 +01001258 async def _terminate_ng_ro(
1259 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1260 ):
tierno69f0d382020-05-07 13:08:09 +00001261 db_nsr_update = {}
1262 failed_detail = []
1263 action_id = None
1264 start_deploy = time()
1265 try:
1266 target = {
1267 "ns": {"vld": []},
1268 "vnf": [],
1269 "image": [],
1270 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001271 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001272 }
1273 desc = await self.RO.deploy(nsr_id, target)
1274 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001275 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001276 self.logger.debug(
1277 logging_text
1278 + "ns terminate action at RO. action_id={}".format(action_id)
1279 )
tierno69f0d382020-05-07 13:08:09 +00001280
1281 # wait until done
1282 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001283 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001284 nsr_id,
1285 action_id,
1286 nslcmop_id,
1287 start_deploy,
1288 delete_timeout,
1289 stage,
1290 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001291 )
tierno69f0d382020-05-07 13:08:09 +00001292 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1293 # delete all nsr
1294 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001295 except NgRoException as e:
1296 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001297 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1298 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001299 self.logger.debug(
1300 logging_text + "RO_action_id={} already deleted".format(action_id)
1301 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001302 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001303 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001304 self.logger.debug(
1305 logging_text
1306 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1307 )
tierno69f0d382020-05-07 13:08:09 +00001308 else:
1309 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001310 self.logger.error(
1311 logging_text
1312 + "RO_action_id={} delete error: {}".format(action_id, e)
1313 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001314 except Exception as e:
1315 failed_detail.append("delete error: {}".format(e))
1316 self.logger.error(
1317 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1318 )
tierno69f0d382020-05-07 13:08:09 +00001319
1320 if failed_detail:
1321 stage[2] = "Error deleting from VIM"
1322 else:
1323 stage[2] = "Deleted from VIM"
1324 db_nsr_update["detailed-status"] = " ".join(stage)
1325 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1326 self._write_op_status(nslcmop_id, stage)
1327
1328 if failed_detail:
1329 raise LcmException("; ".join(failed_detail))
1330 return
1331
garciadeblas5697b8b2021-03-24 09:17:02 +01001332 async def instantiate_RO(
1333 self,
1334 logging_text,
1335 nsr_id,
1336 nsd,
1337 db_nsr,
1338 db_nslcmop,
1339 db_vnfrs,
1340 db_vnfds,
1341 n2vc_key_list,
1342 stage,
1343 ):
tiernoe95ed362020-04-23 08:24:57 +00001344 """
1345 Instantiate at RO
1346 :param logging_text: preffix text to use at logging
1347 :param nsr_id: nsr identity
1348 :param nsd: database content of ns descriptor
1349 :param db_nsr: database content of ns record
1350 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1351 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001352 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001353 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1354 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1355 :return: None or exception
1356 """
tiernoe876f672020-02-13 14:34:48 +00001357 try:
tiernoe876f672020-02-13 14:34:48 +00001358 start_deploy = time()
1359 ns_params = db_nslcmop.get("operationParams")
1360 if ns_params and ns_params.get("timeout_ns_deploy"):
1361 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1362 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001363 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001364
tiernoe876f672020-02-13 14:34:48 +00001365 # Check for and optionally request placement optimization. Database will be updated if placement activated
1366 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001367 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1368 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1369 for vnfr in db_vnfrs.values():
1370 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1371 break
1372 else:
1373 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001374
garciadeblas5697b8b2021-03-24 09:17:02 +01001375 return await self._instantiate_ng_ro(
1376 logging_text,
1377 nsr_id,
1378 nsd,
1379 db_nsr,
1380 db_nslcmop,
1381 db_vnfrs,
1382 db_vnfds,
1383 n2vc_key_list,
1384 stage,
1385 start_deploy,
1386 timeout_ns_deploy,
1387 )
tierno2357f4e2020-10-19 16:38:59 +00001388 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001389 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001390 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001391 self.logger.error(
1392 "Error deploying at VIM {}".format(e),
1393 exc_info=not isinstance(
1394 e,
1395 (
1396 ROclient.ROClientException,
1397 LcmException,
1398 DbException,
1399 NgRoException,
1400 ),
1401 ),
1402 )
tiernoe876f672020-02-13 14:34:48 +00001403 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001404
tierno7ecbc342020-09-21 14:05:39 +00001405 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1406 """
1407 Wait for kdu to be up, get ip address
1408 :param logging_text: prefix use for logging
1409 :param nsr_id:
1410 :param vnfr_id:
1411 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001412 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001413 """
1414
1415 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1416 nb_tries = 0
1417
1418 while nb_tries < 360:
1419 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001420 kdur = next(
1421 (
1422 x
1423 for x in get_iterable(db_vnfr, "kdur")
1424 if x.get("kdu-name") == kdu_name
1425 ),
1426 None,
1427 )
tierno7ecbc342020-09-21 14:05:39 +00001428 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001429 raise LcmException(
1430 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1431 )
tierno7ecbc342020-09-21 14:05:39 +00001432 if kdur.get("status"):
1433 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001434 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001435 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001436 raise LcmException(
1437 "target KDU={} is in error state".format(kdu_name)
1438 )
tierno7ecbc342020-09-21 14:05:39 +00001439
Gabriel Cubae7898982023-05-11 01:57:21 -05001440 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001441 nb_tries += 1
1442 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1443
garciadeblas5697b8b2021-03-24 09:17:02 +01001444 async def wait_vm_up_insert_key_ro(
1445 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1446 ):
tiernoa5088192019-11-26 16:12:53 +00001447 """
1448 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1449 :param logging_text: prefix use for logging
1450 :param nsr_id:
1451 :param vnfr_id:
1452 :param vdu_id:
1453 :param vdu_index:
1454 :param pub_key: public ssh key to inject, None to skip
1455 :param user: user to apply the public ssh key
1456 :return: IP address
1457 """
quilesj7e13aeb2019-10-08 13:34:55 +02001458
tierno2357f4e2020-10-19 16:38:59 +00001459 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001460 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001461 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001462 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001463
tiernod8323042019-08-09 11:32:23 +00001464 while True:
quilesj3149f262019-12-03 10:58:10 +00001465 ro_retries += 1
1466 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001467 raise LcmException(
1468 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1469 )
quilesj3149f262019-12-03 10:58:10 +00001470
Gabriel Cubae7898982023-05-11 01:57:21 -05001471 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001472
1473 # get ip address
tiernod8323042019-08-09 11:32:23 +00001474 if not target_vdu_id:
1475 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001476
1477 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001478 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001479 raise LcmException(
1480 "Cannot inject ssh-key because target VNF is in error state"
1481 )
tiernod8323042019-08-09 11:32:23 +00001482 ip_address = db_vnfr.get("ip-address")
1483 if not ip_address:
1484 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001485 vdur = next(
1486 (
1487 x
1488 for x in get_iterable(db_vnfr, "vdur")
1489 if x.get("ip-address") == ip_address
1490 ),
1491 None,
1492 )
quilesj3149f262019-12-03 10:58:10 +00001493 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001494 vdur = next(
1495 (
1496 x
1497 for x in get_iterable(db_vnfr, "vdur")
1498 if x.get("vdu-id-ref") == vdu_id
1499 and x.get("count-index") == vdu_index
1500 ),
1501 None,
1502 )
quilesj3149f262019-12-03 10:58:10 +00001503
garciadeblas5697b8b2021-03-24 09:17:02 +01001504 if (
1505 not vdur and len(db_vnfr.get("vdur", ())) == 1
1506 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001507 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001508 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001509 raise LcmException(
1510 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1511 vnfr_id, vdu_id, vdu_index
1512 )
1513 )
tierno2357f4e2020-10-19 16:38:59 +00001514 # New generation RO stores information at "vim_info"
1515 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001516 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001517 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001518 target_vim = next(
1519 t for t in vdur["vim_info"]
1520 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001521 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001522 if (
1523 vdur.get("pdu-type")
1524 or vdur.get("status") == "ACTIVE"
1525 or ng_ro_status == "ACTIVE"
1526 ):
quilesj3149f262019-12-03 10:58:10 +00001527 ip_address = vdur.get("ip-address")
1528 if not ip_address:
1529 continue
1530 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001531 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001532 raise LcmException(
1533 "Cannot inject ssh-key because target VM is in error state"
1534 )
quilesj3149f262019-12-03 10:58:10 +00001535
tiernod8323042019-08-09 11:32:23 +00001536 if not target_vdu_id:
1537 continue
tiernod8323042019-08-09 11:32:23 +00001538
quilesj7e13aeb2019-10-08 13:34:55 +02001539 # inject public key into machine
1540 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001541 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001542 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001543 if vdur.get("pdu-type"):
1544 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1545 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001546 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001547 target = {
1548 "action": {
1549 "action": "inject_ssh_key",
1550 "key": pub_key,
1551 "user": user,
1552 },
1553 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1554 }
1555 desc = await self.RO.deploy(nsr_id, target)
1556 action_id = desc["action_id"]
1557 await self._wait_ng_ro(
1558 nsr_id, action_id, timeout=600, operation="instantiation"
1559 )
1560 break
tierno69f0d382020-05-07 13:08:09 +00001561 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001562 raise LcmException(
1563 "Reaching max tries injecting key. Error: {}".format(e)
1564 )
quilesj7e13aeb2019-10-08 13:34:55 +02001565 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001566 break
1567
1568 return ip_address
1569
tierno5ee02052019-12-05 19:55:02 +00001570 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1571 """
1572 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1573 """
1574 my_vca = vca_deployed_list[vca_index]
1575 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001576 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001577 return
1578 timeout = 300
1579 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001580 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1581 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1582 configuration_status_list = db_nsr["configurationStatus"]
1583 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001584 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001585 # myself
tierno5ee02052019-12-05 19:55:02 +00001586 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001587 if not my_vca.get("member-vnf-index") or (
1588 vca_deployed.get("member-vnf-index")
1589 == my_vca.get("member-vnf-index")
1590 ):
quilesj3655ae02019-12-12 16:08:35 +00001591 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001592 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001593 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001594 elif internal_status == "BROKEN":
1595 raise LcmException(
1596 "Configuration aborted because dependent charm/s has failed"
1597 )
quilesj3655ae02019-12-12 16:08:35 +00001598 else:
1599 break
tierno5ee02052019-12-05 19:55:02 +00001600 else:
quilesj3655ae02019-12-12 16:08:35 +00001601 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001602 return
1603 await asyncio.sleep(10)
1604 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001605
1606 raise LcmException("Configuration aborted because dependent charm/s timeout")
1607
David Garciac1fe90a2021-03-31 19:12:02 +02001608 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001609 vca_id = None
1610 if db_vnfr:
1611 vca_id = deep_get(db_vnfr, ("vca-id",))
1612 elif db_nsr:
1613 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1614 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1615 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001616
garciadeblas5697b8b2021-03-24 09:17:02 +01001617 async def instantiate_N2VC(
1618 self,
1619 logging_text,
1620 vca_index,
1621 nsi_id,
1622 db_nsr,
1623 db_vnfr,
1624 vdu_id,
1625 kdu_name,
1626 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001627 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001628 config_descriptor,
1629 deploy_params,
1630 base_folder,
1631 nslcmop_id,
1632 stage,
1633 vca_type,
1634 vca_name,
1635 ee_config_descriptor,
1636 ):
tiernod8323042019-08-09 11:32:23 +00001637 nsr_id = db_nsr["_id"]
1638 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001639 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001640 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001641 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001642 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001643 "collection": "nsrs",
1644 "filter": {"_id": nsr_id},
1645 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001646 }
tiernod8323042019-08-09 11:32:23 +00001647 step = ""
1648 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001649 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001650 element_under_configuration = nsr_id
1651
tiernod8323042019-08-09 11:32:23 +00001652 vnfr_id = None
1653 if db_vnfr:
1654 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001655 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001656
garciadeblas5697b8b2021-03-24 09:17:02 +01001657 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001658
aktas98488ed2021-07-29 17:42:49 +03001659 if vca_type == "native_charm":
1660 index_number = 0
1661 else:
1662 index_number = vdu_index or 0
1663
tiernod8323042019-08-09 11:32:23 +00001664 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001665 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001666 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001667 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001668 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001669 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001670 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001671 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001672 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001673 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001674 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001675 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001676 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001677 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001678
1679 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001680 if base_folder["pkg-dir"]:
1681 artifact_path = "{}/{}/{}/{}".format(
1682 base_folder["folder"],
1683 base_folder["pkg-dir"],
1684 "charms"
aticig15db6142022-01-24 12:51:26 +03001685 if vca_type
1686 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001687 else "helm-charts",
1688 vca_name,
1689 )
1690 else:
1691 artifact_path = "{}/Scripts/{}/{}/".format(
1692 base_folder["folder"],
1693 "charms"
aticig15db6142022-01-24 12:51:26 +03001694 if vca_type
1695 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001696 else "helm-charts",
1697 vca_name,
1698 )
bravof922c4172020-11-24 21:21:43 -03001699
1700 self.logger.debug("Artifact path > {}".format(artifact_path))
1701
tiernoa278b842020-07-08 15:33:55 +00001702 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001703 initial_config_primitive_list = config_descriptor.get(
1704 "initial-config-primitive"
1705 )
tiernoa278b842020-07-08 15:33:55 +00001706
garciadeblas5697b8b2021-03-24 09:17:02 +01001707 self.logger.debug(
1708 "Initial config primitive list > {}".format(
1709 initial_config_primitive_list
1710 )
1711 )
bravof922c4172020-11-24 21:21:43 -03001712
tiernoa278b842020-07-08 15:33:55 +00001713 # add config if not present for NS charm
1714 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001715 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001716 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1717 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1718 )
tiernod8323042019-08-09 11:32:23 +00001719
garciadeblas5697b8b2021-03-24 09:17:02 +01001720 self.logger.debug(
1721 "Initial config primitive list #2 > {}".format(
1722 initial_config_primitive_list
1723 )
1724 )
tierno588547c2020-07-01 15:30:20 +00001725 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001726 # find old ee_id if exists
1727 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001728
David Garciac1fe90a2021-03-31 19:12:02 +02001729 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001730 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001731 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001732 self._write_configuration_status(
1733 nsr_id=nsr_id,
1734 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001735 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001736 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001737 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001738 )
tiernod8323042019-08-09 11:32:23 +00001739
tierno588547c2020-07-01 15:30:20 +00001740 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001741 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001742
1743 ee_id = None
1744 credentials = None
1745 if vca_type == "k8s_proxy_charm":
1746 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001747 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001748 namespace=namespace,
1749 artifact_path=artifact_path,
1750 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001751 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001752 )
Luis Vegae11384e2023-10-10 22:36:33 +00001753 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001754 ee_id, credentials = await self.vca_map[
1755 vca_type
1756 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001757 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001758 reuse_ee_id=ee_id,
1759 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001760 config=osm_config,
1761 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001762 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001763 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001764 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001765 else:
1766 ee_id, credentials = await self.vca_map[
1767 vca_type
1768 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001769 namespace=namespace,
1770 reuse_ee_id=ee_id,
1771 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001772 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001773 )
quilesj3655ae02019-12-12 16:08:35 +00001774
tierno588547c2020-07-01 15:30:20 +00001775 elif vca_type == "native_charm":
1776 step = "Waiting to VM being up and getting IP address"
1777 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001778 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1779 logging_text,
1780 nsr_id,
1781 vnfr_id,
1782 vdu_id,
1783 vdu_index,
1784 user=None,
1785 pub_key=None,
1786 )
tierno588547c2020-07-01 15:30:20 +00001787 credentials = {"hostname": rw_mgmt_ip}
1788 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001789 username = deep_get(
1790 config_descriptor, ("config-access", "ssh-access", "default-user")
1791 )
tierno588547c2020-07-01 15:30:20 +00001792 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1793 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001794 if not username and initial_config_primitive_list:
1795 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001796 for param in config_primitive.get("parameter", ()):
1797 if param["name"] == "ssh-username":
1798 username = param["value"]
1799 break
1800 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001801 raise LcmException(
1802 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1803 "'config-access.ssh-access.default-user'"
1804 )
tierno588547c2020-07-01 15:30:20 +00001805 credentials["username"] = username
1806 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001807
tierno588547c2020-07-01 15:30:20 +00001808 self._write_configuration_status(
1809 nsr_id=nsr_id,
1810 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001811 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001812 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001813 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001814 )
quilesj3655ae02019-12-12 16:08:35 +00001815
tierno588547c2020-07-01 15:30:20 +00001816 step = "register execution environment {}".format(credentials)
1817 self.logger.debug(logging_text + step)
1818 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001819 credentials=credentials,
1820 namespace=namespace,
1821 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001822 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001823 )
tierno3bedc9b2019-11-27 15:46:57 +00001824
tierno588547c2020-07-01 15:30:20 +00001825 # for compatibility with MON/POL modules, the need model and application name at database
1826 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001827 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001828 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1829 if len(ee_id_parts) >= 2:
1830 model_name = ee_id_parts[0]
1831 application_name = ee_id_parts[1]
1832 db_nsr_update[db_update_entry + "model"] = model_name
1833 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001834
1835 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001836 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001837
tiernoc231a872020-01-21 08:49:05 +00001838 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001839 nsr_id=nsr_id,
1840 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001841 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001842 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001843 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001844 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001845 )
1846
tierno3bedc9b2019-11-27 15:46:57 +00001847 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001848 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001849 config = None
tierno588547c2020-07-01 15:30:20 +00001850 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001851 config_primitive = next(
1852 (p for p in initial_config_primitive_list if p["name"] == "config"),
1853 None,
1854 )
tiernoa278b842020-07-08 15:33:55 +00001855 if config_primitive:
1856 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001857 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001858 )
tierno588547c2020-07-01 15:30:20 +00001859 num_units = 1
1860 if vca_type == "lxc_proxy_charm":
1861 if element_type == "NS":
1862 num_units = db_nsr.get("config-units") or 1
1863 elif element_type == "VNF":
1864 num_units = db_vnfr.get("config-units") or 1
1865 elif element_type == "VDU":
1866 for v in db_vnfr["vdur"]:
1867 if vdu_id == v["vdu-id-ref"]:
1868 num_units = v.get("config-units") or 1
1869 break
David Garciaaae391f2020-11-09 11:12:54 +01001870 if vca_type != "k8s_proxy_charm":
1871 await self.vca_map[vca_type].install_configuration_sw(
1872 ee_id=ee_id,
1873 artifact_path=artifact_path,
1874 db_dict=db_dict,
1875 config=config,
1876 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001877 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001878 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001879 )
quilesj7e13aeb2019-10-08 13:34:55 +02001880
quilesj63f90042020-01-17 09:53:55 +00001881 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001882 self.update_db_2(
1883 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1884 )
quilesj63f90042020-01-17 09:53:55 +00001885
1886 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001887 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001888 logging_text=logging_text,
1889 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001890 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001891 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001892 )
quilesj63f90042020-01-17 09:53:55 +00001893
Patricia Reinosob4312c02023-01-06 22:28:44 +00001894 if not is_relation_added:
1895 raise LcmException("Relations could not be added to VCA.")
1896
quilesj7e13aeb2019-10-08 13:34:55 +02001897 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001898 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001899 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001900 pub_key = None
1901 user = None
tierno588547c2020-07-01 15:30:20 +00001902 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001903 if deep_get(
1904 config_descriptor, ("config-access", "ssh-access", "required")
1905 ):
tierno588547c2020-07-01 15:30:20 +00001906 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001907 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001908 user = deep_get(
1909 config_descriptor,
1910 ("config-access", "ssh-access", "default-user"),
1911 )
tierno3bedc9b2019-11-27 15:46:57 +00001912 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001913 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001914 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001915 )
quilesj7e13aeb2019-10-08 13:34:55 +02001916
garciadeblas5697b8b2021-03-24 09:17:02 +01001917 step = "Insert public key into VM user={} ssh_key={}".format(
1918 user, pub_key
1919 )
tierno3bedc9b2019-11-27 15:46:57 +00001920 else:
tierno588547c2020-07-01 15:30:20 +00001921 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001922 step = "Waiting to VM being up and getting IP address"
1923 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001924
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001925 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1926 rw_mgmt_ip = None
1927
tierno3bedc9b2019-11-27 15:46:57 +00001928 # n2vc_redesign STEP 5.1
1929 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001930 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001931 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001932 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001933 logging_text, nsr_id, vnfr_id, kdu_name
1934 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001935 vnfd = self.db.get_one(
1936 "vnfds_revisions",
1937 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1938 )
1939 kdu = get_kdu(vnfd, kdu_name)
1940 kdu_services = [
1941 service["name"] for service in get_kdu_services(kdu)
1942 ]
1943 exposed_services = []
1944 for service in services:
1945 if any(s in service["name"] for s in kdu_services):
1946 exposed_services.append(service)
1947 await self.vca_map[vca_type].exec_primitive(
1948 ee_id=ee_id,
1949 primitive_name="config",
1950 params_dict={
1951 "osm-config": json.dumps(
1952 OsmConfigBuilder(
1953 k8s={"services": exposed_services}
1954 ).build()
1955 )
1956 },
1957 vca_id=vca_id,
1958 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001959
1960 # This verification is needed in order to avoid trying to add a public key
1961 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1962 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1963 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1964 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001965 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001966 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1967 logging_text,
1968 nsr_id,
1969 vnfr_id,
1970 vdu_id,
1971 vdu_index,
1972 user=user,
1973 pub_key=pub_key,
1974 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001975
garciadeblas5697b8b2021-03-24 09:17:02 +01001976 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001977
tiernoa5088192019-11-26 16:12:53 +00001978 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001979 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001980
1981 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001982 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001983
1984 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001985 if initial_config_primitive_list:
1986 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001987
1988 # stage, in function of element type: vdu, kdu, vnf or ns
1989 my_vca = vca_deployed_list[vca_index]
1990 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1991 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001992 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001993 elif my_vca.get("member-vnf-index"):
1994 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001995 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001996 else:
1997 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001998 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00001999
tiernoc231a872020-01-21 08:49:05 +00002000 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002001 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002002 )
2003
garciadeblas5697b8b2021-03-24 09:17:02 +01002004 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002005
tiernoe876f672020-02-13 14:34:48 +00002006 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002007 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002008 # adding information on the vca_deployed if it is a NS execution environment
2009 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002010 deploy_params["ns_config_info"] = json.dumps(
2011 self._get_ns_config_info(nsr_id)
2012 )
tiernod8323042019-08-09 11:32:23 +00002013 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002014 primitive_params_ = self._map_primitive_params(
2015 initial_config_primitive, {}, deploy_params
2016 )
tierno3bedc9b2019-11-27 15:46:57 +00002017
garciadeblas5697b8b2021-03-24 09:17:02 +01002018 step = "execute primitive '{}' params '{}'".format(
2019 initial_config_primitive["name"], primitive_params_
2020 )
tiernod8323042019-08-09 11:32:23 +00002021 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002022 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002023 ee_id=ee_id,
2024 primitive_name=initial_config_primitive["name"],
2025 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002026 db_dict=db_dict,
2027 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002028 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002029 )
tiernoe876f672020-02-13 14:34:48 +00002030 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2031 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002032 if config_descriptor.get("terminate-config-primitive"):
2033 self.update_db_2(
2034 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2035 )
tiernoe876f672020-02-13 14:34:48 +00002036 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002037
tiernod8323042019-08-09 11:32:23 +00002038 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002039
tiernob996d942020-07-03 14:52:28 +00002040 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00002041 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02002042 # TODO: review for those cases where the helm chart is a reference and
2043 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002044 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002045 ee_id=ee_id,
2046 artifact_path=artifact_path,
2047 ee_config_descriptor=ee_config_descriptor,
2048 vnfr_id=vnfr_id,
2049 nsr_id=nsr_id,
2050 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002051 element_type=element_type,
2052 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2053 vdu_id=vdu_id,
2054 vdu_index=vdu_index,
2055 kdu_name=kdu_name,
2056 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002057 )
2058 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002059 self.update_db_2(
2060 "nsrs",
2061 nsr_id,
2062 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2063 )
tiernob996d942020-07-03 14:52:28 +00002064
bravof73bac502021-05-11 07:38:47 -04002065 for job in prometheus_jobs:
2066 self.db.set_one(
2067 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002068 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002069 job,
2070 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002071 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002072 )
2073
quilesj7e13aeb2019-10-08 13:34:55 +02002074 step = "instantiated at VCA"
2075 self.logger.debug(logging_text + step)
2076
tiernoc231a872020-01-21 08:49:05 +00002077 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002078 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002079 )
2080
tiernod8323042019-08-09 11:32:23 +00002081 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002082 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002083 if not isinstance(
2084 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2085 ):
2086 self.logger.error(
2087 "Exception while {} : {}".format(step, e), exc_info=True
2088 )
tiernoc231a872020-01-21 08:49:05 +00002089 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002090 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002091 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002092 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002093
garciadeblas5697b8b2021-03-24 09:17:02 +01002094 def _write_ns_status(
2095 self,
2096 nsr_id: str,
2097 ns_state: str,
2098 current_operation: str,
2099 current_operation_id: str,
2100 error_description: str = None,
2101 error_detail: str = None,
2102 other_update: dict = None,
2103 ):
tiernoe876f672020-02-13 14:34:48 +00002104 """
2105 Update db_nsr fields.
2106 :param nsr_id:
2107 :param ns_state:
2108 :param current_operation:
2109 :param current_operation_id:
2110 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002111 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002112 :param other_update: Other required changes at database if provided, will be cleared
2113 :return:
2114 """
quilesj4cda56b2019-12-05 10:02:20 +00002115 try:
tiernoe876f672020-02-13 14:34:48 +00002116 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002117 db_dict[
2118 "_admin.nslcmop"
2119 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002120 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002121 db_dict["_admin.operation-type"] = (
2122 current_operation if current_operation != "IDLE" else None
2123 )
quilesj4cda56b2019-12-05 10:02:20 +00002124 db_dict["currentOperation"] = current_operation
2125 db_dict["currentOperationID"] = current_operation_id
2126 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002127 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002128
2129 if ns_state:
2130 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002131 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002132 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002133 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002134
garciadeblas5697b8b2021-03-24 09:17:02 +01002135 def _write_op_status(
2136 self,
2137 op_id: str,
2138 stage: list = None,
2139 error_message: str = None,
2140 queuePosition: int = 0,
2141 operation_state: str = None,
2142 other_update: dict = None,
2143 ):
quilesj3655ae02019-12-12 16:08:35 +00002144 try:
tiernoe876f672020-02-13 14:34:48 +00002145 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002146 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002147 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002148 db_dict["stage"] = stage[0]
2149 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002150 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002151 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002152
2153 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002154 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002155 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002156 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002157 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002158 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002159 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002160 self.logger.warn(
2161 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2162 )
quilesj3655ae02019-12-12 16:08:35 +00002163
tierno51183952020-04-03 15:48:18 +00002164 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002165 try:
tierno51183952020-04-03 15:48:18 +00002166 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002167 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002168 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002169 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002170 db_nsr_update = {
2171 "configurationStatus.{}.status".format(index): status
2172 for index, v in enumerate(config_status)
2173 if v
2174 }
quilesj3655ae02019-12-12 16:08:35 +00002175 # update status
tierno51183952020-04-03 15:48:18 +00002176 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002177
tiernoe876f672020-02-13 14:34:48 +00002178 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002179 self.logger.warn(
2180 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2181 )
quilesj3655ae02019-12-12 16:08:35 +00002182
garciadeblas5697b8b2021-03-24 09:17:02 +01002183 def _write_configuration_status(
2184 self,
2185 nsr_id: str,
2186 vca_index: int,
2187 status: str = None,
2188 element_under_configuration: str = None,
2189 element_type: str = None,
2190 other_update: dict = None,
2191 ):
quilesj3655ae02019-12-12 16:08:35 +00002192 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2193 # .format(vca_index, status))
2194
2195 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002196 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002197 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002198 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002199 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002200 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002201 db_dict[
2202 db_path + "elementUnderConfiguration"
2203 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002204 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002205 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002206 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002207 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002208 self.logger.warn(
2209 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2210 status, nsr_id, vca_index, e
2211 )
2212 )
quilesj4cda56b2019-12-05 10:02:20 +00002213
tierno38089af2020-04-16 07:56:58 +00002214 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2215 """
2216 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2217 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2218 Database is used because the result can be obtained from a different LCM worker in case of HA.
2219 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2220 :param db_nslcmop: database content of nslcmop
2221 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002222 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2223 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002224 """
tierno8790a3d2020-04-23 22:49:52 +00002225 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002226 nslcmop_id = db_nslcmop["_id"]
2227 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002228 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002229 self.logger.debug(
2230 logging_text + "Invoke and wait for placement optimization"
2231 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002232 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002233 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002234 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002235 pla_result = None
2236 while not pla_result and wait >= 0:
2237 await asyncio.sleep(db_poll_interval)
2238 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002239 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002240 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002241
2242 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002243 raise LcmException(
2244 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2245 )
magnussonle9198bb2020-01-21 13:00:51 +01002246
garciadeblas5697b8b2021-03-24 09:17:02 +01002247 for pla_vnf in pla_result["vnf"]:
2248 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2249 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002250 continue
tierno8790a3d2020-04-23 22:49:52 +00002251 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002252 self.db.set_one(
2253 "vnfrs",
2254 {"_id": vnfr["_id"]},
2255 {"vim-account-id": pla_vnf["vimAccountId"]},
2256 )
tierno38089af2020-04-16 07:56:58 +00002257 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002258 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002259 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002260
aguilard1ae3c562023-02-16 17:24:35 +00002261 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2262 alerts = []
2263 nsr_id = vnfr["nsr-id-ref"]
2264 df = vnfd.get("df", [{}])[0]
2265 # Checking for auto-healing configuration
2266 if "healing-aspect" in df:
2267 healing_aspects = df["healing-aspect"]
2268 for healing in healing_aspects:
2269 for healing_policy in healing.get("healing-policy", ()):
2270 vdu_id = healing_policy["vdu-id"]
2271 vdur = next(
2272 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2273 {},
2274 )
2275 if not vdur:
2276 continue
2277 metric_name = "vm_status"
2278 vdu_name = vdur.get("name")
2279 vnf_member_index = vnfr["member-vnf-index-ref"]
2280 uuid = str(uuid4())
2281 name = f"healing_{uuid}"
2282 action = healing_policy
2283 # action_on_recovery = healing.get("action-on-recovery")
2284 # cooldown_time = healing.get("cooldown-time")
2285 # day1 = healing.get("day1")
2286 alert = {
2287 "uuid": uuid,
2288 "name": name,
2289 "metric": metric_name,
2290 "tags": {
2291 "ns_id": nsr_id,
2292 "vnf_member_index": vnf_member_index,
2293 "vdu_name": vdu_name,
2294 },
2295 "alarm_status": "ok",
2296 "action_type": "healing",
2297 "action": action,
2298 }
2299 alerts.append(alert)
2300 return alerts
2301
2302 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2303 alerts = []
2304 nsr_id = vnfr["nsr-id-ref"]
2305 df = vnfd.get("df", [{}])[0]
2306 # Checking for auto-scaling configuration
2307 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002308 scaling_aspects = df["scaling-aspect"]
2309 all_vnfd_monitoring_params = {}
2310 for ivld in vnfd.get("int-virtual-link-desc", ()):
2311 for mp in ivld.get("monitoring-parameters", ()):
2312 all_vnfd_monitoring_params[mp.get("id")] = mp
2313 for vdu in vnfd.get("vdu", ()):
2314 for mp in vdu.get("monitoring-parameter", ()):
2315 all_vnfd_monitoring_params[mp.get("id")] = mp
2316 for df in vnfd.get("df", ()):
2317 for mp in df.get("monitoring-parameter", ()):
2318 all_vnfd_monitoring_params[mp.get("id")] = mp
2319 for scaling_aspect in scaling_aspects:
2320 scaling_group_name = scaling_aspect.get("name", "")
2321 # Get monitored VDUs
2322 all_monitored_vdus = set()
2323 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2324 "deltas", ()
2325 ):
2326 for vdu_delta in delta.get("vdu-delta", ()):
2327 all_monitored_vdus.add(vdu_delta.get("id"))
2328 monitored_vdurs = list(
2329 filter(
2330 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2331 vnfr["vdur"],
2332 )
2333 )
2334 if not monitored_vdurs:
2335 self.logger.error(
2336 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2337 )
2338 continue
2339 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2340 if scaling_policy["scaling-type"] != "automatic":
2341 continue
2342 threshold_time = scaling_policy.get("threshold-time", "1")
2343 cooldown_time = scaling_policy.get("cooldown-time", "0")
2344 for scaling_criteria in scaling_policy["scaling-criteria"]:
2345 monitoring_param_ref = scaling_criteria.get(
2346 "vnf-monitoring-param-ref"
2347 )
2348 vnf_monitoring_param = all_vnfd_monitoring_params[
2349 monitoring_param_ref
2350 ]
2351 for vdur in monitored_vdurs:
2352 vdu_id = vdur["vdu-id-ref"]
2353 metric_name = vnf_monitoring_param.get("performance-metric")
Rahul Kumar54671c52024-05-09 15:34:01 +05302354 if "exporters-endpoints" not in df:
2355 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002356 vnf_member_index = vnfr["member-vnf-index-ref"]
2357 scalein_threshold = scaling_criteria.get(
2358 "scale-in-threshold"
2359 )
2360 scaleout_threshold = scaling_criteria.get(
2361 "scale-out-threshold"
2362 )
2363 # Looking for min/max-number-of-instances
2364 instances_min_number = 1
2365 instances_max_number = 1
2366 vdu_profile = df["vdu-profile"]
2367 if vdu_profile:
2368 profile = next(
2369 item for item in vdu_profile if item["id"] == vdu_id
2370 )
2371 instances_min_number = profile.get(
2372 "min-number-of-instances", 1
2373 )
2374 instances_max_number = profile.get(
2375 "max-number-of-instances", 1
2376 )
2377
2378 if scalein_threshold:
2379 uuid = str(uuid4())
2380 name = f"scalein_{uuid}"
2381 operation = scaling_criteria[
2382 "scale-in-relational-operation"
2383 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002384 rel_operator = self.rel_operation_types.get(
2385 operation, "<="
2386 )
aguilard1ae3c562023-02-16 17:24:35 +00002387 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2388 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302389 if (
2390 "exporters-endpoints" in df
2391 and metric_name.startswith("kpi_")
2392 ):
2393 new_metric_name = (
2394 f'osm_{metric_name.replace("kpi_", "").strip()}'
2395 )
2396 metric_port = df["exporters-endpoints"].get(
2397 "metric-port", 9100
2398 )
2399 vdu_ip = vdur["ip-address"]
2400 ip_port = str(vdu_ip) + ":" + str(metric_port)
2401 metric_selector = (
2402 f'{new_metric_name}{{instance="{ip_port}"}}'
2403 )
2404 expression = f"({metric_selector} {rel_operator} {scalein_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002405 labels = {
2406 "ns_id": nsr_id,
2407 "vnf_member_index": vnf_member_index,
2408 "vdu_id": vdu_id,
2409 }
2410 prom_cfg = {
2411 "alert": name,
2412 "expr": expression,
2413 "for": str(threshold_time) + "m",
2414 "labels": labels,
2415 }
2416 action = scaling_policy
2417 action = {
2418 "scaling-group": scaling_group_name,
2419 "cooldown-time": cooldown_time,
2420 }
2421 alert = {
2422 "uuid": uuid,
2423 "name": name,
2424 "metric": metric_name,
2425 "tags": {
2426 "ns_id": nsr_id,
2427 "vnf_member_index": vnf_member_index,
2428 "vdu_id": vdu_id,
2429 },
2430 "alarm_status": "ok",
2431 "action_type": "scale_in",
2432 "action": action,
2433 "prometheus_config": prom_cfg,
2434 }
2435 alerts.append(alert)
2436
2437 if scaleout_threshold:
2438 uuid = str(uuid4())
2439 name = f"scaleout_{uuid}"
2440 operation = scaling_criteria[
2441 "scale-out-relational-operation"
2442 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002443 rel_operator = self.rel_operation_types.get(
2444 operation, "<="
2445 )
aguilard1ae3c562023-02-16 17:24:35 +00002446 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2447 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302448 if (
2449 "exporters-endpoints" in df
2450 and metric_name.startswith("kpi_")
2451 ):
2452 new_metric_name = (
2453 f'osm_{metric_name.replace("kpi_", "").strip()}'
2454 )
2455 metric_port = df["exporters-endpoints"].get(
2456 "metric-port", 9100
2457 )
2458 vdu_ip = vdur["ip-address"]
2459 ip_port = str(vdu_ip) + ":" + str(metric_port)
2460 metric_selector = (
2461 f'{new_metric_name}{{instance="{ip_port}"}}'
2462 )
2463 expression = f"({metric_selector} {rel_operator} {scaleout_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002464 labels = {
2465 "ns_id": nsr_id,
2466 "vnf_member_index": vnf_member_index,
2467 "vdu_id": vdu_id,
2468 }
2469 prom_cfg = {
2470 "alert": name,
2471 "expr": expression,
2472 "for": str(threshold_time) + "m",
2473 "labels": labels,
2474 }
2475 action = scaling_policy
2476 action = {
2477 "scaling-group": scaling_group_name,
2478 "cooldown-time": cooldown_time,
2479 }
2480 alert = {
2481 "uuid": uuid,
2482 "name": name,
2483 "metric": metric_name,
2484 "tags": {
2485 "ns_id": nsr_id,
2486 "vnf_member_index": vnf_member_index,
2487 "vdu_id": vdu_id,
2488 },
2489 "alarm_status": "ok",
2490 "action_type": "scale_out",
2491 "action": action,
2492 "prometheus_config": prom_cfg,
2493 }
2494 alerts.append(alert)
2495 return alerts
2496
garciadeblas9148fa82023-05-30 12:51:14 +02002497 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2498 alerts = []
2499 nsr_id = vnfr["nsr-id-ref"]
2500 vnf_member_index = vnfr["member-vnf-index-ref"]
2501
2502 # Checking for VNF alarm configuration
2503 for vdur in vnfr["vdur"]:
2504 vdu_id = vdur["vdu-id-ref"]
2505 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2506 if "alarm" in vdu:
2507 # Get VDU monitoring params, since alerts are based on them
2508 vdu_monitoring_params = {}
2509 for mp in vdu.get("monitoring-parameter", []):
2510 vdu_monitoring_params[mp.get("id")] = mp
2511 if not vdu_monitoring_params:
2512 self.logger.error(
2513 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2514 )
2515 continue
2516 # Get alarms in the VDU
2517 alarm_descriptors = vdu["alarm"]
2518 # Create VDU alarms for each alarm in the VDU
2519 for alarm_descriptor in alarm_descriptors:
2520 # Check that the VDU alarm refers to a proper monitoring param
2521 alarm_monitoring_param = alarm_descriptor.get(
2522 "vnf-monitoring-param-ref", ""
2523 )
2524 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2525 alarm_monitoring_param, {}
2526 )
2527 if not vdu_specific_monitoring_param:
2528 self.logger.error(
2529 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2530 )
2531 continue
2532 metric_name = vdu_specific_monitoring_param.get(
2533 "performance-metric"
2534 )
2535 if not metric_name:
2536 self.logger.error(
2537 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2538 )
2539 continue
2540 # Set params of the alarm to be created in Prometheus
2541 metric_name = f"osm_{metric_name}"
2542 metric_threshold = alarm_descriptor.get("value")
2543 uuid = str(uuid4())
2544 alert_name = f"vdu_alarm_{uuid}"
2545 operation = alarm_descriptor["operation"]
2546 rel_operator = self.rel_operation_types.get(operation, "<=")
2547 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
aguilardeb076722023-05-31 09:45:00 +00002548 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002549 labels = {
2550 "ns_id": nsr_id,
2551 "vnf_member_index": vnf_member_index,
2552 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002553 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002554 }
2555 prom_cfg = {
2556 "alert": alert_name,
2557 "expr": expression,
2558 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2559 "labels": labels,
2560 }
2561 alarm_action = dict()
2562 for action_type in ["ok", "insufficient-data", "alarm"]:
2563 if (
2564 "actions" in alarm_descriptor
2565 and action_type in alarm_descriptor["actions"]
2566 ):
aguilardeb076722023-05-31 09:45:00 +00002567 alarm_action[action_type] = alarm_descriptor["actions"][
2568 action_type
2569 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002570 alert = {
2571 "uuid": uuid,
2572 "name": alert_name,
2573 "metric": metric_name,
2574 "tags": {
2575 "ns_id": nsr_id,
2576 "vnf_member_index": vnf_member_index,
2577 "vdu_id": vdu_id,
2578 },
2579 "alarm_status": "ok",
2580 "action_type": "vdu_alarm",
2581 "action": alarm_action,
2582 "prometheus_config": prom_cfg,
2583 }
2584 alerts.append(alert)
2585 return alerts
2586
magnussonle9198bb2020-01-21 13:00:51 +01002587 def update_nsrs_with_pla_result(self, params):
2588 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002589 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2590 self.update_db_2(
2591 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2592 )
magnussonle9198bb2020-01-21 13:00:51 +01002593 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002594 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002595
tierno59d22d22018-09-25 18:10:19 +02002596 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002597 """
2598
2599 :param nsr_id: ns instance to deploy
2600 :param nslcmop_id: operation to run
2601 :return:
2602 """
kuused124bfe2019-06-18 12:09:24 +02002603
2604 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002605 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002606 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002607 self.logger.debug(
2608 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2609 )
kuused124bfe2019-06-18 12:09:24 +02002610 return
2611
tierno59d22d22018-09-25 18:10:19 +02002612 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2613 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002614
tierno59d22d22018-09-25 18:10:19 +02002615 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002616
2617 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002618 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002619
2620 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002621 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002622
2623 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002624 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002625 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002626 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002627
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002628 timeout_ns_deploy = self.timeout.ns_deploy
2629
tierno59d22d22018-09-25 18:10:19 +02002630 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002631 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002632 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002633 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002634 exc = None
tiernoe876f672020-02-13 14:34:48 +00002635 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002636 stage = [
2637 "Stage 1/5: preparation of the environment.",
2638 "Waiting for previous operations to terminate.",
2639 "",
2640 ]
tiernoe876f672020-02-13 14:34:48 +00002641 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002642 try:
kuused124bfe2019-06-18 12:09:24 +02002643 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002644 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002645
quilesj7e13aeb2019-10-08 13:34:55 +02002646 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002647 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002648 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002649 db_nsr_update["detailed-status"] = "creating"
2650 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002651 self._write_ns_status(
2652 nsr_id=nsr_id,
2653 ns_state="BUILDING",
2654 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002655 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002656 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002657 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002658 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002659
quilesj7e13aeb2019-10-08 13:34:55 +02002660 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002661 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002662 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002663 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2664 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2665 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2666 )
tierno744303e2020-01-13 16:46:31 +00002667 ns_params = db_nslcmop.get("operationParams")
2668 if ns_params and ns_params.get("timeout_ns_deploy"):
2669 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002670
2671 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002672 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002673 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002674 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002675 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002676 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002677 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002678 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002679 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002680 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002681
quilesj7e13aeb2019-10-08 13:34:55 +02002682 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002683 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002684 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002685 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002686
quilesj7e13aeb2019-10-08 13:34:55 +02002687 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002688 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002689
2690 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002691 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002692 if vnfr.get("kdur"):
2693 kdur_list = []
2694 for kdur in vnfr["kdur"]:
2695 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002696 kdur["additionalParams"] = json.loads(
2697 kdur["additionalParams"]
2698 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002699 kdur_list.append(kdur)
2700 vnfr["kdur"] = kdur_list
2701
bravof922c4172020-11-24 21:21:43 -03002702 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2703 vnfd_id = vnfr["vnfd-id"]
2704 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002705 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002706
quilesj7e13aeb2019-10-08 13:34:55 +02002707 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002708 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002709 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002710 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2711 vnfd_id, vnfd_ref
2712 )
tiernoe876f672020-02-13 14:34:48 +00002713 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002714 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002715
quilesj7e13aeb2019-10-08 13:34:55 +02002716 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002717 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002718
2719 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002720 vca_deployed_list = None
2721 if db_nsr["_admin"].get("deployed"):
2722 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2723 if vca_deployed_list is None:
2724 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002725 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002726 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002727 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002728 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002729 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002730 elif isinstance(vca_deployed_list, dict):
2731 # maintain backward compatibility. Change a dict to list at database
2732 vca_deployed_list = list(vca_deployed_list.values())
2733 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002734 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002735
garciadeblas5697b8b2021-03-24 09:17:02 +01002736 if not isinstance(
2737 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2738 ):
tiernoa009e552019-01-30 16:45:44 +00002739 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2740 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002741
tiernobaa51102018-12-14 13:16:18 +00002742 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2743 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2744 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002745 self.db.set_list(
2746 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2747 )
quilesj3655ae02019-12-12 16:08:35 +00002748
2749 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002750 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2751 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002752
tiernob5203912020-08-11 11:20:13 +00002753 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002754 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002755 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002756 await self.deploy_kdus(
2757 logging_text=logging_text,
2758 nsr_id=nsr_id,
2759 nslcmop_id=nslcmop_id,
2760 db_vnfrs=db_vnfrs,
2761 db_vnfds=db_vnfds,
2762 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002763 )
tiernoe876f672020-02-13 14:34:48 +00002764
2765 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002766 # n2vc_redesign STEP 1 Get VCA public ssh-key
2767 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002768 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002769 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002770 if self.vca_config.public_key:
2771 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002772
tiernoe876f672020-02-13 14:34:48 +00002773 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002774 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002775 self.instantiate_RO(
2776 logging_text=logging_text,
2777 nsr_id=nsr_id,
2778 nsd=nsd,
2779 db_nsr=db_nsr,
2780 db_nslcmop=db_nslcmop,
2781 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002782 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002783 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002784 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002785 )
tiernod8323042019-08-09 11:32:23 +00002786 )
2787 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002788 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002789
tiernod8323042019-08-09 11:32:23 +00002790 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002791 stage[1] = "Deploying Execution Environments."
2792 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002793
Gabriel Cuba1411a002022-10-07 11:38:23 -05002794 # create namespace and certificate if any helm based EE is present in the NS
2795 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002796 await self.vca_map["helm-v3"].setup_ns_namespace(
2797 name=nsr_id,
2798 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002799 # create TLS certificates
2800 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002801 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002802 dns_prefix="*",
2803 nsr_id=nsr_id,
2804 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002805 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002806 )
2807
tiernod8323042019-08-09 11:32:23 +00002808 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002809 for vnf_profile in get_vnf_profiles(nsd):
2810 vnfd_id = vnf_profile["vnfd-id"]
2811 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2812 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002813 db_vnfr = db_vnfrs[member_vnf_index]
2814 base_folder = vnfd["_admin"]["storage"]
2815 vdu_id = None
2816 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002817 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002818 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002819 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002820
tierno8a518872018-12-21 13:42:14 +00002821 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002822 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002823 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002824 deploy_params.update(
2825 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2826 )
tierno8a518872018-12-21 13:42:14 +00002827
bravofe5a31bc2021-02-17 19:09:12 -03002828 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002829 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002830 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002831 logging_text=logging_text
2832 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002833 db_nsr=db_nsr,
2834 db_vnfr=db_vnfr,
2835 nslcmop_id=nslcmop_id,
2836 nsr_id=nsr_id,
2837 nsi_id=nsi_id,
2838 vnfd_id=vnfd_id,
2839 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002840 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002841 member_vnf_index=member_vnf_index,
2842 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002843 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002844 vdu_name=vdu_name,
2845 deploy_params=deploy_params,
2846 descriptor_config=descriptor_config,
2847 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002848 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002849 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002850 )
tierno59d22d22018-09-25 18:10:19 +02002851
2852 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002853 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002854 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002855 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002856 vdur = find_in_list(
2857 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2858 )
bravof922c4172020-11-24 21:21:43 -03002859
tierno626e0152019-11-29 14:16:16 +00002860 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002861 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002862 else:
2863 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002864 deploy_params_vdu["OSM"] = get_osm_params(
2865 db_vnfr, vdu_id, vdu_count_index=0
2866 )
endika76ba9232021-06-21 18:55:07 +02002867 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002868
2869 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002870 self.logger.debug(
2871 "Descriptor config > {}".format(descriptor_config)
2872 )
tierno588547c2020-07-01 15:30:20 +00002873 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002874 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002875 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002876 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002877 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002878 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002879 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002880 logging_text=logging_text
2881 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2882 member_vnf_index, vdu_id, vdu_index
2883 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002884 db_nsr=db_nsr,
2885 db_vnfr=db_vnfr,
2886 nslcmop_id=nslcmop_id,
2887 nsr_id=nsr_id,
2888 nsi_id=nsi_id,
2889 vnfd_id=vnfd_id,
2890 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002891 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002892 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002893 member_vnf_index=member_vnf_index,
2894 vdu_index=vdu_index,
2895 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002896 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002897 descriptor_config=descriptor_config,
2898 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002899 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002900 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002901 )
bravof922c4172020-11-24 21:21:43 -03002902 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002903 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002904 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002905 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002906 vdu_id = None
2907 vdu_index = 0
2908 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002909 kdu_index, kdur = next(
2910 x
2911 for x in enumerate(db_vnfr["kdur"])
2912 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002913 )
bravof922c4172020-11-24 21:21:43 -03002914 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002915 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002916 deploy_params_kdu.update(
2917 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002918 )
tierno59d22d22018-09-25 18:10:19 +02002919
calvinosanch9f9c6f22019-11-04 13:37:39 +01002920 self._deploy_n2vc(
2921 logging_text=logging_text,
2922 db_nsr=db_nsr,
2923 db_vnfr=db_vnfr,
2924 nslcmop_id=nslcmop_id,
2925 nsr_id=nsr_id,
2926 nsi_id=nsi_id,
2927 vnfd_id=vnfd_id,
2928 vdu_id=vdu_id,
2929 kdu_name=kdu_name,
2930 member_vnf_index=member_vnf_index,
2931 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002932 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002933 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002934 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002935 descriptor_config=descriptor_config,
2936 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002937 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002938 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002939 )
tierno59d22d22018-09-25 18:10:19 +02002940
k4.rahul74944982023-04-19 17:00:52 +05302941 # Check if each vnf has exporter for metric collection if so update prometheus job records
2942 if "exporters-endpoints" in vnfd.get("df")[0]:
2943 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2944 self.logger.debug("exporter config :{}".format(exporter_config))
2945 artifact_path = "{}/{}/{}".format(
2946 base_folder["folder"],
2947 base_folder["pkg-dir"],
2948 "exporter-endpoint",
2949 )
2950 ee_id = None
2951 ee_config_descriptor = exporter_config
2952 vnfr_id = db_vnfr["id"]
2953 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2954 logging_text,
2955 nsr_id,
2956 vnfr_id,
2957 vdu_id=None,
2958 vdu_index=None,
2959 user=None,
2960 pub_key=None,
2961 )
2962 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2963 self.logger.debug("Artifact_path:{}".format(artifact_path))
2964 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2965 vdu_id_for_prom = None
2966 vdu_index_for_prom = None
2967 for x in get_iterable(db_vnfr, "vdur"):
2968 vdu_id_for_prom = x.get("vdu-id-ref")
2969 vdu_index_for_prom = x.get("count-index")
2970 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2971 ee_id=ee_id,
2972 artifact_path=artifact_path,
2973 ee_config_descriptor=ee_config_descriptor,
2974 vnfr_id=vnfr_id,
2975 nsr_id=nsr_id,
2976 target_ip=rw_mgmt_ip,
2977 element_type="VDU",
2978 vdu_id=vdu_id_for_prom,
2979 vdu_index=vdu_index_for_prom,
2980 )
2981
2982 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2983 if prometheus_jobs:
2984 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2985 self.update_db_2(
2986 "nsrs",
2987 nsr_id,
2988 db_nsr_update,
2989 )
2990
2991 for job in prometheus_jobs:
2992 self.db.set_one(
2993 "prometheus_jobs",
2994 {"job_name": job["job_name"]},
2995 job,
2996 upsert=True,
2997 fail_on_empty=False,
2998 )
2999
tierno1b633412019-02-25 16:48:23 +00003000 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00003001 descriptor_config = nsd.get("ns-configuration")
3002 if descriptor_config and descriptor_config.get("juju"):
3003 vnfd_id = None
3004 db_vnfr = None
3005 member_vnf_index = None
3006 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01003007 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01003008 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00003009 vdu_index = 0
3010 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00003011
tiernod8323042019-08-09 11:32:23 +00003012 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01003013 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00003014 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003015 deploy_params.update(
3016 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
3017 )
tiernod8323042019-08-09 11:32:23 +00003018 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02003019 self._deploy_n2vc(
3020 logging_text=logging_text,
3021 db_nsr=db_nsr,
3022 db_vnfr=db_vnfr,
3023 nslcmop_id=nslcmop_id,
3024 nsr_id=nsr_id,
3025 nsi_id=nsi_id,
3026 vnfd_id=vnfd_id,
3027 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01003028 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02003029 member_vnf_index=member_vnf_index,
3030 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003031 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02003032 vdu_name=vdu_name,
3033 deploy_params=deploy_params,
3034 descriptor_config=descriptor_config,
3035 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00003036 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01003037 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02003038 )
tierno1b633412019-02-25 16:48:23 +00003039
tiernoe876f672020-02-13 14:34:48 +00003040 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00003041
garciadeblas5697b8b2021-03-24 09:17:02 +01003042 except (
3043 ROclient.ROClientException,
3044 DbException,
3045 LcmException,
3046 N2VCException,
3047 ) as e:
3048 self.logger.error(
3049 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3050 )
tierno59d22d22018-09-25 18:10:19 +02003051 exc = e
3052 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003053 self.logger.error(
3054 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3055 )
tierno59d22d22018-09-25 18:10:19 +02003056 exc = "Operation was cancelled"
3057 except Exception as e:
3058 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003059 self.logger.critical(
3060 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3061 exc_info=True,
3062 )
tierno59d22d22018-09-25 18:10:19 +02003063 finally:
3064 if exc:
tiernoe876f672020-02-13 14:34:48 +00003065 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003066 try:
tiernoe876f672020-02-13 14:34:48 +00003067 # wait for pending tasks
3068 if tasks_dict_info:
3069 stage[1] = "Waiting for instantiate pending tasks."
3070 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003071 error_list += await self._wait_for_tasks(
3072 logging_text,
3073 tasks_dict_info,
3074 timeout_ns_deploy,
3075 stage,
3076 nslcmop_id,
3077 nsr_id=nsr_id,
3078 )
tiernoe876f672020-02-13 14:34:48 +00003079 stage[1] = stage[2] = ""
3080 except asyncio.CancelledError:
3081 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003082 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3083 await self._wait_for_tasks(
3084 logging_text,
3085 tasks_dict_info,
3086 timeout_ns_deploy,
3087 stage,
3088 nslcmop_id,
3089 nsr_id=nsr_id,
3090 )
tiernoe876f672020-02-13 14:34:48 +00003091 except Exception as exc:
3092 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003093
tiernoe876f672020-02-13 14:34:48 +00003094 # update operation-status
3095 db_nsr_update["operational-status"] = "running"
3096 # let's begin with VCA 'configured' status (later we can change it)
3097 db_nsr_update["config-status"] = "configured"
3098 for task, task_name in tasks_dict_info.items():
3099 if not task.done() or task.cancelled() or task.exception():
3100 if task_name.startswith(self.task_name_deploy_vca):
3101 # A N2VC task is pending
3102 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003103 else:
tiernoe876f672020-02-13 14:34:48 +00003104 # RO or KDU task is pending
3105 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003106
tiernoe876f672020-02-13 14:34:48 +00003107 # update status at database
3108 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003109 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003110 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003111 error_description_nslcmop = "{} Detail: {}".format(
3112 stage[0], error_detail
3113 )
3114 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3115 nslcmop_id, stage[0]
3116 )
quilesj3655ae02019-12-12 16:08:35 +00003117
garciadeblas5697b8b2021-03-24 09:17:02 +01003118 db_nsr_update["detailed-status"] = (
3119 error_description_nsr + " Detail: " + error_detail
3120 )
tiernoe876f672020-02-13 14:34:48 +00003121 db_nslcmop_update["detailed-status"] = error_detail
3122 nslcmop_operation_state = "FAILED"
3123 ns_state = "BROKEN"
3124 else:
tiernoa2143262020-03-27 16:20:40 +00003125 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003126 error_description_nsr = error_description_nslcmop = None
3127 ns_state = "READY"
3128 db_nsr_update["detailed-status"] = "Done"
3129 db_nslcmop_update["detailed-status"] = "Done"
3130 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003131 # Gather auto-healing and auto-scaling alerts for each vnfr
3132 healing_alerts = []
3133 scaling_alerts = []
3134 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3135 vnfd = next(
3136 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3137 )
3138 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3139 for alert in healing_alerts:
3140 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3141 self.db.create("alerts", alert)
3142
3143 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3144 for alert in scaling_alerts:
3145 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3146 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003147
garciadeblas9148fa82023-05-30 12:51:14 +02003148 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3149 for alert in alarm_alerts:
3150 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3151 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003152 if db_nsr:
3153 self._write_ns_status(
3154 nsr_id=nsr_id,
3155 ns_state=ns_state,
3156 current_operation="IDLE",
3157 current_operation_id=None,
3158 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003159 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003160 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003161 )
tiernoa17d4f42020-04-28 09:59:23 +00003162 self._write_op_status(
3163 op_id=nslcmop_id,
3164 stage="",
3165 error_message=error_description_nslcmop,
3166 operation_state=nslcmop_operation_state,
3167 other_update=db_nslcmop_update,
3168 )
quilesj3655ae02019-12-12 16:08:35 +00003169
tierno59d22d22018-09-25 18:10:19 +02003170 if nslcmop_operation_state:
3171 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003172 await self.msg.aiowrite(
3173 "ns",
3174 "instantiated",
3175 {
3176 "nsr_id": nsr_id,
3177 "nslcmop_id": nslcmop_id,
3178 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003179 "startTime": db_nslcmop["startTime"],
3180 "links": db_nslcmop["links"],
3181 "operationParams": {
3182 "nsInstanceId": nsr_id,
3183 "nsdId": db_nsr["nsd-id"],
3184 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003185 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003186 )
tierno59d22d22018-09-25 18:10:19 +02003187 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003188 self.logger.error(
3189 logging_text + "kafka_write notification Exception {}".format(e)
3190 )
tierno59d22d22018-09-25 18:10:19 +02003191
3192 self.logger.debug(logging_text + "Exit")
3193 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3194
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003195 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003196 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003197 cached_vnfds[vnfd_id] = self.db.get_one(
3198 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3199 )
David Garciab4ebcd02021-10-28 02:00:43 +02003200 return cached_vnfds[vnfd_id]
3201
3202 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3203 if vnf_profile_id not in cached_vnfrs:
3204 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3205 "vnfrs",
3206 {
3207 "member-vnf-index-ref": vnf_profile_id,
3208 "nsr-id-ref": nsr_id,
3209 },
3210 )
3211 return cached_vnfrs[vnf_profile_id]
3212
3213 def _is_deployed_vca_in_relation(
3214 self, vca: DeployedVCA, relation: Relation
3215 ) -> bool:
3216 found = False
3217 for endpoint in (relation.provider, relation.requirer):
3218 if endpoint["kdu-resource-profile-id"]:
3219 continue
3220 found = (
3221 vca.vnf_profile_id == endpoint.vnf_profile_id
3222 and vca.vdu_profile_id == endpoint.vdu_profile_id
3223 and vca.execution_environment_ref == endpoint.execution_environment_ref
3224 )
3225 if found:
3226 break
3227 return found
3228
3229 def _update_ee_relation_data_with_implicit_data(
3230 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3231 ):
3232 ee_relation_data = safe_get_ee_relation(
3233 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3234 )
3235 ee_relation_level = EELevel.get_level(ee_relation_data)
3236 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3237 "execution-environment-ref"
3238 ]:
3239 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3240 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003241 project = nsd["_admin"]["projects_read"][0]
3242 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003243 entity_id = (
3244 vnfd_id
3245 if ee_relation_level == EELevel.VNF
3246 else ee_relation_data["vdu-profile-id"]
3247 )
3248 ee = get_juju_ee_ref(db_vnfd, entity_id)
3249 if not ee:
3250 raise Exception(
3251 f"not execution environments found for ee_relation {ee_relation_data}"
3252 )
3253 ee_relation_data["execution-environment-ref"] = ee["id"]
3254 return ee_relation_data
3255
3256 def _get_ns_relations(
3257 self,
3258 nsr_id: str,
3259 nsd: Dict[str, Any],
3260 vca: DeployedVCA,
3261 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003262 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003263 relations = []
3264 db_ns_relations = get_ns_configuration_relation_list(nsd)
3265 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003266 provider_dict = None
3267 requirer_dict = None
3268 if all(key in r for key in ("provider", "requirer")):
3269 provider_dict = r["provider"]
3270 requirer_dict = r["requirer"]
3271 elif "entities" in r:
3272 provider_id = r["entities"][0]["id"]
3273 provider_dict = {
3274 "nsr-id": nsr_id,
3275 "endpoint": r["entities"][0]["endpoint"],
3276 }
3277 if provider_id != nsd["id"]:
3278 provider_dict["vnf-profile-id"] = provider_id
3279 requirer_id = r["entities"][1]["id"]
3280 requirer_dict = {
3281 "nsr-id": nsr_id,
3282 "endpoint": r["entities"][1]["endpoint"],
3283 }
3284 if requirer_id != nsd["id"]:
3285 requirer_dict["vnf-profile-id"] = requirer_id
3286 else:
aticig15db6142022-01-24 12:51:26 +03003287 raise Exception(
3288 "provider/requirer or entities must be included in the relation."
3289 )
David Garciab4ebcd02021-10-28 02:00:43 +02003290 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003291 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003292 )
3293 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003294 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003295 )
3296 provider = EERelation(relation_provider)
3297 requirer = EERelation(relation_requirer)
3298 relation = Relation(r["name"], provider, requirer)
3299 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3300 if vca_in_relation:
3301 relations.append(relation)
3302 return relations
3303
3304 def _get_vnf_relations(
3305 self,
3306 nsr_id: str,
3307 nsd: Dict[str, Any],
3308 vca: DeployedVCA,
3309 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003310 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003311 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003312 if vca.target_element == "ns":
3313 self.logger.debug("VCA is a NS charm, not a VNF.")
3314 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003315 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3316 vnf_profile_id = vnf_profile["id"]
3317 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003318 project = nsd["_admin"]["projects_read"][0]
3319 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003320 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3321 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003322 provider_dict = None
3323 requirer_dict = None
3324 if all(key in r for key in ("provider", "requirer")):
3325 provider_dict = r["provider"]
3326 requirer_dict = r["requirer"]
3327 elif "entities" in r:
3328 provider_id = r["entities"][0]["id"]
3329 provider_dict = {
3330 "nsr-id": nsr_id,
3331 "vnf-profile-id": vnf_profile_id,
3332 "endpoint": r["entities"][0]["endpoint"],
3333 }
3334 if provider_id != vnfd_id:
3335 provider_dict["vdu-profile-id"] = provider_id
3336 requirer_id = r["entities"][1]["id"]
3337 requirer_dict = {
3338 "nsr-id": nsr_id,
3339 "vnf-profile-id": vnf_profile_id,
3340 "endpoint": r["entities"][1]["endpoint"],
3341 }
3342 if requirer_id != vnfd_id:
3343 requirer_dict["vdu-profile-id"] = requirer_id
3344 else:
aticig15db6142022-01-24 12:51:26 +03003345 raise Exception(
3346 "provider/requirer or entities must be included in the relation."
3347 )
David Garciab4ebcd02021-10-28 02:00:43 +02003348 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003349 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003350 )
3351 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003352 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003353 )
3354 provider = EERelation(relation_provider)
3355 requirer = EERelation(relation_requirer)
3356 relation = Relation(r["name"], provider, requirer)
3357 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3358 if vca_in_relation:
3359 relations.append(relation)
3360 return relations
3361
3362 def _get_kdu_resource_data(
3363 self,
3364 ee_relation: EERelation,
3365 db_nsr: Dict[str, Any],
3366 cached_vnfds: Dict[str, Any],
3367 ) -> DeployedK8sResource:
3368 nsd = get_nsd(db_nsr)
3369 vnf_profiles = get_vnf_profiles(nsd)
3370 vnfd_id = find_in_list(
3371 vnf_profiles,
3372 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3373 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003374 project = nsd["_admin"]["projects_read"][0]
3375 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003376 kdu_resource_profile = get_kdu_resource_profile(
3377 db_vnfd, ee_relation.kdu_resource_profile_id
3378 )
3379 kdu_name = kdu_resource_profile["kdu-name"]
3380 deployed_kdu, _ = get_deployed_kdu(
3381 db_nsr.get("_admin", ()).get("deployed", ()),
3382 kdu_name,
3383 ee_relation.vnf_profile_id,
3384 )
3385 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3386 return deployed_kdu
3387
3388 def _get_deployed_component(
3389 self,
3390 ee_relation: EERelation,
3391 db_nsr: Dict[str, Any],
3392 cached_vnfds: Dict[str, Any],
3393 ) -> DeployedComponent:
3394 nsr_id = db_nsr["_id"]
3395 deployed_component = None
3396 ee_level = EELevel.get_level(ee_relation)
3397 if ee_level == EELevel.NS:
3398 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3399 if vca:
3400 deployed_component = DeployedVCA(nsr_id, vca)
3401 elif ee_level == EELevel.VNF:
3402 vca = get_deployed_vca(
3403 db_nsr,
3404 {
3405 "vdu_id": None,
3406 "member-vnf-index": ee_relation.vnf_profile_id,
3407 "ee_descriptor_id": ee_relation.execution_environment_ref,
3408 },
3409 )
3410 if vca:
3411 deployed_component = DeployedVCA(nsr_id, vca)
3412 elif ee_level == EELevel.VDU:
3413 vca = get_deployed_vca(
3414 db_nsr,
3415 {
3416 "vdu_id": ee_relation.vdu_profile_id,
3417 "member-vnf-index": ee_relation.vnf_profile_id,
3418 "ee_descriptor_id": ee_relation.execution_environment_ref,
3419 },
3420 )
3421 if vca:
3422 deployed_component = DeployedVCA(nsr_id, vca)
3423 elif ee_level == EELevel.KDU:
3424 kdu_resource_data = self._get_kdu_resource_data(
3425 ee_relation, db_nsr, cached_vnfds
3426 )
3427 if kdu_resource_data:
3428 deployed_component = DeployedK8sResource(kdu_resource_data)
3429 return deployed_component
3430
3431 async def _add_relation(
3432 self,
3433 relation: Relation,
3434 vca_type: str,
3435 db_nsr: Dict[str, Any],
3436 cached_vnfds: Dict[str, Any],
3437 cached_vnfrs: Dict[str, Any],
3438 ) -> bool:
3439 deployed_provider = self._get_deployed_component(
3440 relation.provider, db_nsr, cached_vnfds
3441 )
3442 deployed_requirer = self._get_deployed_component(
3443 relation.requirer, db_nsr, cached_vnfds
3444 )
3445 if (
3446 deployed_provider
3447 and deployed_requirer
3448 and deployed_provider.config_sw_installed
3449 and deployed_requirer.config_sw_installed
3450 ):
3451 provider_db_vnfr = (
3452 self._get_vnfr(
3453 relation.provider.nsr_id,
3454 relation.provider.vnf_profile_id,
3455 cached_vnfrs,
3456 )
3457 if relation.provider.vnf_profile_id
3458 else None
3459 )
3460 requirer_db_vnfr = (
3461 self._get_vnfr(
3462 relation.requirer.nsr_id,
3463 relation.requirer.vnf_profile_id,
3464 cached_vnfrs,
3465 )
3466 if relation.requirer.vnf_profile_id
3467 else None
3468 )
3469 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3470 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3471 provider_relation_endpoint = RelationEndpoint(
3472 deployed_provider.ee_id,
3473 provider_vca_id,
3474 relation.provider.endpoint,
3475 )
3476 requirer_relation_endpoint = RelationEndpoint(
3477 deployed_requirer.ee_id,
3478 requirer_vca_id,
3479 relation.requirer.endpoint,
3480 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003481 try:
3482 await self.vca_map[vca_type].add_relation(
3483 provider=provider_relation_endpoint,
3484 requirer=requirer_relation_endpoint,
3485 )
3486 except N2VCException as exception:
3487 self.logger.error(exception)
3488 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003489 return True
3490 return False
3491
David Garciac1fe90a2021-03-31 19:12:02 +02003492 async def _add_vca_relations(
3493 self,
3494 logging_text,
3495 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003496 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003497 vca_index: int,
3498 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003499 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003500 # steps:
3501 # 1. find all relations for this VCA
3502 # 2. wait for other peers related
3503 # 3. add relations
3504
3505 try:
quilesj63f90042020-01-17 09:53:55 +00003506 # STEP 1: find all relations for this VCA
3507
3508 # read nsr record
3509 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003510 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003511
3512 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003513 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3514 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003515
David Garciab4ebcd02021-10-28 02:00:43 +02003516 cached_vnfds = {}
3517 cached_vnfrs = {}
3518 relations = []
3519 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3520 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003521
3522 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003523 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003524 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003525 return True
3526
David Garciab4ebcd02021-10-28 02:00:43 +02003527 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003528
3529 # add all relations
3530 start = time()
3531 while True:
3532 # check timeout
3533 now = time()
3534 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003535 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003536 return False
3537
David Garciab4ebcd02021-10-28 02:00:43 +02003538 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003539 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3540
David Garciab4ebcd02021-10-28 02:00:43 +02003541 # for each relation, find the VCA's related
3542 for relation in relations.copy():
3543 added = await self._add_relation(
3544 relation,
3545 vca_type,
3546 db_nsr,
3547 cached_vnfds,
3548 cached_vnfrs,
3549 )
3550 if added:
3551 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003552
David Garciab4ebcd02021-10-28 02:00:43 +02003553 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003554 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003555 break
David Garciab4ebcd02021-10-28 02:00:43 +02003556 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003557
3558 return True
3559
3560 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003561 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003562 return False
3563
garciadeblas5697b8b2021-03-24 09:17:02 +01003564 async def _install_kdu(
3565 self,
3566 nsr_id: str,
3567 nsr_db_path: str,
3568 vnfr_data: dict,
3569 kdu_index: int,
3570 kdud: dict,
3571 vnfd: dict,
3572 k8s_instance_info: dict,
3573 k8params: dict = None,
3574 timeout: int = 600,
3575 vca_id: str = None,
3576 ):
tiernob9018152020-04-16 14:18:24 +00003577 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003578 k8sclustertype = k8s_instance_info["k8scluster-type"]
3579 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003580 db_dict_install = {
3581 "collection": "nsrs",
3582 "filter": {"_id": nsr_id},
3583 "path": nsr_db_path,
3584 }
lloretgalleg7c121132020-07-08 07:53:22 +00003585
romeromonser4554a702021-05-28 12:00:08 +02003586 if k8s_instance_info.get("kdu-deployment-name"):
3587 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3588 else:
3589 kdu_instance = self.k8scluster_map[
3590 k8sclustertype
3591 ].generate_kdu_instance_name(
3592 db_dict=db_dict_install,
3593 kdu_model=k8s_instance_info["kdu-model"],
3594 kdu_name=k8s_instance_info["kdu-name"],
3595 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003596
3597 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003598 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003599 item="nsrs",
3600 _id=nsr_id,
3601 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003602 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003603
3604 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3605 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3606 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3607 # namespace, this first verification could be removed, and the next step would be done for any kind
3608 # of KNF.
3609 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3610 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3611 if k8sclustertype in ("juju", "juju-bundle"):
3612 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3613 # that the user passed a namespace which he wants its KDU to be deployed in)
3614 if (
3615 self.db.count(
3616 table="nsrs",
3617 q_filter={
3618 "_id": nsr_id,
3619 "_admin.projects_write": k8s_instance_info["namespace"],
3620 "_admin.projects_read": k8s_instance_info["namespace"],
3621 },
3622 )
3623 > 0
3624 ):
3625 self.logger.debug(
3626 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3627 )
3628 self.update_db_2(
3629 item="nsrs",
3630 _id=nsr_id,
3631 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3632 )
3633 k8s_instance_info["namespace"] = kdu_instance
3634
David Garciad64e2742021-02-25 20:19:18 +01003635 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003636 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3637 kdu_model=k8s_instance_info["kdu-model"],
3638 atomic=True,
3639 params=k8params,
3640 db_dict=db_dict_install,
3641 timeout=timeout,
3642 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003643 namespace=k8s_instance_info["namespace"],
3644 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003645 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003646 )
lloretgalleg7c121132020-07-08 07:53:22 +00003647
3648 # Obtain services to obtain management service ip
3649 services = await self.k8scluster_map[k8sclustertype].get_services(
3650 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3651 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003652 namespace=k8s_instance_info["namespace"],
3653 )
lloretgalleg7c121132020-07-08 07:53:22 +00003654
3655 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003656 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003657 kdu_config = get_configuration(vnfd, kdud["name"])
3658 if kdu_config:
3659 target_ee_list = kdu_config.get("execution-environment-list", [])
3660 else:
3661 target_ee_list = []
3662
lloretgalleg7c121132020-07-08 07:53:22 +00003663 if services:
tierno7ecbc342020-09-21 14:05:39 +00003664 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003665 mgmt_services = [
3666 service
3667 for service in kdud.get("service", [])
3668 if service.get("mgmt-service")
3669 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003670 for mgmt_service in mgmt_services:
3671 for service in services:
3672 if service["name"].startswith(mgmt_service["name"]):
3673 # Mgmt service found, Obtain service ip
3674 ip = service.get("external_ip", service.get("cluster_ip"))
3675 if isinstance(ip, list) and len(ip) == 1:
3676 ip = ip[0]
3677
garciadeblas5697b8b2021-03-24 09:17:02 +01003678 vnfr_update_dict[
3679 "kdur.{}.ip-address".format(kdu_index)
3680 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003681
3682 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003683 service_external_cp = mgmt_service.get(
3684 "external-connection-point-ref"
3685 )
lloretgalleg7c121132020-07-08 07:53:22 +00003686 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003687 if (
3688 deep_get(vnfd, ("mgmt-interface", "cp"))
3689 == service_external_cp
3690 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003691 vnfr_update_dict["ip-address"] = ip
3692
bravof6ec62b72021-02-25 17:20:35 -03003693 if find_in_list(
3694 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003695 lambda ee: ee.get(
3696 "external-connection-point-ref", ""
3697 )
3698 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003699 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003700 vnfr_update_dict[
3701 "kdur.{}.ip-address".format(kdu_index)
3702 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003703 break
3704 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003705 self.logger.warn(
3706 "Mgmt service name: {} not found".format(
3707 mgmt_service["name"]
3708 )
3709 )
lloretgalleg7c121132020-07-08 07:53:22 +00003710
tierno7ecbc342020-09-21 14:05:39 +00003711 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3712 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003713
bravof9a256db2021-02-22 18:02:07 -03003714 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003715 if (
3716 kdu_config
3717 and kdu_config.get("initial-config-primitive")
3718 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
jegan99448902024-12-06 07:19:34 +00003719 and get_helm_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
garciadeblas5697b8b2021-03-24 09:17:02 +01003720 ):
3721 initial_config_primitive_list = kdu_config.get(
3722 "initial-config-primitive"
3723 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003724 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3725
3726 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003727 primitive_params_ = self._map_primitive_params(
3728 initial_config_primitive, {}, {}
3729 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003730
3731 await asyncio.wait_for(
3732 self.k8scluster_map[k8sclustertype].exec_primitive(
3733 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3734 kdu_instance=kdu_instance,
3735 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003736 params=primitive_params_,
3737 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003738 vca_id=vca_id,
3739 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003740 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003741 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003742
tiernob9018152020-04-16 14:18:24 +00003743 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003744 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003745 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003746 self.update_db_2(
3747 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3748 )
3749 self.update_db_2(
3750 "vnfrs",
3751 vnfr_data.get("_id"),
3752 {"kdur.{}.status".format(kdu_index): "ERROR"},
3753 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003754 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003755 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003756 self.logger.warning(
3757 f"An exception occurred while updating DB: {str(error)}"
3758 )
lloretgalleg7c121132020-07-08 07:53:22 +00003759 # reraise original error
3760 raise
3761
3762 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003763
garciadeblas5697b8b2021-03-24 09:17:02 +01003764 async def deploy_kdus(
3765 self,
3766 logging_text,
3767 nsr_id,
3768 nslcmop_id,
3769 db_vnfrs,
3770 db_vnfds,
3771 task_instantiation_info,
3772 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003773 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003774
garciadeblas5697b8b2021-03-24 09:17:02 +01003775 k8scluster_id_2_uuic = {
3776 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003777 "juju-bundle": {},
3778 }
tierno626e0152019-11-29 14:16:16 +00003779
tierno16f4a4e2020-07-20 09:05:51 +00003780 async def _get_cluster_id(cluster_id, cluster_type):
Anirudh Gupta77b50a02025-05-13 05:53:38 +00003781 # nonlocal k8scluster_id_2_uuic
tierno626e0152019-11-29 14:16:16 +00003782 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3783 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3784
tierno16f4a4e2020-07-20 09:05:51 +00003785 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003786 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3787 "k8scluster", cluster_id
3788 )
tierno16f4a4e2020-07-20 09:05:51 +00003789 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003790 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3791 task_name, cluster_id
3792 )
tierno16f4a4e2020-07-20 09:05:51 +00003793 self.logger.debug(logging_text + text)
3794 await asyncio.wait(task_dependency, timeout=3600)
3795
garciadeblas5697b8b2021-03-24 09:17:02 +01003796 db_k8scluster = self.db.get_one(
3797 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3798 )
tierno626e0152019-11-29 14:16:16 +00003799 if not db_k8scluster:
3800 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003801
tierno626e0152019-11-29 14:16:16 +00003802 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3803 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003804 if cluster_type == "helm-chart-v3":
3805 try:
3806 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003807 k8s_credentials = yaml.safe_dump(
3808 db_k8scluster.get("credentials")
3809 )
3810 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3811 k8s_credentials, reuse_cluster_uuid=cluster_id
3812 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003813 db_k8scluster_update = {}
3814 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3815 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003816 db_k8scluster_update[
3817 "_admin.helm-chart-v3.created"
3818 ] = uninstall_sw
3819 db_k8scluster_update[
3820 "_admin.helm-chart-v3.operationalState"
3821 ] = "ENABLED"
3822 self.update_db_2(
3823 "k8sclusters", cluster_id, db_k8scluster_update
3824 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003825 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003826 self.logger.error(
3827 logging_text
3828 + "error initializing helm-v3 cluster: {}".format(str(e))
3829 )
3830 raise LcmException(
3831 "K8s cluster '{}' has not been initialized for '{}'".format(
3832 cluster_id, cluster_type
3833 )
3834 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003835 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003836 raise LcmException(
3837 "K8s cluster '{}' has not been initialized for '{}'".format(
3838 cluster_id, cluster_type
3839 )
3840 )
tierno626e0152019-11-29 14:16:16 +00003841 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3842 return k8s_id
3843
3844 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003845 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003846 try:
tierno626e0152019-11-29 14:16:16 +00003847 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003848 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003849
tierno626e0152019-11-29 14:16:16 +00003850 index = 0
tiernoe876f672020-02-13 14:34:48 +00003851 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003852 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003853
tierno626e0152019-11-29 14:16:16 +00003854 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003855 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003856 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3857 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003858 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003859 vnfd_id = vnfr_data.get("vnfd-id")
3860 vnfd_with_id = find_in_list(
3861 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3862 )
3863 kdud = next(
3864 kdud
3865 for kdud in vnfd_with_id["kdu"]
3866 if kdud["name"] == kdur["kdu-name"]
3867 )
tiernode1584f2020-04-07 09:07:33 +00003868 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003869 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003870 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003871 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003872 # Default version: helm3, if helm-version is v2 assign v2
3873 k8sclustertype = "helm-chart-v3"
3874 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003875 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003876 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003877 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003878 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003879 raise LcmException(
3880 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3881 "juju-bundle. Maybe an old NBI version is running".format(
3882 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3883 )
3884 )
quilesjacde94f2020-01-23 10:07:08 +00003885 # check if kdumodel is a file and exists
3886 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003887 vnfd_with_id = find_in_list(
3888 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3889 )
3890 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003891 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003892 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003893 if storage["pkg-dir"]:
3894 filename = "{}/{}/{}s/{}".format(
3895 storage["folder"],
3896 storage["pkg-dir"],
3897 k8sclustertype,
3898 kdumodel,
3899 )
3900 else:
3901 filename = "{}/Scripts/{}s/{}".format(
3902 storage["folder"],
3903 k8sclustertype,
3904 kdumodel,
3905 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003906 if self.fs.file_exists(
3907 filename, mode="file"
3908 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003909 kdumodel = self.fs.path + filename
3910 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003911 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003912 except Exception as e: # it is not a file
3913 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003914
tiernoe876f672020-02-13 14:34:48 +00003915 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003916 step = "Synchronize repos for k8s cluster '{}'".format(
3917 k8s_cluster_id
3918 )
tierno16f4a4e2020-07-20 09:05:51 +00003919 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003920
lloretgalleg7c121132020-07-08 07:53:22 +00003921 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003922 if (
3923 k8sclustertype == "helm-chart"
3924 and cluster_uuid not in updated_cluster_list
3925 ) or (
3926 k8sclustertype == "helm-chart-v3"
3927 and cluster_uuid not in updated_v3_cluster_list
3928 ):
tiernoe876f672020-02-13 14:34:48 +00003929 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003930 self.k8scluster_map[k8sclustertype].synchronize_repos(
3931 cluster_uuid=cluster_uuid
3932 )
3933 )
tiernoe876f672020-02-13 14:34:48 +00003934 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003935 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003936 unset = {
3937 "_admin.helm_charts_added." + item: None
3938 for item in del_repo_list
3939 }
3940 updated = {
3941 "_admin.helm_charts_added." + item: name
3942 for item, name in added_repo_dict.items()
3943 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003944 updated_cluster_list.append(cluster_uuid)
3945 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003946 unset = {
3947 "_admin.helm_charts_v3_added." + item: None
3948 for item in del_repo_list
3949 }
3950 updated = {
3951 "_admin.helm_charts_v3_added." + item: name
3952 for item, name in added_repo_dict.items()
3953 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003954 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003955 self.logger.debug(
3956 logging_text + "repos synchronized on k8s cluster "
3957 "'{}' to_delete: {}, to_add: {}".format(
3958 k8s_cluster_id, del_repo_list, added_repo_dict
3959 )
3960 )
3961 self.db.set_one(
3962 "k8sclusters",
3963 {"_id": k8s_cluster_id},
3964 updated,
3965 unset=unset,
3966 )
lloretgallegedc5f332020-02-20 11:50:50 +01003967
lloretgalleg7c121132020-07-08 07:53:22 +00003968 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003969 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3970 vnfr_data["member-vnf-index-ref"],
3971 kdur["kdu-name"],
3972 k8s_cluster_id,
3973 )
3974 k8s_instance_info = {
3975 "kdu-instance": None,
3976 "k8scluster-uuid": cluster_uuid,
3977 "k8scluster-type": k8sclustertype,
3978 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3979 "kdu-name": kdur["kdu-name"],
3980 "kdu-model": kdumodel,
3981 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003982 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003983 }
tiernob9018152020-04-16 14:18:24 +00003984 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003985 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003986 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003987 vnfd_with_id = find_in_list(
3988 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3989 )
tiernoa2143262020-03-27 16:20:40 +00003990 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003991 self._install_kdu(
3992 nsr_id,
3993 db_path,
3994 vnfr_data,
3995 kdu_index,
3996 kdud,
3997 vnfd_with_id,
3998 k8s_instance_info,
3999 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02004000 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01004001 vca_id=vca_id,
4002 )
4003 )
4004 self.lcm_tasks.register(
4005 "ns",
4006 nsr_id,
4007 nslcmop_id,
4008 "instantiate_KDU-{}".format(index),
4009 task,
4010 )
4011 task_instantiation_info[task] = "Deploying KDU {}".format(
4012 kdur["kdu-name"]
4013 )
tiernoe876f672020-02-13 14:34:48 +00004014
tierno626e0152019-11-29 14:16:16 +00004015 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00004016
tiernoe876f672020-02-13 14:34:48 +00004017 except (LcmException, asyncio.CancelledError):
4018 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01004019 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00004020 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
4021 if isinstance(e, (N2VCException, DbException)):
4022 self.logger.error(logging_text + msg)
4023 else:
4024 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00004025 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01004026 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01004027 if db_nsr_update:
4028 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00004029
garciadeblas5697b8b2021-03-24 09:17:02 +01004030 def _deploy_n2vc(
4031 self,
4032 logging_text,
4033 db_nsr,
4034 db_vnfr,
4035 nslcmop_id,
4036 nsr_id,
4037 nsi_id,
4038 vnfd_id,
4039 vdu_id,
4040 kdu_name,
4041 member_vnf_index,
4042 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004043 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004044 vdu_name,
4045 deploy_params,
4046 descriptor_config,
4047 base_folder,
4048 task_instantiation_info,
4049 stage,
4050 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004051 # launch instantiate_N2VC in a asyncio task and register task object
4052 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4053 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004054 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004055
garciadeblas5697b8b2021-03-24 09:17:02 +01004056 self.logger.debug(
4057 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4058 )
aticig9bc63ac2022-07-27 09:32:06 +03004059
4060 charm_name = ""
4061 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004062 if "execution-environment-list" in descriptor_config:
4063 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004064 elif "juju" in descriptor_config:
4065 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004066 if "execution-environment-list" not in descriptor_config:
4067 # charm name is only required for ns charms
4068 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004069 else: # other types as script are not supported
4070 ee_list = []
4071
4072 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004073 self.logger.debug(
4074 logging_text
4075 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4076 ee_item.get("juju"), ee_item.get("helm-chart")
4077 )
4078 )
tiernoa278b842020-07-08 15:33:55 +00004079 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05004080 vca_name, charm_name, vca_type = self.get_vca_info(
4081 ee_item, db_nsr, get_charm_name
4082 )
4083 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004084 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004085 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004086 )
quilesj7e13aeb2019-10-08 13:34:55 +02004087 continue
quilesj3655ae02019-12-12 16:08:35 +00004088
tierno588547c2020-07-01 15:30:20 +00004089 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004090 for vca_index, vca_deployed in enumerate(
4091 db_nsr["_admin"]["deployed"]["VCA"]
4092 ):
tierno588547c2020-07-01 15:30:20 +00004093 if not vca_deployed:
4094 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004095 if (
4096 vca_deployed.get("member-vnf-index") == member_vnf_index
4097 and vca_deployed.get("vdu_id") == vdu_id
4098 and vca_deployed.get("kdu_name") == kdu_name
4099 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4100 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4101 ):
tierno588547c2020-07-01 15:30:20 +00004102 break
4103 else:
4104 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004105 target = (
4106 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4107 )
tiernoa278b842020-07-08 15:33:55 +00004108 if vdu_id:
4109 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4110 elif kdu_name:
4111 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004112 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004113 "target_element": target,
4114 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004115 "member-vnf-index": member_vnf_index,
4116 "vdu_id": vdu_id,
4117 "kdu_name": kdu_name,
4118 "vdu_count_index": vdu_index,
4119 "operational-status": "init", # TODO revise
4120 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004121 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004122 "vnfd_id": vnfd_id,
4123 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004124 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004125 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004126 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004127 }
4128 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004129
tierno588547c2020-07-01 15:30:20 +00004130 # create VCA and configurationStatus in db
4131 db_dict = {
4132 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004133 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004134 }
4135 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004136
tierno588547c2020-07-01 15:30:20 +00004137 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4138
bravof922c4172020-11-24 21:21:43 -03004139 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4140 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4141 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4142
tierno588547c2020-07-01 15:30:20 +00004143 # Launch task
4144 task_n2vc = asyncio.ensure_future(
4145 self.instantiate_N2VC(
4146 logging_text=logging_text,
4147 vca_index=vca_index,
4148 nsi_id=nsi_id,
4149 db_nsr=db_nsr,
4150 db_vnfr=db_vnfr,
4151 vdu_id=vdu_id,
4152 kdu_name=kdu_name,
4153 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004154 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004155 deploy_params=deploy_params,
4156 config_descriptor=descriptor_config,
4157 base_folder=base_folder,
4158 nslcmop_id=nslcmop_id,
4159 stage=stage,
4160 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004161 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004162 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004163 )
quilesj7e13aeb2019-10-08 13:34:55 +02004164 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004165 self.lcm_tasks.register(
4166 "ns",
4167 nsr_id,
4168 nslcmop_id,
4169 "instantiate_N2VC-{}".format(vca_index),
4170 task_n2vc,
4171 )
4172 task_instantiation_info[
4173 task_n2vc
4174 ] = self.task_name_deploy_vca + " {}.{}".format(
4175 member_vnf_index or "", vdu_id or ""
4176 )
tiernobaa51102018-12-14 13:16:18 +00004177
calvinosanch9f9c6f22019-11-04 13:37:39 +01004178 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004179 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004180 for key, value in params.items():
4181 if str(value).startswith("!!yaml "):
4182 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004183 return params
4184
kuuse8b998e42019-07-30 15:22:16 +02004185 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004186 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004187 primitive_params = {}
4188 params = {
4189 "member_vnf_index": vnf_index,
4190 "primitive": primitive,
4191 "primitive_params": primitive_params,
4192 }
4193 desc_params = {}
4194 return self._map_primitive_params(seq, params, desc_params)
4195
kuuseac3a8882019-10-03 10:48:06 +02004196 # sub-operations
4197
tierno51183952020-04-03 15:48:18 +00004198 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004199 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4200 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004201 # b. Skip sub-operation
4202 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4203 return self.SUBOPERATION_STATUS_SKIP
4204 else:
tierno7c4e24c2020-05-13 08:41:35 +00004205 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004206 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004207 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004208 operationState = "PROCESSING"
4209 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004210 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004211 db_nslcmop, op_index, operationState, detailed_status
4212 )
kuuseac3a8882019-10-03 10:48:06 +02004213 # Return the sub-operation index
4214 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4215 # with arguments extracted from the sub-operation
4216 return op_index
4217
4218 # Find a sub-operation where all keys in a matching dictionary must match
4219 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4220 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004221 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004222 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004223 for i, op in enumerate(op_list):
4224 if all(op.get(k) == match[k] for k in match):
4225 return i
4226 return self.SUBOPERATION_STATUS_NOT_FOUND
4227
4228 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004229 def _update_suboperation_status(
4230 self, db_nslcmop, op_index, operationState, detailed_status
4231 ):
kuuseac3a8882019-10-03 10:48:06 +02004232 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004233 q_filter = {"_id": db_nslcmop["_id"]}
4234 update_dict = {
4235 "_admin.operations.{}.operationState".format(op_index): operationState,
4236 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4237 }
4238 self.db.set_one(
4239 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4240 )
kuuseac3a8882019-10-03 10:48:06 +02004241
4242 # Add sub-operation, return the index of the added sub-operation
4243 # Optionally, set operationState, detailed-status, and operationType
4244 # Status and type are currently set for 'scale' sub-operations:
4245 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4246 # 'detailed-status' : status message
4247 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4248 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004249 def _add_suboperation(
4250 self,
4251 db_nslcmop,
4252 vnf_index,
4253 vdu_id,
4254 vdu_count_index,
4255 vdu_name,
4256 primitive,
4257 mapped_primitive_params,
4258 operationState=None,
4259 detailed_status=None,
4260 operationType=None,
4261 RO_nsr_id=None,
4262 RO_scaling_info=None,
4263 ):
tiernoe876f672020-02-13 14:34:48 +00004264 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004265 return self.SUBOPERATION_STATUS_NOT_FOUND
4266 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004267 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4268 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004269 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004270 new_op = {
4271 "member_vnf_index": vnf_index,
4272 "vdu_id": vdu_id,
4273 "vdu_count_index": vdu_count_index,
4274 "primitive": primitive,
4275 "primitive_params": mapped_primitive_params,
4276 }
kuuseac3a8882019-10-03 10:48:06 +02004277 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004278 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004279 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004280 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004281 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004282 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004283 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004284 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004285 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004286 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004287 if not op_list:
4288 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004289 db_nslcmop_admin.update({"operations": [new_op]})
4290 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004291 else:
4292 # Existing operations, append operation to list
4293 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004294
garciadeblas5697b8b2021-03-24 09:17:02 +01004295 db_nslcmop_update = {"_admin.operations": op_list}
4296 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004297 op_index = len(op_list) - 1
4298 return op_index
4299
4300 # Helper methods for scale() sub-operations
4301
4302 # pre-scale/post-scale:
4303 # Check for 3 different cases:
4304 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4305 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004306 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004307 def _check_or_add_scale_suboperation(
4308 self,
4309 db_nslcmop,
4310 vnf_index,
4311 vnf_config_primitive,
4312 primitive_params,
4313 operationType,
4314 RO_nsr_id=None,
4315 RO_scaling_info=None,
4316 ):
kuuseac3a8882019-10-03 10:48:06 +02004317 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004318 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004319 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004320 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004321 "member_vnf_index": vnf_index,
4322 "RO_nsr_id": RO_nsr_id,
4323 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004324 }
4325 else:
4326 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004327 "member_vnf_index": vnf_index,
4328 "primitive": vnf_config_primitive,
4329 "primitive_params": primitive_params,
4330 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004331 }
4332 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004333 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004334 # a. New sub-operation
4335 # The sub-operation does not exist, add it.
4336 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4337 # The following parameters are set to None for all kind of scaling:
4338 vdu_id = None
4339 vdu_count_index = None
4340 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004341 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004342 vnf_config_primitive = None
4343 primitive_params = None
4344 else:
4345 RO_nsr_id = None
4346 RO_scaling_info = None
4347 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004348 operationState = "PROCESSING"
4349 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004350 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004351 self._add_suboperation(
4352 db_nslcmop,
4353 vnf_index,
4354 vdu_id,
4355 vdu_count_index,
4356 vdu_name,
4357 vnf_config_primitive,
4358 primitive_params,
4359 operationState,
4360 detailed_status,
4361 operationType,
4362 RO_nsr_id,
4363 RO_scaling_info,
4364 )
kuuseac3a8882019-10-03 10:48:06 +02004365 return self.SUBOPERATION_STATUS_NEW
4366 else:
4367 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4368 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004369 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004370
preethika.pdf7d8e02019-12-10 13:10:48 +00004371 # Function to return execution_environment id
4372
David Garciac1fe90a2021-03-31 19:12:02 +02004373 async def destroy_N2VC(
4374 self,
4375 logging_text,
4376 db_nslcmop,
4377 vca_deployed,
4378 config_descriptor,
4379 vca_index,
4380 destroy_ee=True,
4381 exec_primitives=True,
4382 scaling_in=False,
4383 vca_id: str = None,
4384 ):
tiernoe876f672020-02-13 14:34:48 +00004385 """
4386 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4387 :param logging_text:
4388 :param db_nslcmop:
4389 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4390 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4391 :param vca_index: index in the database _admin.deployed.VCA
4392 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004393 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4394 not executed properly
aktas13251562021-02-12 22:19:10 +03004395 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004396 :return: None or exception
4397 """
tiernoe876f672020-02-13 14:34:48 +00004398
tierno588547c2020-07-01 15:30:20 +00004399 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004400 logging_text
4401 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004402 vca_index, vca_deployed, config_descriptor, destroy_ee
4403 )
4404 )
4405
4406 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4407
4408 # execute terminate_primitives
4409 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004410 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004411 config_descriptor.get("terminate-config-primitive"),
4412 vca_deployed.get("ee_descriptor_id"),
4413 )
tierno588547c2020-07-01 15:30:20 +00004414 vdu_id = vca_deployed.get("vdu_id")
4415 vdu_count_index = vca_deployed.get("vdu_count_index")
4416 vdu_name = vca_deployed.get("vdu_name")
4417 vnf_index = vca_deployed.get("member-vnf-index")
4418 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004419 for seq in terminate_primitives:
4420 # For each sequence in list, get primitive and call _ns_execute_primitive()
4421 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004422 vnf_index, seq.get("name")
4423 )
tierno588547c2020-07-01 15:30:20 +00004424 self.logger.debug(logging_text + step)
4425 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004426 primitive = seq.get("name")
4427 mapped_primitive_params = self._get_terminate_primitive_params(
4428 seq, vnf_index
4429 )
tierno588547c2020-07-01 15:30:20 +00004430
4431 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004432 self._add_suboperation(
4433 db_nslcmop,
4434 vnf_index,
4435 vdu_id,
4436 vdu_count_index,
4437 vdu_name,
4438 primitive,
4439 mapped_primitive_params,
4440 )
tierno588547c2020-07-01 15:30:20 +00004441 # Sub-operations: Call _ns_execute_primitive() instead of action()
4442 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004443 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004444 vca_deployed["ee_id"],
4445 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004446 mapped_primitive_params,
4447 vca_type=vca_type,
4448 vca_id=vca_id,
4449 )
tierno588547c2020-07-01 15:30:20 +00004450 except LcmException:
4451 # this happens when VCA is not deployed. In this case it is not needed to terminate
4452 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004453 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004454 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004455 raise LcmException(
4456 "terminate_primitive {} for vnf_member_index={} fails with "
4457 "error {}".format(seq.get("name"), vnf_index, result_detail)
4458 )
tierno588547c2020-07-01 15:30:20 +00004459 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004460 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4461 vca_index
4462 )
4463 self.update_db_2(
4464 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4465 )
tiernoe876f672020-02-13 14:34:48 +00004466
bravof73bac502021-05-11 07:38:47 -04004467 # Delete Prometheus Jobs if any
4468 # This uses NSR_ID, so it will destroy any jobs under this index
4469 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004470
tiernoe876f672020-02-13 14:34:48 +00004471 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004472 await self.vca_map[vca_type].delete_execution_environment(
4473 vca_deployed["ee_id"],
4474 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004475 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004476 vca_id=vca_id,
4477 )
kuuse0ca67472019-05-13 15:59:27 +02004478
David Garciac1fe90a2021-03-31 19:12:02 +02004479 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004480 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004481 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004482 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004483 await self.n2vc.delete_namespace(
4484 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004485 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004486 vca_id=vca_id,
4487 )
tiernof59ad6c2020-04-08 12:50:52 +00004488 except N2VCNotFound: # already deleted. Skip
4489 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004490 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004491
tiernoe876f672020-02-13 14:34:48 +00004492 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004493 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004494 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004495 if not task_is_locked_by_me:
4496 return
4497
tierno59d22d22018-09-25 18:10:19 +02004498 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4499 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004500 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004501 db_nsr = None
4502 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004503 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004504 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004505 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004506 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004507 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004508 tasks_dict_info = {}
4509 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004510 stage = [
4511 "Stage 1/3: Preparing task.",
4512 "Waiting for previous operations to terminate.",
4513 "",
4514 ]
tiernoe876f672020-02-13 14:34:48 +00004515 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004516 try:
kuused124bfe2019-06-18 12:09:24 +02004517 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004518 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004519
tiernoe876f672020-02-13 14:34:48 +00004520 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4521 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4522 operation_params = db_nslcmop.get("operationParams") or {}
4523 if operation_params.get("timeout_ns_terminate"):
4524 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4525 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4526 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4527
4528 db_nsr_update["operational-status"] = "terminating"
4529 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004530 self._write_ns_status(
4531 nsr_id=nsr_id,
4532 ns_state="TERMINATING",
4533 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004534 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004535 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004536 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004537 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004538 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004539 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4540 return
tierno59d22d22018-09-25 18:10:19 +02004541
tiernoe876f672020-02-13 14:34:48 +00004542 stage[1] = "Getting vnf descriptors from db."
4543 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004544 db_vnfrs_dict = {
4545 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4546 }
tiernoe876f672020-02-13 14:34:48 +00004547 db_vnfds_from_id = {}
4548 db_vnfds_from_member_index = {}
4549 # Loop over VNFRs
4550 for vnfr in db_vnfrs_list:
4551 vnfd_id = vnfr["vnfd-id"]
4552 if vnfd_id not in db_vnfds_from_id:
4553 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4554 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004555 db_vnfds_from_member_index[
4556 vnfr["member-vnf-index-ref"]
4557 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004558
tiernoe876f672020-02-13 14:34:48 +00004559 # Destroy individual execution environments when there are terminating primitives.
4560 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004561 # TODO - check before calling _destroy_N2VC
4562 # if not operation_params.get("skip_terminate_primitives"):#
4563 # or not vca.get("needed_terminate"):
4564 stage[0] = "Stage 2/3 execute terminating primitives."
4565 self.logger.debug(logging_text + stage[0])
4566 stage[1] = "Looking execution environment that needs terminate."
4567 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004568
tierno588547c2020-07-01 15:30:20 +00004569 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004570 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004571 vca_member_vnf_index = vca.get("member-vnf-index")
4572 vca_id = self.get_vca_id(
4573 db_vnfrs_dict.get(vca_member_vnf_index)
4574 if vca_member_vnf_index
4575 else None,
4576 db_nsr,
4577 )
tierno588547c2020-07-01 15:30:20 +00004578 if not vca or not vca.get("ee_id"):
4579 continue
4580 if not vca.get("member-vnf-index"):
4581 # ns
4582 config_descriptor = db_nsr.get("ns-configuration")
4583 elif vca.get("vdu_id"):
4584 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004585 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004586 elif vca.get("kdu_name"):
4587 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004588 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004589 else:
bravofe5a31bc2021-02-17 19:09:12 -03004590 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004591 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004592 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004593 exec_terminate_primitives = not operation_params.get(
4594 "skip_terminate_primitives"
4595 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004596 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4597 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004598 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004599 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4600 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004601 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004602 self.destroy_N2VC(
4603 logging_text,
4604 db_nslcmop,
4605 vca,
4606 config_descriptor,
4607 vca_index,
4608 destroy_ee,
4609 exec_terminate_primitives,
4610 vca_id=vca_id,
4611 )
4612 )
tierno588547c2020-07-01 15:30:20 +00004613 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004614
tierno588547c2020-07-01 15:30:20 +00004615 # wait for pending tasks of terminate primitives
4616 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004617 self.logger.debug(
4618 logging_text
4619 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4620 )
4621 error_list = await self._wait_for_tasks(
4622 logging_text,
4623 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004624 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004625 stage,
4626 nslcmop_id,
4627 )
tierno86e33612020-09-16 14:13:06 +00004628 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004629 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004630 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004631
tiernoe876f672020-02-13 14:34:48 +00004632 # remove All execution environments at once
4633 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004634
tierno49676be2020-04-07 16:34:35 +00004635 if nsr_deployed.get("VCA"):
4636 stage[1] = "Deleting all execution environments."
4637 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004638 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4639 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004640 # Delete Namespace and Certificates
4641 await self.vca_map["helm-v3"].delete_tls_certificate(
4642 namespace=db_nslcmop["nsInstanceId"],
4643 certificate_name=self.EE_TLS_NAME,
4644 )
4645 await self.vca_map["helm-v3"].delete_namespace(
4646 namespace=db_nslcmop["nsInstanceId"],
4647 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004648 else:
4649 vca_id = self.get_vca_id({}, db_nsr)
4650 task_delete_ee = asyncio.ensure_future(
4651 asyncio.wait_for(
4652 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4653 timeout=self.timeout.charm_delete,
4654 )
4655 )
4656 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004657
tiernoe876f672020-02-13 14:34:48 +00004658 # Delete from k8scluster
4659 stage[1] = "Deleting KDUs."
4660 self.logger.debug(logging_text + stage[1])
4661 # print(nsr_deployed)
4662 for kdu in get_iterable(nsr_deployed, "K8s"):
4663 if not kdu or not kdu.get("kdu-instance"):
4664 continue
4665 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004666 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004667 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4668 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004669 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004670 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4671 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004672 kdu_instance=kdu_instance,
4673 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004674 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004675 )
4676 )
tiernoe876f672020-02-13 14:34:48 +00004677 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004678 self.logger.error(
4679 logging_text
4680 + "Unknown k8s deployment type {}".format(
4681 kdu.get("k8scluster-type")
4682 )
4683 )
tiernoe876f672020-02-13 14:34:48 +00004684 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004685 tasks_dict_info[
4686 task_delete_kdu_instance
4687 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004688
4689 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004690 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004691 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004692 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004693 self._terminate_ng_ro(
4694 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4695 )
4696 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004697 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004698
tiernoe876f672020-02-13 14:34:48 +00004699 # rest of staff will be done at finally
4700
garciadeblas5697b8b2021-03-24 09:17:02 +01004701 except (
4702 ROclient.ROClientException,
4703 DbException,
4704 LcmException,
4705 N2VCException,
4706 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004707 self.logger.error(logging_text + "Exit Exception {}".format(e))
4708 exc = e
4709 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004710 self.logger.error(
4711 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4712 )
tiernoe876f672020-02-13 14:34:48 +00004713 exc = "Operation was cancelled"
4714 except Exception as e:
4715 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004716 self.logger.critical(
4717 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4718 exc_info=True,
4719 )
tiernoe876f672020-02-13 14:34:48 +00004720 finally:
4721 if exc:
4722 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004723 try:
tiernoe876f672020-02-13 14:34:48 +00004724 # wait for pending tasks
4725 if tasks_dict_info:
4726 stage[1] = "Waiting for terminate pending tasks."
4727 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004728 error_list += await self._wait_for_tasks(
4729 logging_text,
4730 tasks_dict_info,
4731 timeout_ns_terminate,
4732 stage,
4733 nslcmop_id,
4734 )
tiernoe876f672020-02-13 14:34:48 +00004735 stage[1] = stage[2] = ""
4736 except asyncio.CancelledError:
4737 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004738 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4739 await self._wait_for_tasks(
4740 logging_text,
4741 tasks_dict_info,
4742 timeout_ns_terminate,
4743 stage,
4744 nslcmop_id,
4745 )
tiernoe876f672020-02-13 14:34:48 +00004746 except Exception as exc:
4747 error_list.append(str(exc))
4748 # update status at database
4749 if error_list:
4750 error_detail = "; ".join(error_list)
4751 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004752 error_description_nslcmop = "{} Detail: {}".format(
4753 stage[0], error_detail
4754 )
4755 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4756 nslcmop_id, stage[0]
4757 )
tierno59d22d22018-09-25 18:10:19 +02004758
tierno59d22d22018-09-25 18:10:19 +02004759 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004760 db_nsr_update["detailed-status"] = (
4761 error_description_nsr + " Detail: " + error_detail
4762 )
tiernoe876f672020-02-13 14:34:48 +00004763 db_nslcmop_update["detailed-status"] = error_detail
4764 nslcmop_operation_state = "FAILED"
4765 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004766 else:
tiernoa2143262020-03-27 16:20:40 +00004767 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004768 error_description_nsr = error_description_nslcmop = None
4769 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004770 db_nsr_update["operational-status"] = "terminated"
4771 db_nsr_update["detailed-status"] = "Done"
4772 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4773 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004774 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004775
tiernoe876f672020-02-13 14:34:48 +00004776 if db_nsr:
4777 self._write_ns_status(
4778 nsr_id=nsr_id,
4779 ns_state=ns_state,
4780 current_operation="IDLE",
4781 current_operation_id=None,
4782 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004783 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004784 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004785 )
tiernoa17d4f42020-04-28 09:59:23 +00004786 self._write_op_status(
4787 op_id=nslcmop_id,
4788 stage="",
4789 error_message=error_description_nslcmop,
4790 operation_state=nslcmop_operation_state,
4791 other_update=db_nslcmop_update,
4792 )
Rahul Kumar54671c52024-05-09 15:34:01 +05304793 if nslcmop_operation_state == "COMPLETED":
4794 self.db.del_list("prometheus_jobs", {"nsr_id": nsr_id})
lloretgalleg6d488782020-07-22 10:13:46 +00004795 if ns_state == "NOT_INSTANTIATED":
4796 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004797 self.db.set_list(
4798 "vnfrs",
4799 {"nsr-id-ref": nsr_id},
4800 {"_admin.nsState": "NOT_INSTANTIATED"},
4801 )
lloretgalleg6d488782020-07-22 10:13:46 +00004802 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004803 self.logger.warn(
4804 logging_text
4805 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4806 nsr_id, e
4807 )
4808 )
tiernoa17d4f42020-04-28 09:59:23 +00004809 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004810 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004811 if nslcmop_operation_state:
4812 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004813 await self.msg.aiowrite(
4814 "ns",
4815 "terminated",
4816 {
4817 "nsr_id": nsr_id,
4818 "nslcmop_id": nslcmop_id,
4819 "operationState": nslcmop_operation_state,
4820 "autoremove": autoremove,
4821 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004822 )
tierno59d22d22018-09-25 18:10:19 +02004823 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004824 self.logger.error(
4825 logging_text + "kafka_write notification Exception {}".format(e)
4826 )
aguilard1ae3c562023-02-16 17:24:35 +00004827 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4828 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004829
tierno59d22d22018-09-25 18:10:19 +02004830 self.logger.debug(logging_text + "Exit")
4831 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4832
garciadeblas5697b8b2021-03-24 09:17:02 +01004833 async def _wait_for_tasks(
4834 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4835 ):
tiernoe876f672020-02-13 14:34:48 +00004836 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004837 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004838 error_list = []
4839 pending_tasks = list(created_tasks_info.keys())
4840 num_tasks = len(pending_tasks)
4841 num_done = 0
4842 stage[1] = "{}/{}.".format(num_done, num_tasks)
4843 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004844 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004845 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004846 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004847 done, pending_tasks = await asyncio.wait(
4848 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4849 )
tiernoe876f672020-02-13 14:34:48 +00004850 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004851 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004852 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004853 new_error = created_tasks_info[task] + ": Timeout"
4854 error_detail_list.append(new_error)
4855 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004856 break
4857 for task in done:
4858 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004859 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004860 else:
4861 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004862 if exc:
4863 if isinstance(exc, asyncio.TimeoutError):
4864 exc = "Timeout"
4865 new_error = created_tasks_info[task] + ": {}".format(exc)
4866 error_list.append(created_tasks_info[task])
4867 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004868 if isinstance(
4869 exc,
4870 (
4871 str,
4872 DbException,
4873 N2VCException,
4874 ROclient.ROClientException,
4875 LcmException,
4876 K8sException,
4877 NgRoException,
4878 ),
4879 ):
tierno067e04a2020-03-31 12:53:13 +00004880 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004881 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004882 exc_traceback = "".join(
4883 traceback.format_exception(None, exc, exc.__traceback__)
4884 )
4885 self.logger.error(
4886 logging_text
4887 + created_tasks_info[task]
4888 + " "
4889 + exc_traceback
4890 )
tierno067e04a2020-03-31 12:53:13 +00004891 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004892 self.logger.debug(
4893 logging_text + created_tasks_info[task] + ": Done"
4894 )
tiernoe876f672020-02-13 14:34:48 +00004895 stage[1] = "{}/{}.".format(num_done, num_tasks)
4896 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004897 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004898 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004899 self.update_db_2(
4900 "nsrs",
4901 nsr_id,
4902 {
4903 "errorDescription": "Error at: " + ", ".join(error_list),
4904 "errorDetail": ". ".join(error_detail_list),
4905 },
4906 )
tiernoe876f672020-02-13 14:34:48 +00004907 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004908 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004909
Gabriel Cubab6049d32023-10-30 13:44:49 -05004910 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4911 for task, name in created_tasks_info.items():
4912 self.logger.debug(logging_text + "Cancelling task: " + name)
4913 task.cancel()
4914
tiernoda1ff8c2020-10-22 14:12:46 +00004915 @staticmethod
4916 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004917 """
4918 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4919 The default-value is used. If it is between < > it look for a value at instantiation_params
4920 :param primitive_desc: portion of VNFD/NSD that describes primitive
4921 :param params: Params provided by user
4922 :param instantiation_params: Instantiation params provided by user
4923 :return: a dictionary with the calculated params
4924 """
4925 calculated_params = {}
4926 for parameter in primitive_desc.get("parameter", ()):
4927 param_name = parameter["name"]
4928 if param_name in params:
4929 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004930 elif "default-value" in parameter or "value" in parameter:
4931 if "value" in parameter:
4932 calculated_params[param_name] = parameter["value"]
4933 else:
4934 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004935 if (
4936 isinstance(calculated_params[param_name], str)
4937 and calculated_params[param_name].startswith("<")
4938 and calculated_params[param_name].endswith(">")
4939 ):
tierno98ad6ea2019-05-30 17:16:28 +00004940 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004941 calculated_params[param_name] = instantiation_params[
4942 calculated_params[param_name][1:-1]
4943 ]
tiernoda964822019-01-14 15:53:47 +00004944 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004945 raise LcmException(
4946 "Parameter {} needed to execute primitive {} not provided".format(
4947 calculated_params[param_name], primitive_desc["name"]
4948 )
4949 )
tiernoda964822019-01-14 15:53:47 +00004950 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004951 raise LcmException(
4952 "Parameter {} needed to execute primitive {} not provided".format(
4953 param_name, primitive_desc["name"]
4954 )
4955 )
tierno59d22d22018-09-25 18:10:19 +02004956
tiernoda964822019-01-14 15:53:47 +00004957 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004958 calculated_params[param_name] = yaml.safe_dump(
4959 calculated_params[param_name], default_flow_style=True, width=256
4960 )
4961 elif isinstance(calculated_params[param_name], str) and calculated_params[
4962 param_name
4963 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004964 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004965 if parameter.get("data-type") == "INTEGER":
4966 try:
4967 calculated_params[param_name] = int(calculated_params[param_name])
4968 except ValueError: # error converting string to int
4969 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004970 "Parameter {} of primitive {} must be integer".format(
4971 param_name, primitive_desc["name"]
4972 )
4973 )
tiernofa40e692020-10-14 14:59:36 +00004974 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004975 calculated_params[param_name] = not (
4976 (str(calculated_params[param_name])).lower() == "false"
4977 )
tiernoc3f2a822019-11-05 13:45:04 +00004978
4979 # add always ns_config_info if primitive name is config
4980 if primitive_desc["name"] == "config":
4981 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004982 calculated_params["ns_config_info"] = instantiation_params[
4983 "ns_config_info"
4984 ]
tiernoda964822019-01-14 15:53:47 +00004985 return calculated_params
4986
garciadeblas5697b8b2021-03-24 09:17:02 +01004987 def _look_for_deployed_vca(
4988 self,
4989 deployed_vca,
4990 member_vnf_index,
4991 vdu_id,
4992 vdu_count_index,
4993 kdu_name=None,
4994 ee_descriptor_id=None,
4995 ):
tiernoe876f672020-02-13 14:34:48 +00004996 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4997 for vca in deployed_vca:
4998 if not vca:
4999 continue
5000 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
5001 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01005002 if (
5003 vdu_count_index is not None
5004 and vdu_count_index != vca["vdu_count_index"]
5005 ):
tiernoe876f672020-02-13 14:34:48 +00005006 continue
5007 if kdu_name and kdu_name != vca["kdu_name"]:
5008 continue
tiernoa278b842020-07-08 15:33:55 +00005009 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
5010 continue
tiernoe876f672020-02-13 14:34:48 +00005011 break
5012 else:
5013 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01005014 raise LcmException(
5015 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
5016 " is not deployed".format(
5017 member_vnf_index,
5018 vdu_id,
5019 vdu_count_index,
5020 kdu_name,
5021 ee_descriptor_id,
5022 )
5023 )
tiernoe876f672020-02-13 14:34:48 +00005024 # get ee_id
5025 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01005026 vca_type = vca.get(
5027 "type", "lxc_proxy_charm"
5028 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00005029 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005030 raise LcmException(
5031 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
5032 "execution environment".format(
5033 member_vnf_index, vdu_id, kdu_name, vdu_count_index
5034 )
5035 )
tierno588547c2020-07-01 15:30:20 +00005036 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00005037
David Garciac1fe90a2021-03-31 19:12:02 +02005038 async def _ns_execute_primitive(
5039 self,
5040 ee_id,
5041 primitive,
5042 primitive_params,
5043 retries=0,
5044 retries_interval=30,
5045 timeout=None,
5046 vca_type=None,
5047 db_dict=None,
5048 vca_id: str = None,
5049 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005050 try:
tierno98ad6ea2019-05-30 17:16:28 +00005051 if primitive == "config":
5052 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005053
tierno588547c2020-07-01 15:30:20 +00005054 vca_type = vca_type or "lxc_proxy_charm"
5055
quilesj7e13aeb2019-10-08 13:34:55 +02005056 while retries >= 0:
5057 try:
tierno067e04a2020-03-31 12:53:13 +00005058 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005059 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005060 ee_id=ee_id,
5061 primitive_name=primitive,
5062 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005063 progress_timeout=self.timeout.progress_primitive,
5064 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005065 db_dict=db_dict,
5066 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005067 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005068 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005069 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005070 )
quilesj7e13aeb2019-10-08 13:34:55 +02005071 # execution was OK
5072 break
tierno067e04a2020-03-31 12:53:13 +00005073 except asyncio.CancelledError:
5074 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005075 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005076 retries -= 1
5077 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005078 self.logger.debug(
5079 "Error executing action {} on {} -> {}".format(
5080 primitive, ee_id, e
5081 )
5082 )
quilesj7e13aeb2019-10-08 13:34:55 +02005083 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005084 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005085 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005086 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005087 e = N2VCException(
5088 message="Timed out waiting for action to complete"
5089 )
5090 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005091
garciadeblas5697b8b2021-03-24 09:17:02 +01005092 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005093
tierno067e04a2020-03-31 12:53:13 +00005094 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005095 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005096 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005097 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005098
ksaikiranr3fde2c72021-03-15 10:39:06 +05305099 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5100 """
5101 Updating the vca_status with latest juju information in nsrs record
5102 :param: nsr_id: Id of the nsr
5103 :param: nslcmop_id: Id of the nslcmop
5104 :return: None
5105 """
5106
5107 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5108 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005109 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005110 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005111 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5112 cluster_uuid, kdu_instance, cluster_type = (
5113 k8s["k8scluster-uuid"],
5114 k8s["kdu-instance"],
5115 k8s["k8scluster-type"],
5116 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005117 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005118 cluster_uuid=cluster_uuid,
5119 kdu_instance=kdu_instance,
5120 filter={"_id": nsr_id},
5121 vca_id=vca_id,
5122 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005123 )
3697083243632024-06-07 05:44:08 +00005124 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005125 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305126 table, filter = "nsrs", {"_id": nsr_id}
5127 path = "_admin.deployed.VCA.{}.".format(vca_index)
5128 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305129
5130 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5131 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5132
tierno59d22d22018-09-25 18:10:19 +02005133 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005134 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005135 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005136 if not task_is_locked_by_me:
5137 return
5138
tierno59d22d22018-09-25 18:10:19 +02005139 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5140 self.logger.debug(logging_text + "Enter")
5141 # get all needed from database
5142 db_nsr = None
5143 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005144 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005145 db_nslcmop_update = {}
5146 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005147 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005148 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005149 step = ""
tierno59d22d22018-09-25 18:10:19 +02005150 try:
kuused124bfe2019-06-18 12:09:24 +02005151 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005152 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005153 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005154
quilesj4cda56b2019-12-05 10:02:20 +00005155 self._write_ns_status(
5156 nsr_id=nsr_id,
5157 ns_state=None,
5158 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005159 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005160 )
5161
tierno59d22d22018-09-25 18:10:19 +02005162 step = "Getting information from database"
5163 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5164 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005165 if db_nslcmop["operationParams"].get("primitive_params"):
5166 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5167 db_nslcmop["operationParams"]["primitive_params"]
5168 )
tiernoda964822019-01-14 15:53:47 +00005169
tiernoe4f7e6c2018-11-27 14:55:30 +00005170 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005171 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005172 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005173 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005174 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005175 primitive = db_nslcmop["operationParams"]["primitive"]
5176 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005177 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005178 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005179 )
tierno59d22d22018-09-25 18:10:19 +02005180
tierno1b633412019-02-25 16:48:23 +00005181 if vnf_index:
5182 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005183 db_vnfr = self.db.get_one(
5184 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5185 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005186 if db_vnfr.get("kdur"):
5187 kdur_list = []
5188 for kdur in db_vnfr["kdur"]:
5189 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005190 kdur["additionalParams"] = json.loads(
5191 kdur["additionalParams"]
5192 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005193 kdur_list.append(kdur)
5194 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005195 step = "Getting vnfd from database"
5196 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005197
5198 # Sync filesystem before running a primitive
5199 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005200 else:
tierno067e04a2020-03-31 12:53:13 +00005201 step = "Getting nsd from database"
5202 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005203
David Garciac1fe90a2021-03-31 19:12:02 +02005204 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005205 # for backward compatibility
5206 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5207 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5208 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5209 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5210
tiernoda964822019-01-14 15:53:47 +00005211 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005212 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005213 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005214 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005215 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005216 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005217 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005218 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005219 else:
tiernoa278b842020-07-08 15:33:55 +00005220 descriptor_configuration = db_nsd.get("ns-configuration")
5221
garciadeblas5697b8b2021-03-24 09:17:02 +01005222 if descriptor_configuration and descriptor_configuration.get(
5223 "config-primitive"
5224 ):
tiernoa278b842020-07-08 15:33:55 +00005225 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005226 if config_primitive["name"] == primitive:
5227 config_primitive_desc = config_primitive
5228 break
tiernoda964822019-01-14 15:53:47 +00005229
garciadeblas6bed6b32020-07-20 11:05:42 +00005230 if not config_primitive_desc:
5231 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005232 raise LcmException(
5233 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5234 primitive
5235 )
5236 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005237 primitive_name = primitive
5238 ee_descriptor_id = None
5239 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005240 primitive_name = config_primitive_desc.get(
5241 "execution-environment-primitive", primitive
5242 )
5243 ee_descriptor_id = config_primitive_desc.get(
5244 "execution-environment-ref"
5245 )
tierno1b633412019-02-25 16:48:23 +00005246
tierno1b633412019-02-25 16:48:23 +00005247 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005248 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005249 vdur = next(
5250 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5251 )
bravof922c4172020-11-24 21:21:43 -03005252 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005253 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005254 kdur = next(
5255 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5256 )
bravof922c4172020-11-24 21:21:43 -03005257 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005258 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005259 desc_params = parse_yaml_strings(
5260 db_vnfr.get("additionalParamsForVnf")
5261 )
tierno1b633412019-02-25 16:48:23 +00005262 else:
bravof922c4172020-11-24 21:21:43 -03005263 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005264 if kdu_name and get_configuration(db_vnfd, kdu_name):
5265 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005266 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005267 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005268 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005269 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005270 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005271 kdu = find_in_list(
5272 nsr_deployed["K8s"],
5273 lambda kdu: kdu_name == kdu["kdu-name"]
5274 and kdu["member-vnf-index"] == vnf_index,
5275 )
5276 kdu_action = (
5277 True
5278 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005279 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005280 else False
5281 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005282
tiernoda964822019-01-14 15:53:47 +00005283 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005284 if kdu_name and (
5285 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5286 ):
tierno067e04a2020-03-31 12:53:13 +00005287 # TODO Check if we will need something at vnf level
5288 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005289 if (
5290 kdu_name == kdu["kdu-name"]
5291 and kdu["member-vnf-index"] == vnf_index
5292 ):
tierno067e04a2020-03-31 12:53:13 +00005293 break
5294 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005295 raise LcmException(
5296 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5297 )
quilesj7e13aeb2019-10-08 13:34:55 +02005298
tierno067e04a2020-03-31 12:53:13 +00005299 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005300 msg = "unknown k8scluster-type '{}'".format(
5301 kdu.get("k8scluster-type")
5302 )
tierno067e04a2020-03-31 12:53:13 +00005303 raise LcmException(msg)
5304
garciadeblas5697b8b2021-03-24 09:17:02 +01005305 db_dict = {
5306 "collection": "nsrs",
5307 "filter": {"_id": nsr_id},
5308 "path": "_admin.deployed.K8s.{}".format(index),
5309 }
5310 self.logger.debug(
5311 logging_text
5312 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5313 )
tiernoa278b842020-07-08 15:33:55 +00005314 step = "Executing kdu {}".format(primitive_name)
garciadeblas8eb84d52024-07-19 12:08:07 +02005315 if primitive_name == "upgrade" and primitive_params:
5316 if primitive_params.get("kdu_model"):
5317 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005318 else:
5319 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005320 if kdu_model.count("/") < 2: # helm chart is not embedded
5321 parts = kdu_model.split(sep=":")
5322 if len(parts) == 2:
5323 kdu_model = parts[0]
garciadeblas8eb84d52024-07-19 12:08:07 +02005324 if primitive_params.get("kdu_atomic_upgrade"):
5325 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005326 "kdu_atomic_upgrade"
5327 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005328 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005329 else:
5330 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005331 # Type of upgrade: reset, reuse, reset_then_reuse
5332 reset_values = False
5333 reuse_values = False
5334 reset_then_reuse_values = False
5335 # If no option is specified, default behaviour is reuse_values
5336 # Otherwise, options will be parsed and used
5337 if (
garciadeblas8eb84d52024-07-19 12:08:07 +02005338 ("kdu_reset_values" not in primitive_params)
5339 and ("kdu_reuse_values" not in primitive_params)
5340 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasb891d382024-02-08 14:11:51 +01005341 ):
5342 reuse_values = True
5343 else:
garciadeblas8eb84d52024-07-19 12:08:07 +02005344 if primitive_params.get("kdu_reset_values"):
5345 reset_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005346 "kdu_reset_values"
5347 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005348 if primitive_params.get("kdu_reuse_values"):
5349 reuse_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005350 "kdu_reuse_values"
5351 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005352 if primitive_params.get("kdu_reset_then_reuse_values"):
5353 reset_then_reuse_values = primitive_params.get(
garciadeblasb891d382024-02-08 14:11:51 +01005354 "kdu_reset_then_reuse_values"
5355 ).lower() in ("yes", "true", "1")
5356 # Two true options are not possible
5357 if (
5358 sum([reset_values, reuse_values, reset_then_reuse_values])
5359 >= 2
5360 ):
5361 raise LcmException(
5362 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5363 )
garciadeblas8eb84d52024-07-19 12:08:07 +02005364 # kdur and desc_params already set from before
5365 if reset_values:
5366 desc_params = primitive_params
5367 else:
5368 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005369 detailed_status = await asyncio.wait_for(
5370 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5371 cluster_uuid=kdu.get("k8scluster-uuid"),
5372 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005373 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005374 reset_values=reset_values,
5375 reuse_values=reuse_values,
5376 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005377 kdu_model=kdu_model,
5378 params=desc_params,
5379 db_dict=db_dict,
5380 timeout=timeout_ns_action,
5381 ),
5382 timeout=timeout_ns_action + 10,
5383 )
5384 self.logger.debug(
5385 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5386 )
tiernoa278b842020-07-08 15:33:55 +00005387 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005388 detailed_status = await asyncio.wait_for(
5389 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5390 cluster_uuid=kdu.get("k8scluster-uuid"),
5391 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005392 db_dict=db_dict,
5393 ),
5394 timeout=timeout_ns_action,
5395 )
tiernoa278b842020-07-08 15:33:55 +00005396 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005397 detailed_status = await asyncio.wait_for(
5398 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5399 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005400 kdu_instance=kdu.get("kdu-instance"),
5401 vca_id=vca_id,
5402 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005403 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005404 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005405 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005406 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5407 kdu["kdu-name"], nsr_id
5408 )
5409 params = self._map_primitive_params(
5410 config_primitive_desc, primitive_params, desc_params
5411 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005412
5413 detailed_status = await asyncio.wait_for(
5414 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5415 cluster_uuid=kdu.get("k8scluster-uuid"),
5416 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005417 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005418 params=params,
5419 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005420 timeout=timeout_ns_action,
5421 vca_id=vca_id,
5422 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005423 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005424 )
tierno067e04a2020-03-31 12:53:13 +00005425
5426 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005427 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005428 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005429 detailed_status = ""
5430 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005431 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005432 ee_id, vca_type = self._look_for_deployed_vca(
5433 nsr_deployed["VCA"],
5434 member_vnf_index=vnf_index,
5435 vdu_id=vdu_id,
5436 vdu_count_index=vdu_count_index,
5437 ee_descriptor_id=ee_descriptor_id,
5438 )
5439 for vca_index, vca_deployed in enumerate(
5440 db_nsr["_admin"]["deployed"]["VCA"]
5441 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305442 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005443 db_dict = {
5444 "collection": "nsrs",
5445 "filter": {"_id": nsr_id},
5446 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5447 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305448 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005449 (
5450 nslcmop_operation_state,
5451 detailed_status,
5452 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005453 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005454 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005455 primitive_params=self._map_primitive_params(
5456 config_primitive_desc, primitive_params, desc_params
5457 ),
tierno588547c2020-07-01 15:30:20 +00005458 timeout=timeout_ns_action,
5459 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005460 db_dict=db_dict,
5461 vca_id=vca_id,
5462 )
tierno067e04a2020-03-31 12:53:13 +00005463
5464 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005465 error_description_nslcmop = (
5466 detailed_status if nslcmop_operation_state == "FAILED" else ""
5467 )
5468 self.logger.debug(
5469 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005470 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005471 nslcmop_operation_state, detailed_status
5472 )
5473 )
tierno59d22d22018-09-25 18:10:19 +02005474 return # database update is called inside finally
5475
tiernof59ad6c2020-04-08 12:50:52 +00005476 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005477 self.logger.error(logging_text + "Exit Exception {}".format(e))
5478 exc = e
5479 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005480 self.logger.error(
5481 logging_text + "Cancelled Exception while '{}'".format(step)
5482 )
tierno59d22d22018-09-25 18:10:19 +02005483 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005484 except asyncio.TimeoutError:
5485 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5486 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005487 except Exception as e:
5488 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005489 self.logger.critical(
5490 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5491 exc_info=True,
5492 )
tierno59d22d22018-09-25 18:10:19 +02005493 finally:
tierno067e04a2020-03-31 12:53:13 +00005494 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005495 db_nslcmop_update[
5496 "detailed-status"
5497 ] = (
5498 detailed_status
5499 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005500 nslcmop_operation_state = "FAILED"
5501 if db_nsr:
5502 self._write_ns_status(
5503 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005504 ns_state=db_nsr[
5505 "nsState"
5506 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005507 current_operation="IDLE",
5508 current_operation_id=None,
5509 # error_description=error_description_nsr,
5510 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005511 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005512 )
5513
garciadeblas5697b8b2021-03-24 09:17:02 +01005514 self._write_op_status(
5515 op_id=nslcmop_id,
5516 stage="",
5517 error_message=error_description_nslcmop,
5518 operation_state=nslcmop_operation_state,
5519 other_update=db_nslcmop_update,
5520 )
tierno067e04a2020-03-31 12:53:13 +00005521
tierno59d22d22018-09-25 18:10:19 +02005522 if nslcmop_operation_state:
5523 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005524 await self.msg.aiowrite(
5525 "ns",
5526 "actioned",
5527 {
5528 "nsr_id": nsr_id,
5529 "nslcmop_id": nslcmop_id,
5530 "operationState": nslcmop_operation_state,
5531 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005532 )
tierno59d22d22018-09-25 18:10:19 +02005533 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005534 self.logger.error(
5535 logging_text + "kafka_write notification Exception {}".format(e)
5536 )
tierno59d22d22018-09-25 18:10:19 +02005537 self.logger.debug(logging_text + "Exit")
5538 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005539 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005540
elumalaica7ece02022-04-12 12:47:32 +05305541 async def terminate_vdus(
5542 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5543 ):
5544 """This method terminates VDUs
5545
5546 Args:
5547 db_vnfr: VNF instance record
5548 member_vnf_index: VNF index to identify the VDUs to be removed
5549 db_nsr: NS instance record
5550 update_db_nslcmops: Nslcmop update record
5551 """
5552 vca_scaling_info = []
5553 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5554 scaling_info["scaling_direction"] = "IN"
5555 scaling_info["vdu-delete"] = {}
5556 scaling_info["kdu-delete"] = {}
5557 db_vdur = db_vnfr.get("vdur")
5558 vdur_list = copy(db_vdur)
5559 count_index = 0
5560 for index, vdu in enumerate(vdur_list):
5561 vca_scaling_info.append(
5562 {
5563 "osm_vdu_id": vdu["vdu-id-ref"],
5564 "member-vnf-index": member_vnf_index,
5565 "type": "delete",
5566 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005567 }
5568 )
elumalaica7ece02022-04-12 12:47:32 +05305569 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5570 scaling_info["vdu"].append(
5571 {
5572 "name": vdu.get("name") or vdu.get("vdu-name"),
5573 "vdu_id": vdu["vdu-id-ref"],
5574 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005575 }
5576 )
elumalaica7ece02022-04-12 12:47:32 +05305577 for interface in vdu["interfaces"]:
5578 scaling_info["vdu"][index]["interface"].append(
5579 {
5580 "name": interface["name"],
5581 "ip_address": interface["ip-address"],
5582 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005583 }
5584 )
elumalaica7ece02022-04-12 12:47:32 +05305585 self.logger.info("NS update scaling info{}".format(scaling_info))
5586 stage[2] = "Terminating VDUs"
5587 if scaling_info.get("vdu-delete"):
5588 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005589 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305590 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005591 logging_text,
5592 db_nsr,
5593 update_db_nslcmops,
5594 db_vnfr,
5595 scaling_info,
5596 stage,
elumalaica7ece02022-04-12 12:47:32 +05305597 )
5598
preethika.p28b0bf82022-09-23 07:36:28 +00005599 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305600 """This method is to Remove VNF instances from NS.
5601
5602 Args:
5603 nsr_id: NS instance id
5604 nslcmop_id: nslcmop id of update
5605 vnf_instance_id: id of the VNF instance to be removed
5606
5607 Returns:
5608 result: (str, str) COMPLETED/FAILED, details
5609 """
5610 try:
5611 db_nsr_update = {}
5612 logging_text = "Task ns={} update ".format(nsr_id)
5613 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5614 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5615 if check_vnfr_count > 1:
5616 stage = ["", "", ""]
5617 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005618 self.logger.debug(
5619 step + " after having waited for previous tasks to be completed"
5620 )
elumalaica7ece02022-04-12 12:47:32 +05305621 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5622 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5623 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5624 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5625 """ db_vnfr = self.db.get_one(
5626 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5627
5628 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005629 await self.terminate_vdus(
5630 db_vnfr,
5631 member_vnf_index,
5632 db_nsr,
5633 update_db_nslcmops,
5634 stage,
5635 logging_text,
5636 )
elumalaica7ece02022-04-12 12:47:32 +05305637
5638 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5639 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005640 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5641 "constituent-vnfr-ref"
5642 )
elumalaica7ece02022-04-12 12:47:32 +05305643 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5644 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5645 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5646 return "COMPLETED", "Done"
5647 else:
5648 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005649 raise LcmException(
5650 "{} Cannot terminate the last VNF in this NS.".format(
5651 vnf_instance_id
5652 )
5653 )
elumalaica7ece02022-04-12 12:47:32 +05305654 except (LcmException, asyncio.CancelledError):
5655 raise
5656 except Exception as e:
5657 self.logger.debug("Error removing VNF {}".format(e))
5658 return "FAILED", "Error removing VNF {}".format(e)
5659
elumalaib9e357c2022-04-27 09:58:38 +05305660 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005661 self,
5662 nsr_id,
5663 nslcmop_id,
5664 db_vnfd,
5665 db_vnfr,
5666 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305667 ):
5668 """This method updates and redeploys VNF instances
5669
5670 Args:
5671 nsr_id: NS instance id
5672 nslcmop_id: nslcmop id
5673 db_vnfd: VNF descriptor
5674 db_vnfr: VNF instance record
5675 db_nsr: NS instance record
5676
5677 Returns:
5678 result: (str, str) COMPLETED/FAILED, details
5679 """
5680 try:
5681 count_index = 0
5682 stage = ["", "", ""]
5683 logging_text = "Task ns={} update ".format(nsr_id)
5684 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5685 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5686
5687 # Terminate old VNF resources
5688 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005689 await self.terminate_vdus(
5690 db_vnfr,
5691 member_vnf_index,
5692 db_nsr,
5693 update_db_nslcmops,
5694 stage,
5695 logging_text,
5696 )
elumalaib9e357c2022-04-27 09:58:38 +05305697
5698 # old_vnfd_id = db_vnfr["vnfd-id"]
5699 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5700 new_db_vnfd = db_vnfd
5701 # new_vnfd_ref = new_db_vnfd["id"]
5702 # new_vnfd_id = vnfd_id
5703
5704 # Create VDUR
5705 new_vnfr_cp = []
5706 for cp in new_db_vnfd.get("ext-cpd", ()):
5707 vnf_cp = {
5708 "name": cp.get("id"),
5709 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5710 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5711 "id": cp.get("id"),
5712 }
5713 new_vnfr_cp.append(vnf_cp)
5714 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5715 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5716 # new_vnfr_update = {"vnfd-ref": new_vnfd_ref, "vnfd-id": new_vnfd_id, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""}
preethika.p28b0bf82022-09-23 07:36:28 +00005717 new_vnfr_update = {
5718 "revision": latest_vnfd_revision,
5719 "connection-point": new_vnfr_cp,
5720 "vdur": new_vdur,
5721 "ip-address": "",
5722 }
elumalaib9e357c2022-04-27 09:58:38 +05305723 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5724 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005725 "vnfrs",
5726 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305727 )
5728
5729 # Instantiate new VNF resources
5730 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5731 vca_scaling_info = []
5732 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5733 scaling_info["scaling_direction"] = "OUT"
5734 scaling_info["vdu-create"] = {}
5735 scaling_info["kdu-create"] = {}
5736 vdud_instantiate_list = db_vnfd["vdu"]
5737 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005738 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305739 if cloud_init_text:
5740 additional_params = (
5741 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5742 or {}
5743 )
5744 cloud_init_list = []
5745 if cloud_init_text:
5746 # TODO Information of its own ip is not available because db_vnfr is not updated.
5747 additional_params["OSM"] = get_osm_params(
5748 updated_db_vnfr, vdud["id"], 1
5749 )
5750 cloud_init_list.append(
5751 self._parse_cloud_init(
5752 cloud_init_text,
5753 additional_params,
5754 db_vnfd["id"],
5755 vdud["id"],
5756 )
5757 )
5758 vca_scaling_info.append(
5759 {
5760 "osm_vdu_id": vdud["id"],
5761 "member-vnf-index": member_vnf_index,
5762 "type": "create",
5763 "vdu_index": count_index,
5764 }
5765 )
5766 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005767 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305768 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005769 "New Resources to be deployed: {}".format(scaling_info)
5770 )
elumalaib9e357c2022-04-27 09:58:38 +05305771 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005772 logging_text,
5773 db_nsr,
5774 update_db_nslcmops,
5775 updated_db_vnfr,
5776 scaling_info,
5777 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305778 )
5779 return "COMPLETED", "Done"
5780 except (LcmException, asyncio.CancelledError):
5781 raise
5782 except Exception as e:
5783 self.logger.debug("Error updating VNF {}".format(e))
5784 return "FAILED", "Error updating VNF {}".format(e)
5785
aticigdffa6212022-04-12 15:27:53 +03005786 async def _ns_charm_upgrade(
5787 self,
5788 ee_id,
5789 charm_id,
5790 charm_type,
5791 path,
5792 timeout: float = None,
5793 ) -> (str, str):
5794 """This method upgrade charms in VNF instances
5795
5796 Args:
5797 ee_id: Execution environment id
5798 path: Local path to the charm
5799 charm_id: charm-id
5800 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5801 timeout: (Float) Timeout for the ns update operation
5802
5803 Returns:
5804 result: (str, str) COMPLETED/FAILED, details
5805 """
5806 try:
5807 charm_type = charm_type or "lxc_proxy_charm"
5808 output = await self.vca_map[charm_type].upgrade_charm(
5809 ee_id=ee_id,
5810 path=path,
5811 charm_id=charm_id,
5812 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005813 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005814 )
5815
5816 if output:
5817 return "COMPLETED", output
5818
5819 except (LcmException, asyncio.CancelledError):
5820 raise
5821
5822 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005823 self.logger.debug("Error upgrading charm {}".format(path))
5824
5825 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5826
5827 async def update(self, nsr_id, nslcmop_id):
5828 """Update NS according to different update types
5829
5830 This method performs upgrade of VNF instances then updates the revision
5831 number in VNF record
5832
5833 Args:
5834 nsr_id: Network service will be updated
5835 nslcmop_id: ns lcm operation id
5836
5837 Returns:
5838 It may raise DbException, LcmException, N2VCException, K8sException
5839
5840 """
5841 # Try to lock HA task here
5842 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5843 if not task_is_locked_by_me:
5844 return
5845
5846 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5847 self.logger.debug(logging_text + "Enter")
5848
5849 # Set the required variables to be filled up later
5850 db_nsr = None
5851 db_nslcmop_update = {}
5852 vnfr_update = {}
5853 nslcmop_operation_state = None
5854 db_nsr_update = {}
5855 error_description_nslcmop = ""
5856 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305857 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005858 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005859 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005860
5861 try:
5862 # wait for any previous tasks in process
5863 step = "Waiting for previous operations to terminate"
5864 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5865 self._write_ns_status(
5866 nsr_id=nsr_id,
5867 ns_state=None,
5868 current_operation="UPDATING",
5869 current_operation_id=nslcmop_id,
5870 )
5871
5872 step = "Getting nslcmop from database"
5873 db_nslcmop = self.db.get_one(
5874 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5875 )
5876 update_type = db_nslcmop["operationParams"]["updateType"]
5877
5878 step = "Getting nsr from database"
5879 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5880 old_operational_status = db_nsr["operational-status"]
5881 db_nsr_update["operational-status"] = "updating"
5882 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5883 nsr_deployed = db_nsr["_admin"].get("deployed")
5884
5885 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005886 # Get the input parameters given through update request
5887 vnf_instance_id = db_nslcmop["operationParams"][
5888 "changeVnfPackageData"
5889 ].get("vnfInstanceId")
5890
5891 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5892 "vnfdId"
5893 )
5894 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5895
5896 step = "Getting vnfr from database"
5897 db_vnfr = self.db.get_one(
5898 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5899 )
5900
5901 step = "Getting vnfds from database"
5902 # Latest VNFD
5903 latest_vnfd = self.db.get_one(
5904 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5905 )
5906 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5907
5908 # Current VNFD
5909 current_vnf_revision = db_vnfr.get("revision", 1)
5910 current_vnfd = self.db.get_one(
5911 "vnfds_revisions",
5912 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5913 fail_on_empty=False,
5914 )
5915 # Charm artifact paths will be filled up later
5916 (
5917 current_charm_artifact_path,
5918 target_charm_artifact_path,
5919 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005920 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005921 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005922
5923 step = "Checking if revision has changed in VNFD"
5924 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305925 change_type = "policy_updated"
5926
aticigdffa6212022-04-12 15:27:53 +03005927 # There is new revision of VNFD, update operation is required
5928 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005929 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005930
5931 step = "Removing the VNFD packages if they exist in the local path"
5932 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5933 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5934
5935 step = "Get the VNFD packages from FSMongo"
5936 self.fs.sync(from_path=latest_vnfd_path)
5937 self.fs.sync(from_path=current_vnfd_path)
5938
5939 step = (
5940 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5941 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005942 current_base_folder = current_vnfd["_admin"]["storage"]
5943 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005944
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005945 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005946 get_iterable(nsr_deployed, "VCA")
5947 ):
5948 vnf_index = db_vnfr.get("member-vnf-index-ref")
5949
5950 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005951 if vca_deployed.get("member-vnf-index") == vnf_index:
5952 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5953 vca_type = vca_deployed.get("type")
5954 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005955
5956 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005957 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005958
5959 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005960 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005961 search_key = "kdu_name"
5962 else:
5963 search_key = "vnfd_id"
5964
5965 entity_id = vca_deployed.get(search_key)
5966
aticigdffa6212022-04-12 15:27:53 +03005967 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005968 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005969 )
5970
5971 if "execution-environment-list" in descriptor_config:
5972 ee_list = descriptor_config.get(
5973 "execution-environment-list", []
5974 )
5975 else:
5976 ee_list = []
5977
5978 # There could be several charm used in the same VNF
5979 for ee_item in ee_list:
5980 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005981 step = "Getting charm name"
5982 charm_name = ee_item["juju"].get("charm")
5983
5984 step = "Setting Charm artifact paths"
5985 current_charm_artifact_path.append(
5986 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005987 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005988 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005989 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005990 current_vnf_revision,
5991 )
5992 )
5993 target_charm_artifact_path.append(
5994 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005995 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005996 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005997 vca_type,
aticigd7083542022-05-30 20:45:55 +03005998 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005999 )
6000 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006001 elif ee_item.get("helm-chart"):
6002 # add chart to list and all parameters
6003 step = "Getting helm chart name"
6004 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00006005 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006006 step = "Setting Helm chart artifact paths"
6007
garciadeblasfb1e25f2022-11-18 14:36:22 +01006008 helm_artifacts.append(
6009 {
6010 "current_artifact_path": get_charm_artifact_path(
6011 current_base_folder,
6012 chart_name,
6013 vca_type,
6014 current_vnf_revision,
6015 ),
6016 "target_artifact_path": get_charm_artifact_path(
6017 latest_base_folder,
6018 chart_name,
6019 vca_type,
6020 latest_vnfd_revision,
6021 ),
6022 "ee_id": ee_id,
6023 "vca_index": vca_index,
6024 "vdu_index": vdu_count_index,
6025 }
6026 )
aticigdffa6212022-04-12 15:27:53 +03006027
6028 charm_artifact_paths = zip(
6029 current_charm_artifact_path, target_charm_artifact_path
6030 )
6031
6032 step = "Checking if software version has changed in VNFD"
6033 if find_software_version(current_vnfd) != find_software_version(
6034 latest_vnfd
6035 ):
aticigdffa6212022-04-12 15:27:53 +03006036 step = "Checking if existing VNF has charm"
6037 for current_charm_path, target_charm_path in list(
6038 charm_artifact_paths
6039 ):
6040 if current_charm_path:
6041 raise LcmException(
6042 "Software version change is not supported as VNF instance {} has charm.".format(
6043 vnf_instance_id
6044 )
6045 )
6046
kayal20010cd8af32024-03-13 10:23:16 +05306047 step = "Checking whether the descriptor has SFC"
6048 if db_nsr.get("nsd", {}).get("vnffgd"):
6049 raise LcmException(
6050 "Ns update is not allowed for NS with SFC"
6051 )
6052
aticigdffa6212022-04-12 15:27:53 +03006053 # There is no change in the charm package, then redeploy the VNF
6054 # based on new descriptor
6055 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306056 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006057 (result, detailed_status) = await self._ns_redeploy_vnf(
6058 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306059 )
6060 if result == "FAILED":
6061 nslcmop_operation_state = result
6062 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306063 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306064 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306065 db_nsr_update["detailed-status"] = detailed_status
6066 scaling_aspect = get_scaling_aspect(latest_vnfd)
6067 scaling_group_desc = db_nsr.get("_admin").get(
6068 "scaling-group", None
6069 )
6070 if scaling_group_desc:
6071 for aspect in scaling_aspect:
6072 scaling_group_id = aspect.get("id")
6073 for scale_index, scaling_group in enumerate(
6074 scaling_group_desc
6075 ):
6076 if scaling_group.get("name") == scaling_group_id:
6077 db_nsr_update[
6078 "_admin.scaling-group.{}.nb-scale-op".format(
6079 scale_index
6080 )
6081 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306082 self.logger.debug(
6083 logging_text
6084 + " step {} Done with result {} {}".format(
6085 step, nslcmop_operation_state, detailed_status
6086 )
6087 )
aticigdffa6212022-04-12 15:27:53 +03006088
6089 else:
6090 step = "Checking if any charm package has changed or not"
6091 for current_charm_path, target_charm_path in list(
6092 charm_artifact_paths
6093 ):
6094 if (
6095 current_charm_path
6096 and target_charm_path
6097 and self.check_charm_hash_changed(
6098 current_charm_path, target_charm_path
6099 )
6100 ):
aticigdffa6212022-04-12 15:27:53 +03006101 step = "Checking whether VNF uses juju bundle"
6102 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006103 raise LcmException(
6104 "Charm upgrade is not supported for the instance which"
6105 " uses juju-bundle: {}".format(
6106 check_juju_bundle_existence(current_vnfd)
6107 )
6108 )
6109
6110 step = "Upgrading Charm"
6111 (
6112 result,
6113 detailed_status,
6114 ) = await self._ns_charm_upgrade(
6115 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006116 charm_id=vca_id,
6117 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006118 path=self.fs.path + target_charm_path,
6119 timeout=timeout_seconds,
6120 )
6121
6122 if result == "FAILED":
6123 nslcmop_operation_state = result
6124 error_description_nslcmop = detailed_status
6125
6126 db_nslcmop_update["detailed-status"] = detailed_status
6127 self.logger.debug(
6128 logging_text
6129 + " step {} Done with result {} {}".format(
6130 step, nslcmop_operation_state, detailed_status
6131 )
6132 )
6133
6134 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306135 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6136 result = "COMPLETED"
6137 detailed_status = "Done"
6138 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006139
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006140 # helm base EE
6141 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006142 if not (
6143 item["current_artifact_path"]
6144 and item["target_artifact_path"]
6145 and self.check_charm_hash_changed(
6146 item["current_artifact_path"],
6147 item["target_artifact_path"],
6148 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006149 ):
6150 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006151 db_update_entry = "_admin.deployed.VCA.{}.".format(
6152 item["vca_index"]
6153 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006154 vnfr_id = db_vnfr["_id"]
6155 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6156 db_dict = {
6157 "collection": "nsrs",
6158 "filter": {"_id": nsr_id},
6159 "path": db_update_entry,
6160 }
6161 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006162 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006163 namespace=namespace,
6164 helm_id=helm_id,
6165 db_dict=db_dict,
6166 config=osm_config,
6167 artifact_path=item["target_artifact_path"],
6168 vca_type=vca_type,
6169 )
6170 vnf_id = db_vnfr.get("vnfd-ref")
6171 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6172 self.logger.debug("get ssh key block")
6173 rw_mgmt_ip = None
6174 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006175 config_descriptor,
6176 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006177 ):
6178 # Needed to inject a ssh key
6179 user = deep_get(
6180 config_descriptor,
6181 ("config-access", "ssh-access", "default-user"),
6182 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006183 step = (
6184 "Install configuration Software, getting public ssh key"
6185 )
6186 pub_key = await self.vca_map[
6187 vca_type
6188 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006189 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6190 )
6191
garciadeblasfb1e25f2022-11-18 14:36:22 +01006192 step = (
6193 "Insert public key into VM user={} ssh_key={}".format(
6194 user, pub_key
6195 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006196 )
6197 self.logger.debug(logging_text + step)
6198
6199 # wait for RO (ip-address) Insert pub_key into VM
6200 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6201 logging_text,
6202 nsr_id,
6203 vnfr_id,
6204 None,
6205 item["vdu_index"],
6206 user=user,
6207 pub_key=pub_key,
6208 )
6209
6210 initial_config_primitive_list = config_descriptor.get(
6211 "initial-config-primitive"
6212 )
6213 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006214 (
6215 p
6216 for p in initial_config_primitive_list
6217 if p["name"] == "config"
6218 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006219 None,
6220 )
6221 if not config_primitive:
6222 continue
6223
6224 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6225 if rw_mgmt_ip:
6226 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6227 if db_vnfr.get("additionalParamsForVnf"):
6228 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006229 parse_yaml_strings(
6230 db_vnfr["additionalParamsForVnf"].copy()
6231 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006232 )
6233 primitive_params_ = self._map_primitive_params(
6234 config_primitive, {}, deploy_params
6235 )
6236
6237 step = "execute primitive '{}' params '{}'".format(
6238 config_primitive["name"], primitive_params_
6239 )
6240 self.logger.debug(logging_text + step)
6241 await self.vca_map[vca_type].exec_primitive(
6242 ee_id=ee_id,
6243 primitive_name=config_primitive["name"],
6244 params_dict=primitive_params_,
6245 db_dict=db_dict,
6246 vca_id=vca_id,
6247 vca_type=vca_type,
6248 )
6249
6250 step = "Updating policies"
6251 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6252 detailed_status = "Done"
6253 db_nslcmop_update["detailed-status"] = "Done"
6254
aticigdffa6212022-04-12 15:27:53 +03006255 # If nslcmop_operation_state is None, so any operation is not failed.
6256 if not nslcmop_operation_state:
6257 nslcmop_operation_state = "COMPLETED"
6258
6259 # If update CHANGE_VNFPKG nslcmop_operation is successful
6260 # vnf revision need to be updated
6261 vnfr_update["revision"] = latest_vnfd_revision
6262 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6263
6264 self.logger.debug(
6265 logging_text
6266 + " task Done with result {} {}".format(
6267 nslcmop_operation_state, detailed_status
6268 )
6269 )
6270 elif update_type == "REMOVE_VNF":
6271 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306272 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6273 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6274 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6275 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006276 (result, detailed_status) = await self.remove_vnf(
6277 nsr_id, nslcmop_id, vnf_instance_id
6278 )
elumalaica7ece02022-04-12 12:47:32 +05306279 if result == "FAILED":
6280 nslcmop_operation_state = result
6281 error_description_nslcmop = detailed_status
6282 db_nslcmop_update["detailed-status"] = detailed_status
6283 change_type = "vnf_terminated"
6284 if not nslcmop_operation_state:
6285 nslcmop_operation_state = "COMPLETED"
6286 self.logger.debug(
6287 logging_text
6288 + " task Done with result {} {}".format(
6289 nslcmop_operation_state, detailed_status
6290 )
6291 )
aticigdffa6212022-04-12 15:27:53 +03006292
k4.rahulb827de92022-05-02 16:35:02 +00006293 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006294 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6295 "vnfInstanceId"
6296 ]
6297 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6298 "changeStateTo"
6299 ]
6300 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6301 "additionalParam"
6302 ]
k4.rahulb827de92022-05-02 16:35:02 +00006303 (result, detailed_status) = await self.rebuild_start_stop(
6304 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006305 )
k4.rahulb827de92022-05-02 16:35:02 +00006306 if result == "FAILED":
6307 nslcmop_operation_state = result
6308 error_description_nslcmop = detailed_status
6309 db_nslcmop_update["detailed-status"] = detailed_status
6310 if not nslcmop_operation_state:
6311 nslcmop_operation_state = "COMPLETED"
6312 self.logger.debug(
6313 logging_text
6314 + " task Done with result {} {}".format(
6315 nslcmop_operation_state, detailed_status
6316 )
6317 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306318 elif update_type == "VERTICAL_SCALE":
6319 self.logger.debug(
6320 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6321 )
6322 # Get the input parameters given through update request
6323 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6324 "vnfInstanceId"
6325 )
6326
6327 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6328 "vnfdId"
6329 )
6330 step = "Getting vnfr from database"
6331 db_vnfr = self.db.get_one(
6332 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6333 )
6334 self.logger.debug(step)
6335 step = "Getting vnfds from database"
6336 self.logger.debug("Start" + step)
6337 # Latest VNFD
6338 latest_vnfd = self.db.get_one(
6339 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6340 )
6341 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6342 # Current VNFD
6343 current_vnf_revision = db_vnfr.get("revision", 1)
6344 current_vnfd = self.db.get_one(
6345 "vnfds_revisions",
6346 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6347 fail_on_empty=False,
6348 )
6349 self.logger.debug("End" + step)
6350 # verify flavor changes
6351 step = "Checking for flavor change"
6352 if find_software_version(current_vnfd) != find_software_version(
6353 latest_vnfd
6354 ):
6355 self.logger.debug("Start" + step)
6356 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6357 "virtual-compute-desc"
6358 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6359 "virtual-storage-desc"
6360 ):
6361 raise LcmException(
6362 "No change in flavor check vnfd {}".format(vnfd_id)
6363 )
6364 else:
6365 raise LcmException(
6366 "No change in software_version of vnfd {}".format(vnfd_id)
6367 )
6368
6369 self.logger.debug("End" + step)
6370
6371 (result, detailed_status) = await self.vertical_scale(
6372 nsr_id, nslcmop_id
6373 )
6374 self.logger.debug(
6375 "vertical_scale result: {} detailed_status :{}".format(
6376 result, detailed_status
6377 )
6378 )
6379 if result == "FAILED":
6380 nslcmop_operation_state = result
6381 error_description_nslcmop = detailed_status
6382 db_nslcmop_update["detailed-status"] = detailed_status
6383 if not nslcmop_operation_state:
6384 nslcmop_operation_state = "COMPLETED"
6385 self.logger.debug(
6386 logging_text
6387 + " task Done with result {} {}".format(
6388 nslcmop_operation_state, detailed_status
6389 )
6390 )
k4.rahulb827de92022-05-02 16:35:02 +00006391
aticigdffa6212022-04-12 15:27:53 +03006392 # If nslcmop_operation_state is None, so any operation is not failed.
6393 # All operations are executed in overall.
6394 if not nslcmop_operation_state:
6395 nslcmop_operation_state = "COMPLETED"
6396 db_nsr_update["operational-status"] = old_operational_status
6397
6398 except (DbException, LcmException, N2VCException, K8sException) as e:
6399 self.logger.error(logging_text + "Exit Exception {}".format(e))
6400 exc = e
6401 except asyncio.CancelledError:
6402 self.logger.error(
6403 logging_text + "Cancelled Exception while '{}'".format(step)
6404 )
6405 exc = "Operation was cancelled"
6406 except asyncio.TimeoutError:
6407 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6408 exc = "Timeout"
6409 except Exception as e:
6410 exc = traceback.format_exc()
6411 self.logger.critical(
6412 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6413 exc_info=True,
6414 )
6415 finally:
6416 if exc:
6417 db_nslcmop_update[
6418 "detailed-status"
6419 ] = (
6420 detailed_status
6421 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6422 nslcmop_operation_state = "FAILED"
6423 db_nsr_update["operational-status"] = old_operational_status
6424 if db_nsr:
6425 self._write_ns_status(
6426 nsr_id=nsr_id,
6427 ns_state=db_nsr["nsState"],
6428 current_operation="IDLE",
6429 current_operation_id=None,
6430 other_update=db_nsr_update,
6431 )
6432
6433 self._write_op_status(
6434 op_id=nslcmop_id,
6435 stage="",
6436 error_message=error_description_nslcmop,
6437 operation_state=nslcmop_operation_state,
6438 other_update=db_nslcmop_update,
6439 )
6440
6441 if nslcmop_operation_state:
6442 try:
elumalaica7ece02022-04-12 12:47:32 +05306443 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306444 "nsr_id": nsr_id,
6445 "nslcmop_id": nslcmop_id,
6446 "operationState": nslcmop_operation_state,
6447 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006448 if (
6449 change_type in ("vnf_terminated", "policy_updated")
6450 and member_vnf_index
6451 ):
elumalaica7ece02022-04-12 12:47:32 +05306452 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006453 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006454 except Exception as e:
6455 self.logger.error(
6456 logging_text + "kafka_write notification Exception {}".format(e)
6457 )
6458 self.logger.debug(logging_text + "Exit")
6459 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6460 return nslcmop_operation_state, detailed_status
6461
tierno59d22d22018-09-25 18:10:19 +02006462 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006463 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006464 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006465 if not task_is_locked_by_me:
6466 return
6467
tierno59d22d22018-09-25 18:10:19 +02006468 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006469 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006470 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006471 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006472 self.logger.debug(logging_text + "Enter")
6473 # get all needed from database
6474 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006475 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006476 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006477 exc = None
tierno9ab95942018-10-10 16:44:22 +02006478 # in case of error, indicates what part of scale was failed to put nsr at error status
6479 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006480 old_operational_status = ""
6481 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006482 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006483 prom_job_name = ""
jegan76777192024-07-01 16:47:53 +00006484 exe = None
6485 nb_scale_op_update = False
tierno59d22d22018-09-25 18:10:19 +02006486 try:
kuused124bfe2019-06-18 12:09:24 +02006487 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006488 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006489 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6490 self._write_ns_status(
6491 nsr_id=nsr_id,
6492 ns_state=None,
6493 current_operation="SCALING",
6494 current_operation_id=nslcmop_id,
6495 )
quilesj4cda56b2019-12-05 10:02:20 +00006496
ikalyvas02d9e7b2019-05-27 18:16:01 +03006497 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006498 self.logger.debug(
6499 step + " after having waited for previous tasks to be completed"
6500 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006501 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006502
ikalyvas02d9e7b2019-05-27 18:16:01 +03006503 step = "Getting nsr from database"
6504 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006505 old_operational_status = db_nsr["operational-status"]
6506 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006507
kayal20010cd8af32024-03-13 10:23:16 +05306508 step = "Checking whether the descriptor has SFC"
6509 if db_nsr.get("nsd", {}).get("vnffgd"):
6510 raise LcmException("Scaling is not allowed for NS with SFC")
6511
tierno59d22d22018-09-25 18:10:19 +02006512 step = "Parsing scaling parameters"
6513 db_nsr_update["operational-status"] = "scaling"
6514 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006515 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006516
garciadeblas5697b8b2021-03-24 09:17:02 +01006517 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6518 "scaleByStepData"
6519 ]["member-vnf-index"]
6520 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6521 "scaleByStepData"
6522 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006523 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006524 # for backward compatibility
6525 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6526 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6527 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6528 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6529
tierno59d22d22018-09-25 18:10:19 +02006530 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006531 db_vnfr = self.db.get_one(
6532 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6533 )
bravof922c4172020-11-24 21:21:43 -03006534
David Garciac1fe90a2021-03-31 19:12:02 +02006535 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6536
tierno59d22d22018-09-25 18:10:19 +02006537 step = "Getting vnfd from database"
6538 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006539
aktas13251562021-02-12 22:19:10 +03006540 base_folder = db_vnfd["_admin"]["storage"]
6541
tierno59d22d22018-09-25 18:10:19 +02006542 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006543 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006544 get_scaling_aspect(db_vnfd),
6545 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006546 )
6547 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006548 raise LcmException(
6549 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6550 "at vnfd:scaling-group-descriptor".format(scaling_group)
6551 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006552
tierno15b1cf12019-08-29 13:21:40 +00006553 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006554 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006555 nb_scale_op = 0
6556 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006557 self.update_db_2(
6558 "nsrs",
6559 nsr_id,
6560 {
6561 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006562 {
6563 "name": scaling_group,
6564 "vnf_index": vnf_index,
6565 "nb-scale-op": 0,
6566 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006567 ]
6568 },
6569 )
tierno59d22d22018-09-25 18:10:19 +02006570 admin_scale_index = 0
6571 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006572 for admin_scale_index, admin_scale_info in enumerate(
6573 db_nsr["_admin"]["scaling-group"]
6574 ):
36970ef037852024-04-01 15:41:31 +00006575 if (
6576 admin_scale_info["name"] == scaling_group
6577 and admin_scale_info["vnf_index"] == vnf_index
6578 ):
tierno59d22d22018-09-25 18:10:19 +02006579 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6580 break
tierno9ab95942018-10-10 16:44:22 +02006581 else: # not found, set index one plus last element and add new entry with the name
6582 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006583 db_nsr_update[
6584 "_admin.scaling-group.{}.name".format(admin_scale_index)
6585 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006586 db_nsr_update[
6587 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6588 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006589
6590 vca_scaling_info = []
6591 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006592 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006593 if "aspect-delta-details" not in scaling_descriptor:
6594 raise LcmException(
6595 "Aspect delta details not fount in scaling descriptor {}".format(
6596 scaling_descriptor["name"]
6597 )
6598 )
tierno59d22d22018-09-25 18:10:19 +02006599 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006600 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006601
aktas5f75f102021-03-15 11:26:10 +03006602 scaling_info["scaling_direction"] = "OUT"
6603 scaling_info["vdu-create"] = {}
6604 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006605 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006606 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006607 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006608 # vdu_index also provides the number of instance of the targeted vdu
6609 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006610 if vdu_index <= len(db_vnfr["vdur"]):
6611 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6612 prom_job_name = (
6613 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6614 )
6615 prom_job_name = prom_job_name.replace("_", "")
6616 prom_job_name = prom_job_name.replace("-", "")
6617 else:
6618 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006619 cloud_init_text = self._get_vdu_cloud_init_content(
6620 vdud, db_vnfd
6621 )
tierno72ef84f2020-10-06 08:22:07 +00006622 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006623 additional_params = (
6624 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6625 or {}
6626 )
bravof832f8992020-12-07 12:57:31 -03006627 cloud_init_list = []
6628
6629 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6630 max_instance_count = 10
6631 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006632 max_instance_count = vdu_profile.get(
6633 "max-number-of-instances", 10
6634 )
6635
6636 default_instance_num = get_number_of_instances(
6637 db_vnfd, vdud["id"]
6638 )
aktas5f75f102021-03-15 11:26:10 +03006639 instances_number = vdu_delta.get("number-of-instances", 1)
6640 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006641
aktas5f75f102021-03-15 11:26:10 +03006642 new_instance_count = nb_scale_op + default_instance_num
6643 # Control if new count is over max and vdu count is less than max.
6644 # Then assign new instance count
6645 if new_instance_count > max_instance_count > vdu_count:
6646 instances_number = new_instance_count - max_instance_count
6647 else:
6648 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006649
aktas5f75f102021-03-15 11:26:10 +03006650 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006651 raise LcmException(
6652 "reached the limit of {} (max-instance-count) "
6653 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006654 "scaling-group-descriptor '{}'".format(
6655 nb_scale_op, scaling_group
6656 )
bravof922c4172020-11-24 21:21:43 -03006657 )
bravof832f8992020-12-07 12:57:31 -03006658 for x in range(vdu_delta.get("number-of-instances", 1)):
6659 if cloud_init_text:
6660 # TODO Information of its own ip is not available because db_vnfr is not updated.
6661 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006662 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006663 )
bravof832f8992020-12-07 12:57:31 -03006664 cloud_init_list.append(
6665 self._parse_cloud_init(
6666 cloud_init_text,
6667 additional_params,
6668 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006669 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006670 )
6671 )
aktas5f75f102021-03-15 11:26:10 +03006672 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006673 {
6674 "osm_vdu_id": vdu_delta["id"],
6675 "member-vnf-index": vnf_index,
6676 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006677 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006678 }
6679 )
aktas5f75f102021-03-15 11:26:10 +03006680 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6681 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006682 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006683 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006684 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006685
6686 # Might have different kdus in the same delta
6687 # Should have list for each kdu
6688 if not scaling_info["kdu-create"].get(kdu_name, None):
6689 scaling_info["kdu-create"][kdu_name] = []
6690
6691 kdur = get_kdur(db_vnfr, kdu_name)
6692 if kdur.get("helm-chart"):
6693 k8s_cluster_type = "helm-chart-v3"
6694 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006695 elif kdur.get("juju-bundle"):
6696 k8s_cluster_type = "juju-bundle"
6697 else:
6698 raise LcmException(
6699 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6700 "juju-bundle. Maybe an old NBI version is running".format(
6701 db_vnfr["member-vnf-index-ref"], kdu_name
6702 )
6703 )
6704
6705 max_instance_count = 10
6706 if kdu_profile and "max-number-of-instances" in kdu_profile:
6707 max_instance_count = kdu_profile.get(
6708 "max-number-of-instances", 10
6709 )
6710
6711 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6712 deployed_kdu, _ = get_deployed_kdu(
6713 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006714 )
aktas5f75f102021-03-15 11:26:10 +03006715 if deployed_kdu is None:
6716 raise LcmException(
6717 "KDU '{}' for vnf '{}' not deployed".format(
6718 kdu_name, vnf_index
6719 )
6720 )
6721 kdu_instance = deployed_kdu.get("kdu-instance")
6722 instance_num = await self.k8scluster_map[
6723 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006724 ].get_scale_count(
6725 resource_name,
6726 kdu_instance,
6727 vca_id=vca_id,
6728 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6729 kdu_model=deployed_kdu.get("kdu-model"),
6730 )
aktas5f75f102021-03-15 11:26:10 +03006731 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006732 "number-of-instances", 1
6733 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006734
aktas5f75f102021-03-15 11:26:10 +03006735 # Control if new count is over max and instance_num is less than max.
6736 # Then assign max instance number to kdu replica count
6737 if kdu_replica_count > max_instance_count > instance_num:
6738 kdu_replica_count = max_instance_count
6739 if kdu_replica_count > max_instance_count:
6740 raise LcmException(
6741 "reached the limit of {} (max-instance-count) "
6742 "scaling-out operations for the "
6743 "scaling-group-descriptor '{}'".format(
6744 instance_num, scaling_group
6745 )
6746 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006747
aktas5f75f102021-03-15 11:26:10 +03006748 for x in range(kdu_delta.get("number-of-instances", 1)):
6749 vca_scaling_info.append(
6750 {
6751 "osm_kdu_id": kdu_name,
6752 "member-vnf-index": vnf_index,
6753 "type": "create",
6754 "kdu_index": instance_num + x - 1,
6755 }
6756 )
6757 scaling_info["kdu-create"][kdu_name].append(
6758 {
6759 "member-vnf-index": vnf_index,
6760 "type": "create",
6761 "k8s-cluster-type": k8s_cluster_type,
6762 "resource-name": resource_name,
6763 "scale": kdu_replica_count,
6764 }
6765 )
6766 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006767 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006768
6769 scaling_info["scaling_direction"] = "IN"
6770 scaling_info["vdu-delete"] = {}
6771 scaling_info["kdu-delete"] = {}
6772
bravof832f8992020-12-07 12:57:31 -03006773 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006774 for vdu_delta in delta.get("vdu-delta", {}):
6775 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006776 min_instance_count = 0
6777 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6778 if vdu_profile and "min-number-of-instances" in vdu_profile:
6779 min_instance_count = vdu_profile["min-number-of-instances"]
6780
garciadeblas5697b8b2021-03-24 09:17:02 +01006781 default_instance_num = get_number_of_instances(
6782 db_vnfd, vdu_delta["id"]
6783 )
aktas5f75f102021-03-15 11:26:10 +03006784 instance_num = vdu_delta.get("number-of-instances", 1)
6785 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006786
aktas5f75f102021-03-15 11:26:10 +03006787 new_instance_count = nb_scale_op + default_instance_num
6788
6789 if new_instance_count < min_instance_count < vdu_count:
6790 instances_number = min_instance_count - new_instance_count
6791 else:
6792 instances_number = instance_num
6793
6794 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006795 raise LcmException(
6796 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006797 "scaling-group-descriptor '{}'".format(
6798 nb_scale_op, scaling_group
6799 )
bravof832f8992020-12-07 12:57:31 -03006800 )
aktas13251562021-02-12 22:19:10 +03006801 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006802 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006803 {
6804 "osm_vdu_id": vdu_delta["id"],
6805 "member-vnf-index": vnf_index,
6806 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006807 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006808 }
6809 )
aktas5f75f102021-03-15 11:26:10 +03006810 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6811 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006812 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006813 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006814 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006815
6816 if not scaling_info["kdu-delete"].get(kdu_name, None):
6817 scaling_info["kdu-delete"][kdu_name] = []
6818
6819 kdur = get_kdur(db_vnfr, kdu_name)
6820 if kdur.get("helm-chart"):
6821 k8s_cluster_type = "helm-chart-v3"
6822 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006823 elif kdur.get("juju-bundle"):
6824 k8s_cluster_type = "juju-bundle"
6825 else:
6826 raise LcmException(
6827 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6828 "juju-bundle. Maybe an old NBI version is running".format(
6829 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6830 )
6831 )
6832
6833 min_instance_count = 0
6834 if kdu_profile and "min-number-of-instances" in kdu_profile:
6835 min_instance_count = kdu_profile["min-number-of-instances"]
6836
6837 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6838 deployed_kdu, _ = get_deployed_kdu(
6839 nsr_deployed, kdu_name, vnf_index
6840 )
6841 if deployed_kdu is None:
6842 raise LcmException(
6843 "KDU '{}' for vnf '{}' not deployed".format(
6844 kdu_name, vnf_index
6845 )
6846 )
6847 kdu_instance = deployed_kdu.get("kdu-instance")
6848 instance_num = await self.k8scluster_map[
6849 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006850 ].get_scale_count(
6851 resource_name,
6852 kdu_instance,
6853 vca_id=vca_id,
6854 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6855 kdu_model=deployed_kdu.get("kdu-model"),
6856 )
aktas5f75f102021-03-15 11:26:10 +03006857 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006858 "number-of-instances", 1
6859 )
tierno59d22d22018-09-25 18:10:19 +02006860
aktas5f75f102021-03-15 11:26:10 +03006861 if kdu_replica_count < min_instance_count < instance_num:
6862 kdu_replica_count = min_instance_count
6863 if kdu_replica_count < min_instance_count:
6864 raise LcmException(
6865 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6866 "scaling-group-descriptor '{}'".format(
6867 instance_num, scaling_group
6868 )
6869 )
6870
6871 for x in range(kdu_delta.get("number-of-instances", 1)):
6872 vca_scaling_info.append(
6873 {
6874 "osm_kdu_id": kdu_name,
6875 "member-vnf-index": vnf_index,
6876 "type": "delete",
6877 "kdu_index": instance_num - x - 1,
6878 }
6879 )
6880 scaling_info["kdu-delete"][kdu_name].append(
6881 {
6882 "member-vnf-index": vnf_index,
6883 "type": "delete",
6884 "k8s-cluster-type": k8s_cluster_type,
6885 "resource-name": resource_name,
6886 "scale": kdu_replica_count,
6887 }
6888 )
6889
tierno59d22d22018-09-25 18:10:19 +02006890 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006891 vdu_delete = copy(scaling_info.get("vdu-delete"))
6892 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006893 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006894 if vdu_delete.get(vdur["vdu-id-ref"]):
6895 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006896 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006897 {
6898 "name": vdur.get("name") or vdur.get("vdu-name"),
6899 "vdu_id": vdur["vdu-id-ref"],
6900 "interface": [],
6901 }
6902 )
tierno59d22d22018-09-25 18:10:19 +02006903 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006904 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006905 {
6906 "name": interface["name"],
6907 "ip_address": interface["ip-address"],
6908 "mac_address": interface.get("mac-address"),
6909 }
6910 )
tierno2357f4e2020-10-19 16:38:59 +00006911 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006912
kuuseac3a8882019-10-03 10:48:06 +02006913 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006914 step = "Executing pre-scale vnf-config-primitive"
6915 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006916 for scaling_config_action in scaling_descriptor[
6917 "scaling-config-action"
6918 ]:
6919 if (
6920 scaling_config_action.get("trigger") == "pre-scale-in"
6921 and scaling_type == "SCALE_IN"
6922 ) or (
6923 scaling_config_action.get("trigger") == "pre-scale-out"
6924 and scaling_type == "SCALE_OUT"
6925 ):
6926 vnf_config_primitive = scaling_config_action[
6927 "vnf-config-primitive-name-ref"
6928 ]
6929 step = db_nslcmop_update[
6930 "detailed-status"
6931 ] = "executing pre-scale scaling-config-action '{}'".format(
6932 vnf_config_primitive
6933 )
tiernoda964822019-01-14 15:53:47 +00006934
tierno59d22d22018-09-25 18:10:19 +02006935 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006936 for config_primitive in (
6937 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6938 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006939 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006940 break
6941 else:
6942 raise LcmException(
6943 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006944 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006945 "primitive".format(scaling_group, vnf_config_primitive)
6946 )
tiernoda964822019-01-14 15:53:47 +00006947
aktas5f75f102021-03-15 11:26:10 +03006948 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006949 if db_vnfr.get("additionalParamsForVnf"):
6950 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006951
tierno9ab95942018-10-10 16:44:22 +02006952 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006953 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006954 primitive_params = self._map_primitive_params(
6955 config_primitive, {}, vnfr_params
6956 )
kuuseac3a8882019-10-03 10:48:06 +02006957
tierno7c4e24c2020-05-13 08:41:35 +00006958 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006959 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006960 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006961 vnf_index,
6962 vnf_config_primitive,
6963 primitive_params,
6964 "PRE-SCALE",
6965 )
tierno7c4e24c2020-05-13 08:41:35 +00006966 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006967 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006968 result = "COMPLETED"
6969 result_detail = "Done"
6970 self.logger.debug(
6971 logging_text
6972 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6973 vnf_config_primitive, result, result_detail
6974 )
6975 )
kuuseac3a8882019-10-03 10:48:06 +02006976 else:
tierno7c4e24c2020-05-13 08:41:35 +00006977 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006978 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006979 op_index = (
6980 len(db_nslcmop.get("_admin", {}).get("operations"))
6981 - 1
6982 )
6983 self.logger.debug(
6984 logging_text
6985 + "vnf_config_primitive={} New sub-operation".format(
6986 vnf_config_primitive
6987 )
6988 )
kuuseac3a8882019-10-03 10:48:06 +02006989 else:
tierno7c4e24c2020-05-13 08:41:35 +00006990 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006991 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6992 op_index
6993 ]
6994 vnf_index = op.get("member_vnf_index")
6995 vnf_config_primitive = op.get("primitive")
6996 primitive_params = op.get("primitive_params")
6997 self.logger.debug(
6998 logging_text
6999 + "vnf_config_primitive={} Sub-operation retry".format(
7000 vnf_config_primitive
7001 )
7002 )
tierno588547c2020-07-01 15:30:20 +00007003 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007004 ee_descriptor_id = config_primitive.get(
7005 "execution-environment-ref"
7006 )
7007 primitive_name = config_primitive.get(
7008 "execution-environment-primitive", vnf_config_primitive
7009 )
7010 ee_id, vca_type = self._look_for_deployed_vca(
7011 nsr_deployed["VCA"],
7012 member_vnf_index=vnf_index,
7013 vdu_id=None,
7014 vdu_count_index=None,
7015 ee_descriptor_id=ee_descriptor_id,
7016 )
kuuseac3a8882019-10-03 10:48:06 +02007017 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01007018 ee_id,
7019 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02007020 primitive_params,
7021 vca_type=vca_type,
7022 vca_id=vca_id,
7023 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007024 self.logger.debug(
7025 logging_text
7026 + "vnf_config_primitive={} Done with result {} {}".format(
7027 vnf_config_primitive, result, result_detail
7028 )
7029 )
kuuseac3a8882019-10-03 10:48:06 +02007030 # Update operationState = COMPLETED | FAILED
7031 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007032 db_nslcmop, op_index, result, result_detail
7033 )
kuuseac3a8882019-10-03 10:48:06 +02007034
tierno59d22d22018-09-25 18:10:19 +02007035 if result == "FAILED":
7036 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007037 db_nsr_update["config-status"] = old_config_status
7038 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007039 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007040
garciadeblas5697b8b2021-03-24 09:17:02 +01007041 db_nsr_update[
7042 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
7043 ] = nb_scale_op
7044 db_nsr_update[
7045 "_admin.scaling-group.{}.time".format(admin_scale_index)
7046 ] = time()
jegan76777192024-07-01 16:47:53 +00007047 nb_scale_op_update = True
tierno2357f4e2020-10-19 16:38:59 +00007048
aktas13251562021-02-12 22:19:10 +03007049 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007050 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007051 step = db_nslcmop_update[
7052 "detailed-status"
7053 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007054 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007055 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007056 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007057 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007058 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007059 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007060 )
aktas5f75f102021-03-15 11:26:10 +03007061 if vca_info.get("osm_vdu_id"):
7062 vdu_id = vca_info["osm_vdu_id"]
7063 vdu_index = int(vca_info["vdu_index"])
7064 stage[
7065 1
7066 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7067 member_vnf_index, vdu_id, vdu_index
7068 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007069 stage[2] = step = "Scaling in VCA"
7070 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007071 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7072 config_update = db_nsr["configurationStatus"]
7073 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007074 if (
7075 (vca or vca.get("ee_id"))
7076 and vca["member-vnf-index"] == member_vnf_index
7077 and vca["vdu_count_index"] == vdu_index
7078 ):
aktas13251562021-02-12 22:19:10 +03007079 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007080 config_descriptor = get_configuration(
7081 db_vnfd, vca.get("vdu_id")
7082 )
aktas13251562021-02-12 22:19:10 +03007083 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007084 config_descriptor = get_configuration(
7085 db_vnfd, vca.get("kdu_name")
7086 )
aktas13251562021-02-12 22:19:10 +03007087 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007088 config_descriptor = get_configuration(
7089 db_vnfd, db_vnfd["id"]
7090 )
7091 operation_params = (
7092 db_nslcmop.get("operationParams") or {}
7093 )
7094 exec_terminate_primitives = not operation_params.get(
7095 "skip_terminate_primitives"
7096 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007097 task = asyncio.ensure_future(
7098 asyncio.wait_for(
7099 self.destroy_N2VC(
7100 logging_text,
7101 db_nslcmop,
7102 vca,
7103 config_descriptor,
7104 vca_index,
7105 destroy_ee=True,
7106 exec_primitives=exec_terminate_primitives,
7107 scaling_in=True,
7108 vca_id=vca_id,
7109 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007110 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007111 )
7112 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007113 tasks_dict_info[task] = "Terminating VCA {}".format(
7114 vca.get("ee_id")
7115 )
aktas13251562021-02-12 22:19:10 +03007116 del vca_update[vca_index]
7117 del config_update[vca_index]
7118 # wait for pending tasks of terminate primitives
7119 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007120 self.logger.debug(
7121 logging_text
7122 + "Waiting for tasks {}".format(
7123 list(tasks_dict_info.keys())
7124 )
7125 )
7126 error_list = await self._wait_for_tasks(
7127 logging_text,
7128 tasks_dict_info,
7129 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007130 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007131 ),
7132 stage,
7133 nslcmop_id,
7134 )
aktas13251562021-02-12 22:19:10 +03007135 tasks_dict_info.clear()
7136 if error_list:
7137 raise LcmException("; ".join(error_list))
7138
7139 db_vca_and_config_update = {
7140 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007141 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007142 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007143 self.update_db_2(
7144 "nsrs", db_nsr["_id"], db_vca_and_config_update
7145 )
aktas13251562021-02-12 22:19:10 +03007146 scale_process = None
7147 # SCALE-IN VCA - END
7148
kuuseac3a8882019-10-03 10:48:06 +02007149 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007150 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007151 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007152 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007153 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007154 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007155 )
aktas5f75f102021-03-15 11:26:10 +03007156 scaling_info.pop("vdu-create", None)
7157 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007158
tierno9ab95942018-10-10 16:44:22 +02007159 scale_process = None
aktas13251562021-02-12 22:19:10 +03007160 # SCALE RO - END
7161
aktas5f75f102021-03-15 11:26:10 +03007162 # SCALE KDU - BEGIN
7163 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7164 scale_process = "KDU"
7165 await self._scale_kdu(
7166 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7167 )
7168 scaling_info.pop("kdu-create", None)
7169 scaling_info.pop("kdu-delete", None)
7170
7171 scale_process = None
7172 # SCALE KDU - END
7173
7174 if db_nsr_update:
7175 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7176
aktas13251562021-02-12 22:19:10 +03007177 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007178 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007179 step = db_nslcmop_update[
7180 "detailed-status"
7181 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007182 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007183 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007184 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007185 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007186 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007187 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007188 )
aktas13251562021-02-12 22:19:10 +03007189 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007190 if vca_info.get("osm_vdu_id"):
7191 vdu_index = int(vca_info["vdu_index"])
7192 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7193 if db_vnfr.get("additionalParamsForVnf"):
7194 deploy_params.update(
7195 parse_yaml_strings(
7196 db_vnfr["additionalParamsForVnf"].copy()
7197 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007198 )
aktas5f75f102021-03-15 11:26:10 +03007199 descriptor_config = get_configuration(
7200 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007201 )
aktas5f75f102021-03-15 11:26:10 +03007202 if descriptor_config:
7203 vdu_id = None
7204 vdu_name = None
7205 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007206 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007207 self._deploy_n2vc(
7208 logging_text=logging_text
7209 + "member_vnf_index={} ".format(member_vnf_index),
7210 db_nsr=db_nsr,
7211 db_vnfr=db_vnfr,
7212 nslcmop_id=nslcmop_id,
7213 nsr_id=nsr_id,
7214 nsi_id=nsi_id,
7215 vnfd_id=vnfd_id,
7216 vdu_id=vdu_id,
7217 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007218 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007219 member_vnf_index=member_vnf_index,
7220 vdu_index=vdu_index,
7221 vdu_name=vdu_name,
7222 deploy_params=deploy_params,
7223 descriptor_config=descriptor_config,
7224 base_folder=base_folder,
7225 task_instantiation_info=tasks_dict_info,
7226 stage=stage,
7227 )
7228 vdu_id = vca_info["osm_vdu_id"]
7229 vdur = find_in_list(
7230 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007231 )
aktas5f75f102021-03-15 11:26:10 +03007232 descriptor_config = get_configuration(db_vnfd, vdu_id)
7233 if vdur.get("additionalParams"):
7234 deploy_params_vdu = parse_yaml_strings(
7235 vdur["additionalParams"]
7236 )
7237 else:
7238 deploy_params_vdu = deploy_params
7239 deploy_params_vdu["OSM"] = get_osm_params(
7240 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007241 )
aktas5f75f102021-03-15 11:26:10 +03007242 if descriptor_config:
7243 vdu_name = None
7244 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007245 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007246 stage[
7247 1
7248 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007249 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007250 )
7251 stage[2] = step = "Scaling out VCA"
7252 self._write_op_status(op_id=nslcmop_id, stage=stage)
7253 self._deploy_n2vc(
7254 logging_text=logging_text
7255 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7256 member_vnf_index, vdu_id, vdu_index
7257 ),
7258 db_nsr=db_nsr,
7259 db_vnfr=db_vnfr,
7260 nslcmop_id=nslcmop_id,
7261 nsr_id=nsr_id,
7262 nsi_id=nsi_id,
7263 vnfd_id=vnfd_id,
7264 vdu_id=vdu_id,
7265 kdu_name=kdu_name,
7266 member_vnf_index=member_vnf_index,
7267 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007268 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007269 vdu_name=vdu_name,
7270 deploy_params=deploy_params_vdu,
7271 descriptor_config=descriptor_config,
7272 base_folder=base_folder,
7273 task_instantiation_info=tasks_dict_info,
7274 stage=stage,
7275 )
aktas13251562021-02-12 22:19:10 +03007276 # SCALE-UP VCA - END
7277 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007278
kuuseac3a8882019-10-03 10:48:06 +02007279 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007280 # execute primitive service POST-SCALING
7281 step = "Executing post-scale vnf-config-primitive"
7282 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007283 for scaling_config_action in scaling_descriptor[
7284 "scaling-config-action"
7285 ]:
7286 if (
7287 scaling_config_action.get("trigger") == "post-scale-in"
7288 and scaling_type == "SCALE_IN"
7289 ) or (
7290 scaling_config_action.get("trigger") == "post-scale-out"
7291 and scaling_type == "SCALE_OUT"
7292 ):
7293 vnf_config_primitive = scaling_config_action[
7294 "vnf-config-primitive-name-ref"
7295 ]
7296 step = db_nslcmop_update[
7297 "detailed-status"
7298 ] = "executing post-scale scaling-config-action '{}'".format(
7299 vnf_config_primitive
7300 )
tiernoda964822019-01-14 15:53:47 +00007301
aktas5f75f102021-03-15 11:26:10 +03007302 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007303 if db_vnfr.get("additionalParamsForVnf"):
7304 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7305
tierno59d22d22018-09-25 18:10:19 +02007306 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007307 for config_primitive in (
7308 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7309 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007310 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007311 break
7312 else:
tiernoa278b842020-07-08 15:33:55 +00007313 raise LcmException(
7314 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7315 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007316 "config-primitive".format(
7317 scaling_group, vnf_config_primitive
7318 )
7319 )
tierno9ab95942018-10-10 16:44:22 +02007320 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007321 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007322 primitive_params = self._map_primitive_params(
7323 config_primitive, {}, vnfr_params
7324 )
tiernod6de1992018-10-11 13:05:52 +02007325
tierno7c4e24c2020-05-13 08:41:35 +00007326 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007327 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007328 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007329 vnf_index,
7330 vnf_config_primitive,
7331 primitive_params,
7332 "POST-SCALE",
7333 )
quilesj4cda56b2019-12-05 10:02:20 +00007334 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007335 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007336 result = "COMPLETED"
7337 result_detail = "Done"
7338 self.logger.debug(
7339 logging_text
7340 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7341 vnf_config_primitive, result, result_detail
7342 )
7343 )
kuuseac3a8882019-10-03 10:48:06 +02007344 else:
quilesj4cda56b2019-12-05 10:02:20 +00007345 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007346 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007347 op_index = (
7348 len(db_nslcmop.get("_admin", {}).get("operations"))
7349 - 1
7350 )
7351 self.logger.debug(
7352 logging_text
7353 + "vnf_config_primitive={} New sub-operation".format(
7354 vnf_config_primitive
7355 )
7356 )
kuuseac3a8882019-10-03 10:48:06 +02007357 else:
tierno7c4e24c2020-05-13 08:41:35 +00007358 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007359 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7360 op_index
7361 ]
7362 vnf_index = op.get("member_vnf_index")
7363 vnf_config_primitive = op.get("primitive")
7364 primitive_params = op.get("primitive_params")
7365 self.logger.debug(
7366 logging_text
7367 + "vnf_config_primitive={} Sub-operation retry".format(
7368 vnf_config_primitive
7369 )
7370 )
tierno588547c2020-07-01 15:30:20 +00007371 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007372 ee_descriptor_id = config_primitive.get(
7373 "execution-environment-ref"
7374 )
7375 primitive_name = config_primitive.get(
7376 "execution-environment-primitive", vnf_config_primitive
7377 )
7378 ee_id, vca_type = self._look_for_deployed_vca(
7379 nsr_deployed["VCA"],
7380 member_vnf_index=vnf_index,
7381 vdu_id=None,
7382 vdu_count_index=None,
7383 ee_descriptor_id=ee_descriptor_id,
7384 )
kuuseac3a8882019-10-03 10:48:06 +02007385 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007386 ee_id,
7387 primitive_name,
7388 primitive_params,
7389 vca_type=vca_type,
7390 vca_id=vca_id,
7391 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007392 self.logger.debug(
7393 logging_text
7394 + "vnf_config_primitive={} Done with result {} {}".format(
7395 vnf_config_primitive, result, result_detail
7396 )
7397 )
kuuseac3a8882019-10-03 10:48:06 +02007398 # Update operationState = COMPLETED | FAILED
7399 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007400 db_nslcmop, op_index, result, result_detail
7401 )
kuuseac3a8882019-10-03 10:48:06 +02007402
tierno59d22d22018-09-25 18:10:19 +02007403 if result == "FAILED":
7404 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007405 db_nsr_update["config-status"] = old_config_status
7406 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007407 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007408 # Check if each vnf has exporter for metric collection if so update prometheus job records
Rahul Kumar54671c52024-05-09 15:34:01 +05307409 if scaling_type == "SCALE_OUT" and bool(self.service_kpi.old_sa):
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007410 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7411 vnfr_id = db_vnfr["id"]
7412 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7413 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7414 self.logger.debug("exporter config :{}".format(exporter_config))
7415 artifact_path = "{}/{}/{}".format(
7416 base_folder["folder"],
7417 base_folder["pkg-dir"],
7418 "exporter-endpoint",
7419 )
7420 ee_id = None
7421 ee_config_descriptor = exporter_config
7422 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7423 logging_text,
7424 nsr_id,
7425 vnfr_id,
7426 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7427 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7428 user=None,
7429 pub_key=None,
7430 )
7431 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7432 self.logger.debug("Artifact_path:{}".format(artifact_path))
7433 vdu_id_for_prom = None
7434 vdu_index_for_prom = None
7435 for x in get_iterable(db_vnfr, "vdur"):
7436 vdu_id_for_prom = x.get("vdu-id-ref")
7437 vdu_index_for_prom = x.get("count-index")
7438 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7439 vnfr_id = vnfr_id.replace("_", "")
7440 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7441 ee_id=ee_id,
7442 artifact_path=artifact_path,
7443 ee_config_descriptor=ee_config_descriptor,
7444 vnfr_id=vnfr_id,
7445 nsr_id=nsr_id,
7446 target_ip=rw_mgmt_ip,
7447 element_type="VDU",
7448 vdu_id=vdu_id_for_prom,
7449 vdu_index=vdu_index_for_prom,
7450 )
tierno59d22d22018-09-25 18:10:19 +02007451
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007452 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7453 if prometheus_jobs:
7454 db_nsr_update[
7455 "_admin.deployed.prometheus_jobs"
7456 ] = prometheus_jobs
7457 self.update_db_2(
7458 "nsrs",
7459 nsr_id,
7460 db_nsr_update,
7461 )
7462
7463 for job in prometheus_jobs:
7464 self.db.set_one(
7465 "prometheus_jobs",
7466 {"job_name": ""},
7467 job,
7468 upsert=True,
7469 fail_on_empty=False,
7470 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007471 db_nsr_update[
7472 "detailed-status"
7473 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7474 db_nsr_update["operational-status"] = (
7475 "running"
7476 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007477 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007478 )
tiernod6de1992018-10-11 13:05:52 +02007479 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007480 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007481 except (
7482 ROclient.ROClientException,
jegan76777192024-07-01 16:47:53 +00007483 NgRoException,
7484 ) as e:
7485 exe = "RO exception"
7486 self.logger.error(logging_text + "Exit Exception {}".format(e))
7487 exc = e
7488 except (
garciadeblas5697b8b2021-03-24 09:17:02 +01007489 DbException,
7490 LcmException,
garciadeblas5697b8b2021-03-24 09:17:02 +01007491 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007492 self.logger.error(logging_text + "Exit Exception {}".format(e))
7493 exc = e
7494 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007495 self.logger.error(
7496 logging_text + "Cancelled Exception while '{}'".format(step)
7497 )
tierno59d22d22018-09-25 18:10:19 +02007498 exc = "Operation was cancelled"
7499 except Exception as e:
7500 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007501 self.logger.critical(
7502 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7503 exc_info=True,
7504 )
tierno59d22d22018-09-25 18:10:19 +02007505 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007506 error_list = list()
7507 if exc:
7508 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007509 self._write_ns_status(
7510 nsr_id=nsr_id,
7511 ns_state=None,
7512 current_operation="IDLE",
7513 current_operation_id=None,
7514 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007515 try:
7516 if tasks_dict_info:
7517 stage[1] = "Waiting for instantiate pending tasks."
7518 self.logger.debug(logging_text + stage[1])
7519 exc = await self._wait_for_tasks(
7520 logging_text,
7521 tasks_dict_info,
7522 self.timeout.ns_deploy,
7523 stage,
7524 nslcmop_id,
7525 nsr_id=nsr_id,
7526 )
7527 except asyncio.CancelledError:
7528 error_list.append("Cancelled")
7529 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7530 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007531 logging_text,
7532 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007533 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007534 stage,
7535 nslcmop_id,
7536 nsr_id=nsr_id,
7537 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007538 if error_list:
7539 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007540 db_nslcmop_update[
7541 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007542 ] = error_description_nslcmop = "FAILED {}: {}".format(
7543 step, error_detail
7544 )
tiernoa17d4f42020-04-28 09:59:23 +00007545 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007546 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007547 db_nsr_update["operational-status"] = old_operational_status
7548 db_nsr_update["config-status"] = old_config_status
7549 db_nsr_update["detailed-status"] = ""
7550 if scale_process:
7551 if "VCA" in scale_process:
7552 db_nsr_update["config-status"] = "failed"
7553 if "RO" in scale_process:
7554 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007555 db_nsr_update[
7556 "detailed-status"
7557 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007558 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007559 )
tiernoa17d4f42020-04-28 09:59:23 +00007560 else:
7561 error_description_nslcmop = None
7562 nslcmop_operation_state = "COMPLETED"
7563 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007564 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7565 self.db.del_one(
7566 "prometheus_jobs",
7567 {"job_name": prom_job_name},
7568 fail_on_empty=False,
7569 )
quilesj4cda56b2019-12-05 10:02:20 +00007570
garciadeblas5697b8b2021-03-24 09:17:02 +01007571 self._write_op_status(
7572 op_id=nslcmop_id,
7573 stage="",
7574 error_message=error_description_nslcmop,
7575 operation_state=nslcmop_operation_state,
7576 other_update=db_nslcmop_update,
7577 )
tiernoa17d4f42020-04-28 09:59:23 +00007578 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007579 self._write_ns_status(
7580 nsr_id=nsr_id,
7581 ns_state=None,
7582 current_operation="IDLE",
7583 current_operation_id=None,
7584 other_update=db_nsr_update,
7585 )
jegan76777192024-07-01 16:47:53 +00007586 if exe:
7587 if (
7588 scaling_type == "SCALE_OUT"
7589 and nb_scale_op_update
7590 and exe == "RO exception"
7591 ):
7592 self.rollback_scaling(nsr_id, nslcmop_id)
tiernoa17d4f42020-04-28 09:59:23 +00007593
tierno59d22d22018-09-25 18:10:19 +02007594 if nslcmop_operation_state:
7595 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007596 msg = {
7597 "nsr_id": nsr_id,
7598 "nslcmop_id": nslcmop_id,
7599 "operationState": nslcmop_operation_state,
7600 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007601 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007602 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007603 self.logger.error(
7604 logging_text + "kafka_write notification Exception {}".format(e)
7605 )
tierno59d22d22018-09-25 18:10:19 +02007606 self.logger.debug(logging_text + "Exit")
7607 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007608
aktas5f75f102021-03-15 11:26:10 +03007609 async def _scale_kdu(
7610 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7611 ):
7612 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7613 for kdu_name in _scaling_info:
7614 for kdu_scaling_info in _scaling_info[kdu_name]:
7615 deployed_kdu, index = get_deployed_kdu(
7616 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7617 )
7618 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7619 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007620 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007621 scale = int(kdu_scaling_info["scale"])
7622 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7623
7624 db_dict = {
7625 "collection": "nsrs",
7626 "filter": {"_id": nsr_id},
7627 "path": "_admin.deployed.K8s.{}".format(index),
7628 }
7629
7630 step = "scaling application {}".format(
7631 kdu_scaling_info["resource-name"]
7632 )
7633 self.logger.debug(logging_text + step)
7634
7635 if kdu_scaling_info["type"] == "delete":
7636 kdu_config = get_configuration(db_vnfd, kdu_name)
7637 if (
7638 kdu_config
7639 and kdu_config.get("terminate-config-primitive")
7640 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7641 ):
7642 terminate_config_primitive_list = kdu_config.get(
7643 "terminate-config-primitive"
7644 )
7645 terminate_config_primitive_list.sort(
7646 key=lambda val: int(val["seq"])
7647 )
7648
7649 for (
7650 terminate_config_primitive
7651 ) in terminate_config_primitive_list:
7652 primitive_params_ = self._map_primitive_params(
7653 terminate_config_primitive, {}, {}
7654 )
7655 step = "execute terminate config primitive"
7656 self.logger.debug(logging_text + step)
7657 await asyncio.wait_for(
7658 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7659 cluster_uuid=cluster_uuid,
7660 kdu_instance=kdu_instance,
7661 primitive_name=terminate_config_primitive["name"],
7662 params=primitive_params_,
7663 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007664 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007665 vca_id=vca_id,
7666 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007667 timeout=self.timeout.primitive
7668 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007669 )
7670
7671 await asyncio.wait_for(
7672 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007673 kdu_instance=kdu_instance,
7674 scale=scale,
7675 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007676 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007677 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007678 cluster_uuid=cluster_uuid,
7679 kdu_model=kdu_model,
7680 atomic=True,
7681 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007682 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007683 timeout=self.timeout.scale_on_error
7684 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007685 )
7686
7687 if kdu_scaling_info["type"] == "create":
7688 kdu_config = get_configuration(db_vnfd, kdu_name)
7689 if (
7690 kdu_config
7691 and kdu_config.get("initial-config-primitive")
7692 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7693 ):
7694 initial_config_primitive_list = kdu_config.get(
7695 "initial-config-primitive"
7696 )
7697 initial_config_primitive_list.sort(
7698 key=lambda val: int(val["seq"])
7699 )
7700
7701 for initial_config_primitive in initial_config_primitive_list:
7702 primitive_params_ = self._map_primitive_params(
7703 initial_config_primitive, {}, {}
7704 )
7705 step = "execute initial config primitive"
7706 self.logger.debug(logging_text + step)
7707 await asyncio.wait_for(
7708 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7709 cluster_uuid=cluster_uuid,
7710 kdu_instance=kdu_instance,
7711 primitive_name=initial_config_primitive["name"],
7712 params=primitive_params_,
7713 db_dict=db_dict,
7714 vca_id=vca_id,
7715 ),
7716 timeout=600,
7717 )
7718
garciadeblas5697b8b2021-03-24 09:17:02 +01007719 async def _scale_ng_ro(
7720 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7721 ):
tierno2357f4e2020-10-19 16:38:59 +00007722 nsr_id = db_nslcmop["nsInstanceId"]
7723 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7724 db_vnfrs = {}
7725
7726 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007727 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007728
7729 # for each vnf in ns, read vnfd
7730 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7731 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7732 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007733 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007734 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007735 # read from db
7736 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007737 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007738 n2vc_key = self.n2vc.get_public_key()
7739 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007740 self.scale_vnfr(
7741 db_vnfr,
7742 vdu_scaling_info.get("vdu-create"),
7743 vdu_scaling_info.get("vdu-delete"),
7744 mark_delete=True,
7745 )
tierno2357f4e2020-10-19 16:38:59 +00007746 # db_vnfr has been updated, update db_vnfrs to use it
7747 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007748 await self._instantiate_ng_ro(
7749 logging_text,
7750 nsr_id,
7751 db_nsd,
7752 db_nsr,
7753 db_nslcmop,
7754 db_vnfrs,
7755 db_vnfds,
7756 n2vc_key_list,
7757 stage=stage,
7758 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007759 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007760 )
tierno2357f4e2020-10-19 16:38:59 +00007761 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007762 self.scale_vnfr(
7763 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7764 )
tierno2357f4e2020-10-19 16:38:59 +00007765
bravof73bac502021-05-11 07:38:47 -04007766 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007767 self,
7768 ee_id: str,
7769 artifact_path: str,
7770 ee_config_descriptor: dict,
7771 vnfr_id: str,
7772 nsr_id: str,
7773 target_ip: str,
7774 element_type: str,
7775 vnf_member_index: str = "",
7776 vdu_id: str = "",
7777 vdu_index: int = None,
7778 kdu_name: str = "",
7779 kdu_index: int = None,
7780 ) -> dict:
7781 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7782 This method will wait until the corresponding VDU or KDU is fully instantiated
7783
7784 Args:
7785 ee_id (str): Execution Environment ID
7786 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7787 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7788 vnfr_id (str): VNFR ID where this EE applies
7789 nsr_id (str): NSR ID where this EE applies
7790 target_ip (str): VDU/KDU instance IP address
7791 element_type (str): NS or VNF or VDU or KDU
7792 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7793 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7794 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7795 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7796 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7797
7798 Raises:
7799 LcmException: When the VDU or KDU instance was not found in an hour
7800
7801 Returns:
7802 _type_: Prometheus jobs
7803 """
7804 # default the vdur and kdur names to an empty string, to avoid any later
7805 # problem with Prometheus when the element type is not VDU or KDU
7806 vdur_name = ""
7807 kdur_name = ""
7808
tiernob996d942020-07-03 14:52:28 +00007809 # look if exist a file called 'prometheus*.j2' and
7810 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007811 job_file = next(
7812 (
7813 f
7814 for f in artifact_content
7815 if f.startswith("prometheus") and f.endswith(".j2")
7816 ),
7817 None,
7818 )
tiernob996d942020-07-03 14:52:28 +00007819 if not job_file:
7820 return
k4.rahul74944982023-04-19 17:00:52 +05307821 self.logger.debug("Artifact path{}".format(artifact_path))
7822 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007823 with self.fs.file_open((artifact_path, job_file), "r") as f:
7824 job_data = f.read()
7825
Pedro Escaleira120695e2022-06-11 21:17:26 +01007826 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7827 if element_type in ("VDU", "KDU"):
7828 for _ in range(360):
7829 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7830 if vdu_id and vdu_index is not None:
7831 vdur = next(
7832 (
7833 x
7834 for x in get_iterable(db_vnfr, "vdur")
7835 if (
7836 x.get("vdu-id-ref") == vdu_id
7837 and x.get("count-index") == vdu_index
7838 )
7839 ),
7840 {},
7841 )
7842 if vdur.get("name"):
7843 vdur_name = vdur.get("name")
7844 break
7845 if kdu_name and kdu_index is not None:
7846 kdur = next(
7847 (
7848 x
7849 for x in get_iterable(db_vnfr, "kdur")
7850 if (
7851 x.get("kdu-name") == kdu_name
7852 and x.get("count-index") == kdu_index
7853 )
7854 ),
7855 {},
7856 )
7857 if kdur.get("name"):
7858 kdur_name = kdur.get("name")
7859 break
7860
Gabriel Cubae7898982023-05-11 01:57:21 -05007861 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007862 else:
7863 if vdu_id and vdu_index is not None:
7864 raise LcmException(
7865 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7866 )
7867 if kdu_name and kdu_index is not None:
7868 raise LcmException(
7869 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7870 )
7871
k4.rahul74944982023-04-19 17:00:52 +05307872 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007873 _, namespace, helm_id = get_ee_id_parts(
7874 ee_id
7875 ) # get namespace and EE gRPC service name
7876 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307877 host_port = "80"
7878 vnfr_id = vnfr_id.replace("-", "")
7879 variables = {
7880 "JOB_NAME": vnfr_id,
7881 "TARGET_IP": target_ip,
7882 "EXPORTER_POD_IP": host_name,
7883 "EXPORTER_POD_PORT": host_port,
7884 "NSR_ID": nsr_id,
7885 "VNF_MEMBER_INDEX": vnf_member_index,
7886 "VDUR_NAME": vdur_name,
7887 "KDUR_NAME": kdur_name,
7888 "ELEMENT_TYPE": element_type,
7889 }
7890 else:
7891 metric_path = ee_config_descriptor["metric-path"]
7892 target_port = ee_config_descriptor["metric-port"]
7893 vnfr_id = vnfr_id.replace("-", "")
7894 variables = {
7895 "JOB_NAME": vnfr_id,
7896 "TARGET_IP": target_ip,
7897 "TARGET_PORT": target_port,
7898 "METRIC_PATH": metric_path,
7899 }
7900
bravof73bac502021-05-11 07:38:47 -04007901 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007902 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7903 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007904 if (
7905 not isinstance(job.get("job_name"), str)
7906 or vnfr_id not in job["job_name"]
7907 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307908 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007909 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007910 job["vnfr_id"] = vnfr_id
7911 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007912
preethika.p28b0bf82022-09-23 07:36:28 +00007913 async def rebuild_start_stop(
7914 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7915 ):
k4.rahulb827de92022-05-02 16:35:02 +00007916 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7917 self.logger.info(logging_text + "Enter")
7918 stage = ["Preparing the environment", ""]
7919 # database nsrs record
7920 db_nsr_update = {}
7921 vdu_vim_name = None
7922 vim_vm_id = None
7923 # in case of error, indicates what part of scale was failed to put nsr at error status
7924 start_deploy = time()
7925 try:
7926 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7927 vim_account_id = db_vnfr.get("vim-account-id")
7928 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007929 vdu_id = additional_param["vdu_id"]
7930 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007931 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007932 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007933 )
k4.rahulb827de92022-05-02 16:35:02 +00007934 if vdur:
7935 vdu_vim_name = vdur["name"]
7936 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7937 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007938 else:
7939 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007940 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7941 # wait for any previous tasks in process
7942 stage[1] = "Waiting for previous operations to terminate"
7943 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007944 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007945
7946 stage[1] = "Reading from database."
7947 self.logger.info(stage[1])
7948 self._write_ns_status(
7949 nsr_id=nsr_id,
7950 ns_state=None,
7951 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007952 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007953 )
7954 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7955
7956 # read from db: ns
7957 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7958 db_nsr_update["operational-status"] = operation_type
7959 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7960 # Payload for RO
7961 desc = {
7962 operation_type: {
7963 "vim_vm_id": vim_vm_id,
7964 "vnf_id": vnf_id,
7965 "vdu_index": additional_param["count-index"],
7966 "vdu_id": vdur["id"],
7967 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007968 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007969 }
7970 }
7971 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7972 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7973 self.logger.info("ro nsr id: {}".format(nsr_id))
7974 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7975 self.logger.info("response from RO: {}".format(result_dict))
7976 action_id = result_dict["action_id"]
7977 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007978 nsr_id,
7979 action_id,
7980 nslcmop_id,
7981 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007982 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007983 None,
7984 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007985 )
7986 return "COMPLETED", "Done"
7987 except (ROclient.ROClientException, DbException, LcmException) as e:
7988 self.logger.error("Exit Exception {}".format(e))
7989 exc = e
7990 except asyncio.CancelledError:
7991 self.logger.error("Cancelled Exception while '{}'".format(stage))
7992 exc = "Operation was cancelled"
7993 except Exception as e:
7994 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007995 self.logger.critical(
7996 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7997 )
k4.rahulb827de92022-05-02 16:35:02 +00007998 return "FAILED", "Error in operate VNF {}".format(exc)
7999
elumalai80bcf1c2022-04-28 18:05:01 +05308000 async def migrate(self, nsr_id, nslcmop_id):
8001 """
8002 Migrate VNFs and VDUs instances in a NS
8003
8004 :param: nsr_id: NS Instance ID
8005 :param: nslcmop_id: nslcmop ID of migrate
8006
8007 """
8008 # Try to lock HA task here
8009 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8010 if not task_is_locked_by_me:
8011 return
8012 logging_text = "Task ns={} migrate ".format(nsr_id)
8013 self.logger.debug(logging_text + "Enter")
8014 # get all needed from database
8015 db_nslcmop = None
8016 db_nslcmop_update = {}
8017 nslcmop_operation_state = None
8018 db_nsr_update = {}
8019 target = {}
8020 exc = None
8021 # in case of error, indicates what part of scale was failed to put nsr at error status
8022 start_deploy = time()
8023
8024 try:
8025 # wait for any previous tasks in process
8026 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03008027 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05308028
8029 self._write_ns_status(
8030 nsr_id=nsr_id,
8031 ns_state=None,
8032 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03008033 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05308034 )
8035 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03008036 self.logger.debug(
8037 step + " after having waited for previous tasks to be completed"
8038 )
elumalai80bcf1c2022-04-28 18:05:01 +05308039 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8040 migrate_params = db_nslcmop.get("operationParams")
8041
8042 target = {}
8043 target.update(migrate_params)
Pedro Pereirab6cccb22024-08-23 10:23:02 +01008044
8045 if "migrateToHost" in target:
8046 desc = await self.RO.migrate(nsr_id, target)
8047 self.logger.debug("RO return > {}".format(desc))
8048 action_id = desc["action_id"]
8049 await self._wait_ng_ro(
8050 nsr_id,
8051 action_id,
8052 nslcmop_id,
8053 start_deploy,
8054 self.timeout.migrate,
8055 operation="migrate",
8056 )
8057
8058 elif "targetHostK8sLabels" in target:
8059 await self.k8sclusterhelm3.migrate(nsr_id, target)
8060
elumalai80bcf1c2022-04-28 18:05:01 +05308061 except (ROclient.ROClientException, DbException, LcmException) as e:
8062 self.logger.error("Exit Exception {}".format(e))
8063 exc = e
8064 except asyncio.CancelledError:
8065 self.logger.error("Cancelled Exception while '{}'".format(step))
8066 exc = "Operation was cancelled"
8067 except Exception as e:
8068 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03008069 self.logger.critical(
8070 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8071 )
elumalai80bcf1c2022-04-28 18:05:01 +05308072 finally:
8073 self._write_ns_status(
8074 nsr_id=nsr_id,
8075 ns_state=None,
8076 current_operation="IDLE",
8077 current_operation_id=None,
8078 )
8079 if exc:
aticig349aa462022-05-19 12:29:35 +03008080 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308081 nslcmop_operation_state = "FAILED"
8082 else:
8083 nslcmop_operation_state = "COMPLETED"
8084 db_nslcmop_update["detailed-status"] = "Done"
8085 db_nsr_update["detailed-status"] = "Done"
8086
8087 self._write_op_status(
8088 op_id=nslcmop_id,
8089 stage="",
8090 error_message="",
8091 operation_state=nslcmop_operation_state,
8092 other_update=db_nslcmop_update,
8093 )
8094 if nslcmop_operation_state:
8095 try:
8096 msg = {
8097 "nsr_id": nsr_id,
8098 "nslcmop_id": nslcmop_id,
8099 "operationState": nslcmop_operation_state,
8100 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008101 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308102 except Exception as e:
8103 self.logger.error(
8104 logging_text + "kafka_write notification Exception {}".format(e)
8105 )
8106 self.logger.debug(logging_text + "Exit")
8107 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008108
garciadeblas07f4e4c2022-06-09 09:42:58 +02008109 async def heal(self, nsr_id, nslcmop_id):
8110 """
8111 Heal NS
8112
8113 :param nsr_id: ns instance to heal
8114 :param nslcmop_id: operation to run
8115 :return:
8116 """
8117
8118 # Try to lock HA task here
8119 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8120 if not task_is_locked_by_me:
8121 return
8122
8123 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8124 stage = ["", "", ""]
8125 tasks_dict_info = {}
8126 # ^ stage, step, VIM progress
8127 self.logger.debug(logging_text + "Enter")
8128 # get all needed from database
8129 db_nsr = None
8130 db_nslcmop_update = {}
8131 db_nsr_update = {}
8132 db_vnfrs = {} # vnf's info indexed by _id
8133 exc = None
8134 old_operational_status = ""
8135 old_config_status = ""
8136 nsi_id = None
8137 try:
8138 # wait for any previous tasks in process
8139 step = "Waiting for previous operations to terminate"
8140 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8141 self._write_ns_status(
8142 nsr_id=nsr_id,
8143 ns_state=None,
8144 current_operation="HEALING",
8145 current_operation_id=nslcmop_id,
8146 )
8147
8148 step = "Getting nslcmop from database"
8149 self.logger.debug(
8150 step + " after having waited for previous tasks to be completed"
8151 )
8152 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8153
8154 step = "Getting nsr from database"
8155 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8156 old_operational_status = db_nsr["operational-status"]
8157 old_config_status = db_nsr["config-status"]
8158
8159 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008160 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008161 "_admin.deployed.RO.operational-status": "healing",
8162 }
8163 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8164
8165 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008166 await self.heal_RO(
8167 logging_text=logging_text,
8168 nsr_id=nsr_id,
8169 db_nslcmop=db_nslcmop,
8170 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008171 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008172 # VCA tasks
8173 # read from db: nsd
8174 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8175 self.logger.debug(logging_text + stage[1])
8176 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8177 self.fs.sync(db_nsr["nsd-id"])
8178 db_nsr["nsd"] = nsd
8179 # read from db: vnfr's of this ns
8180 step = "Getting vnfrs from db"
8181 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8182 for vnfr in db_vnfrs_list:
8183 db_vnfrs[vnfr["_id"]] = vnfr
8184 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8185
8186 # Check for each target VNF
8187 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8188 for target_vnf in target_list:
8189 # Find this VNF in the list from DB
8190 vnfr_id = target_vnf.get("vnfInstanceId", None)
8191 if vnfr_id:
8192 db_vnfr = db_vnfrs[vnfr_id]
8193 vnfd_id = db_vnfr.get("vnfd-id")
8194 vnfd_ref = db_vnfr.get("vnfd-ref")
8195 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8196 base_folder = vnfd["_admin"]["storage"]
8197 vdu_id = None
8198 vdu_index = 0
8199 vdu_name = None
8200 kdu_name = None
8201 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8202 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8203
8204 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008205 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8206 "vdu", []
8207 )
garciadeblas50639832022-09-01 13:09:47 +02008208 if not target_vdu_list:
8209 # Codigo nuevo para crear diccionario
8210 target_vdu_list = []
8211 for existing_vdu in db_vnfr.get("vdur"):
8212 vdu_name = existing_vdu.get("vdu-name", None)
8213 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008214 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8215 "run-day1", False
8216 )
8217 vdu_to_be_healed = {
8218 "vdu-id": vdu_name,
8219 "count-index": vdu_index,
8220 "run-day1": vdu_run_day1,
8221 }
garciadeblas50639832022-09-01 13:09:47 +02008222 target_vdu_list.append(vdu_to_be_healed)
8223 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008224 deploy_params_vdu = target_vdu
8225 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008226 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8227 "additionalParams", {}
8228 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008229 deploy_params_vdu["run-day1"] = target_vnf[
8230 "additionalParams"
8231 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008232 vdu_name = target_vdu.get("vdu-id", None)
8233 # TODO: Get vdu_id from vdud.
8234 vdu_id = vdu_name
8235 # For multi instance VDU count-index is mandatory
8236 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008237 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008238
8239 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8240 stage[1] = "Deploying Execution Environments."
8241 self.logger.debug(logging_text + stage[1])
8242
8243 # VNF Level charm. Normal case when proxy charms.
8244 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8245 descriptor_config = get_configuration(vnfd, vnfd_ref)
8246 if descriptor_config:
8247 # Continue if healed machine is management machine
8248 vnf_ip_address = db_vnfr.get("ip-address")
8249 target_instance = None
8250 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008251 if (
8252 instance["vdu-name"] == vdu_name
8253 and instance["count-index"] == vdu_index
8254 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008255 target_instance = instance
8256 break
8257 if vnf_ip_address == target_instance.get("ip-address"):
8258 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008259 logging_text=logging_text
8260 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8261 member_vnf_index, vdu_name, vdu_index
8262 ),
8263 db_nsr=db_nsr,
8264 db_vnfr=db_vnfr,
8265 nslcmop_id=nslcmop_id,
8266 nsr_id=nsr_id,
8267 nsi_id=nsi_id,
8268 vnfd_id=vnfd_ref,
8269 vdu_id=None,
8270 kdu_name=None,
8271 member_vnf_index=member_vnf_index,
8272 vdu_index=0,
8273 vdu_name=None,
8274 deploy_params=deploy_params_vdu,
8275 descriptor_config=descriptor_config,
8276 base_folder=base_folder,
8277 task_instantiation_info=tasks_dict_info,
8278 stage=stage,
8279 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008280
8281 # VDU Level charm. Normal case with native charms.
8282 descriptor_config = get_configuration(vnfd, vdu_name)
8283 if descriptor_config:
8284 self._heal_n2vc(
8285 logging_text=logging_text
8286 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8287 member_vnf_index, vdu_name, vdu_index
8288 ),
8289 db_nsr=db_nsr,
8290 db_vnfr=db_vnfr,
8291 nslcmop_id=nslcmop_id,
8292 nsr_id=nsr_id,
8293 nsi_id=nsi_id,
8294 vnfd_id=vnfd_ref,
8295 vdu_id=vdu_id,
8296 kdu_name=kdu_name,
8297 member_vnf_index=member_vnf_index,
8298 vdu_index=vdu_index,
8299 vdu_name=vdu_name,
8300 deploy_params=deploy_params_vdu,
8301 descriptor_config=descriptor_config,
8302 base_folder=base_folder,
8303 task_instantiation_info=tasks_dict_info,
8304 stage=stage,
8305 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008306 except (
8307 ROclient.ROClientException,
8308 DbException,
8309 LcmException,
8310 NgRoException,
8311 ) as e:
8312 self.logger.error(logging_text + "Exit Exception {}".format(e))
8313 exc = e
8314 except asyncio.CancelledError:
8315 self.logger.error(
8316 logging_text + "Cancelled Exception while '{}'".format(step)
8317 )
8318 exc = "Operation was cancelled"
8319 except Exception as e:
8320 exc = traceback.format_exc()
8321 self.logger.critical(
8322 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8323 exc_info=True,
8324 )
8325 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008326 error_list = list()
36970544ef442024-04-01 10:58:42 +00008327 if db_vnfrs_list and target_list:
8328 for vnfrs in db_vnfrs_list:
8329 for vnf_instance in target_list:
8330 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8331 self.db.set_list(
8332 "vnfrs",
8333 {"_id": vnfrs["_id"]},
8334 {"_admin.modified": time()},
8335 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008336 if exc:
8337 error_list.append(str(exc))
8338 try:
8339 if tasks_dict_info:
8340 stage[1] = "Waiting for healing pending tasks."
8341 self.logger.debug(logging_text + stage[1])
8342 exc = await self._wait_for_tasks(
8343 logging_text,
8344 tasks_dict_info,
8345 self.timeout.ns_deploy,
8346 stage,
8347 nslcmop_id,
8348 nsr_id=nsr_id,
8349 )
8350 except asyncio.CancelledError:
8351 error_list.append("Cancelled")
8352 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8353 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008354 logging_text,
8355 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008356 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008357 stage,
8358 nslcmop_id,
8359 nsr_id=nsr_id,
8360 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008361 if error_list:
8362 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008363 db_nslcmop_update[
8364 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008365 ] = error_description_nslcmop = "FAILED {}: {}".format(
8366 step, error_detail
8367 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008368 nslcmop_operation_state = "FAILED"
8369 if db_nsr:
8370 db_nsr_update["operational-status"] = old_operational_status
8371 db_nsr_update["config-status"] = old_config_status
8372 db_nsr_update[
8373 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008374 ] = "FAILED healing nslcmop={} {}: {}".format(
8375 nslcmop_id, step, error_detail
8376 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008377 for task, task_name in tasks_dict_info.items():
8378 if not task.done() or task.cancelled() or task.exception():
8379 if task_name.startswith(self.task_name_deploy_vca):
8380 # A N2VC task is pending
8381 db_nsr_update["config-status"] = "failed"
8382 else:
8383 # RO task is pending
8384 db_nsr_update["operational-status"] = "failed"
8385 else:
8386 error_description_nslcmop = None
8387 nslcmop_operation_state = "COMPLETED"
8388 db_nslcmop_update["detailed-status"] = "Done"
8389 db_nsr_update["detailed-status"] = "Done"
8390 db_nsr_update["operational-status"] = "running"
8391 db_nsr_update["config-status"] = "configured"
8392
8393 self._write_op_status(
8394 op_id=nslcmop_id,
8395 stage="",
8396 error_message=error_description_nslcmop,
8397 operation_state=nslcmop_operation_state,
8398 other_update=db_nslcmop_update,
8399 )
8400 if db_nsr:
8401 self._write_ns_status(
8402 nsr_id=nsr_id,
8403 ns_state=None,
8404 current_operation="IDLE",
8405 current_operation_id=None,
8406 other_update=db_nsr_update,
8407 )
8408
8409 if nslcmop_operation_state:
8410 try:
8411 msg = {
8412 "nsr_id": nsr_id,
8413 "nslcmop_id": nslcmop_id,
8414 "operationState": nslcmop_operation_state,
8415 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008416 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008417 except Exception as e:
8418 self.logger.error(
8419 logging_text + "kafka_write notification Exception {}".format(e)
8420 )
8421 self.logger.debug(logging_text + "Exit")
8422 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8423
8424 async def heal_RO(
8425 self,
8426 logging_text,
8427 nsr_id,
8428 db_nslcmop,
8429 stage,
8430 ):
8431 """
8432 Heal at RO
8433 :param logging_text: preffix text to use at logging
8434 :param nsr_id: nsr identity
8435 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8436 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8437 :return: None or exception
8438 """
preethika.p28b0bf82022-09-23 07:36:28 +00008439
garciadeblas07f4e4c2022-06-09 09:42:58 +02008440 def get_vim_account(vim_account_id):
Anirudh Gupta77b50a02025-05-13 05:53:38 +00008441 # nonlocal db_vims
garciadeblas07f4e4c2022-06-09 09:42:58 +02008442 if vim_account_id in db_vims:
8443 return db_vims[vim_account_id]
8444 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8445 db_vims[vim_account_id] = db_vim
8446 return db_vim
8447
8448 try:
8449 start_heal = time()
8450 ns_params = db_nslcmop.get("operationParams")
8451 if ns_params and ns_params.get("timeout_ns_heal"):
8452 timeout_ns_heal = ns_params["timeout_ns_heal"]
8453 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008454 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008455
8456 db_vims = {}
8457
8458 nslcmop_id = db_nslcmop["_id"]
8459 target = {
8460 "action_id": nslcmop_id,
8461 }
preethika.p28b0bf82022-09-23 07:36:28 +00008462 self.logger.warning(
8463 "db_nslcmop={} and timeout_ns_heal={}".format(
8464 db_nslcmop, timeout_ns_heal
8465 )
8466 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008467 target.update(db_nslcmop.get("operationParams", {}))
8468
8469 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8470 desc = await self.RO.recreate(nsr_id, target)
8471 self.logger.debug("RO return > {}".format(desc))
8472 action_id = desc["action_id"]
8473 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8474 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008475 nsr_id,
8476 action_id,
8477 nslcmop_id,
8478 start_heal,
8479 timeout_ns_heal,
8480 stage,
8481 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008482 )
8483
8484 # Updating NSR
8485 db_nsr_update = {
8486 "_admin.deployed.RO.operational-status": "running",
8487 "detailed-status": " ".join(stage),
8488 }
8489 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8490 self._write_op_status(nslcmop_id, stage)
8491 self.logger.debug(
8492 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8493 )
8494
8495 except Exception as e:
8496 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008497 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008498 self.logger.error(
8499 "Error healing at VIM {}".format(e),
8500 exc_info=not isinstance(
8501 e,
8502 (
8503 ROclient.ROClientException,
8504 LcmException,
8505 DbException,
8506 NgRoException,
8507 ),
8508 ),
8509 )
8510 raise
8511
8512 def _heal_n2vc(
8513 self,
8514 logging_text,
8515 db_nsr,
8516 db_vnfr,
8517 nslcmop_id,
8518 nsr_id,
8519 nsi_id,
8520 vnfd_id,
8521 vdu_id,
8522 kdu_name,
8523 member_vnf_index,
8524 vdu_index,
8525 vdu_name,
8526 deploy_params,
8527 descriptor_config,
8528 base_folder,
8529 task_instantiation_info,
8530 stage,
8531 ):
8532 # launch instantiate_N2VC in a asyncio task and register task object
8533 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8534 # if not found, create one entry and update database
8535 # fill db_nsr._admin.deployed.VCA.<index>
8536
8537 self.logger.debug(
8538 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8539 )
aticig9bc63ac2022-07-27 09:32:06 +03008540
8541 charm_name = ""
8542 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008543 if "execution-environment-list" in descriptor_config:
8544 ee_list = descriptor_config.get("execution-environment-list", [])
8545 elif "juju" in descriptor_config:
8546 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008547 if "execution-environment-list" not in descriptor_config:
8548 # charm name is only required for ns charms
8549 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008550 else: # other types as script are not supported
8551 ee_list = []
8552
8553 for ee_item in ee_list:
8554 self.logger.debug(
8555 logging_text
8556 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8557 ee_item.get("juju"), ee_item.get("helm-chart")
8558 )
8559 )
8560 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008561 vca_name, charm_name, vca_type = self.get_vca_info(
8562 ee_item, db_nsr, get_charm_name
8563 )
8564 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008565 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008566 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008567 )
8568 continue
8569
8570 vca_index = -1
8571 for vca_index, vca_deployed in enumerate(
8572 db_nsr["_admin"]["deployed"]["VCA"]
8573 ):
8574 if not vca_deployed:
8575 continue
8576 if (
8577 vca_deployed.get("member-vnf-index") == member_vnf_index
8578 and vca_deployed.get("vdu_id") == vdu_id
8579 and vca_deployed.get("kdu_name") == kdu_name
8580 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8581 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8582 ):
8583 break
8584 else:
8585 # not found, create one.
8586 target = (
8587 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8588 )
8589 if vdu_id:
8590 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8591 elif kdu_name:
8592 target += "/kdu/{}".format(kdu_name)
8593 vca_deployed = {
8594 "target_element": target,
8595 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8596 "member-vnf-index": member_vnf_index,
8597 "vdu_id": vdu_id,
8598 "kdu_name": kdu_name,
8599 "vdu_count_index": vdu_index,
8600 "operational-status": "init", # TODO revise
8601 "detailed-status": "", # TODO revise
8602 "step": "initial-deploy", # TODO revise
8603 "vnfd_id": vnfd_id,
8604 "vdu_name": vdu_name,
8605 "type": vca_type,
8606 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008607 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008608 }
8609 vca_index += 1
8610
8611 # create VCA and configurationStatus in db
8612 db_dict = {
8613 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8614 "configurationStatus.{}".format(vca_index): dict(),
8615 }
8616 self.update_db_2("nsrs", nsr_id, db_dict)
8617
8618 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8619
8620 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8621 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8622 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8623
8624 # Launch task
8625 task_n2vc = asyncio.ensure_future(
8626 self.heal_N2VC(
8627 logging_text=logging_text,
8628 vca_index=vca_index,
8629 nsi_id=nsi_id,
8630 db_nsr=db_nsr,
8631 db_vnfr=db_vnfr,
8632 vdu_id=vdu_id,
8633 kdu_name=kdu_name,
8634 vdu_index=vdu_index,
8635 deploy_params=deploy_params,
8636 config_descriptor=descriptor_config,
8637 base_folder=base_folder,
8638 nslcmop_id=nslcmop_id,
8639 stage=stage,
8640 vca_type=vca_type,
8641 vca_name=vca_name,
8642 ee_config_descriptor=ee_item,
8643 )
8644 )
8645 self.lcm_tasks.register(
8646 "ns",
8647 nsr_id,
8648 nslcmop_id,
8649 "instantiate_N2VC-{}".format(vca_index),
8650 task_n2vc,
8651 )
8652 task_instantiation_info[
8653 task_n2vc
8654 ] = self.task_name_deploy_vca + " {}.{}".format(
8655 member_vnf_index or "", vdu_id or ""
8656 )
8657
8658 async def heal_N2VC(
8659 self,
8660 logging_text,
8661 vca_index,
8662 nsi_id,
8663 db_nsr,
8664 db_vnfr,
8665 vdu_id,
8666 kdu_name,
8667 vdu_index,
8668 config_descriptor,
8669 deploy_params,
8670 base_folder,
8671 nslcmop_id,
8672 stage,
8673 vca_type,
8674 vca_name,
8675 ee_config_descriptor,
8676 ):
8677 nsr_id = db_nsr["_id"]
8678 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8679 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8680 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8681 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8682 db_dict = {
8683 "collection": "nsrs",
8684 "filter": {"_id": nsr_id},
8685 "path": db_update_entry,
8686 }
8687 step = ""
8688 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008689 element_type = "NS"
8690 element_under_configuration = nsr_id
8691
8692 vnfr_id = None
8693 if db_vnfr:
8694 vnfr_id = db_vnfr["_id"]
8695 osm_config["osm"]["vnf_id"] = vnfr_id
8696
8697 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8698
8699 if vca_type == "native_charm":
8700 index_number = 0
8701 else:
8702 index_number = vdu_index or 0
8703
8704 if vnfr_id:
8705 element_type = "VNF"
8706 element_under_configuration = vnfr_id
8707 namespace += ".{}-{}".format(vnfr_id, index_number)
8708 if vdu_id:
8709 namespace += ".{}-{}".format(vdu_id, index_number)
8710 element_type = "VDU"
8711 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8712 osm_config["osm"]["vdu_id"] = vdu_id
8713 elif kdu_name:
8714 namespace += ".{}".format(kdu_name)
8715 element_type = "KDU"
8716 element_under_configuration = kdu_name
8717 osm_config["osm"]["kdu_name"] = kdu_name
8718
8719 # Get artifact path
8720 if base_folder["pkg-dir"]:
8721 artifact_path = "{}/{}/{}/{}".format(
8722 base_folder["folder"],
8723 base_folder["pkg-dir"],
8724 "charms"
8725 if vca_type
8726 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8727 else "helm-charts",
8728 vca_name,
8729 )
8730 else:
8731 artifact_path = "{}/Scripts/{}/{}/".format(
8732 base_folder["folder"],
8733 "charms"
8734 if vca_type
8735 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8736 else "helm-charts",
8737 vca_name,
8738 )
8739
8740 self.logger.debug("Artifact path > {}".format(artifact_path))
8741
8742 # get initial_config_primitive_list that applies to this element
8743 initial_config_primitive_list = config_descriptor.get(
8744 "initial-config-primitive"
8745 )
8746
8747 self.logger.debug(
8748 "Initial config primitive list > {}".format(
8749 initial_config_primitive_list
8750 )
8751 )
8752
8753 # add config if not present for NS charm
8754 ee_descriptor_id = ee_config_descriptor.get("id")
8755 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8756 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8757 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8758 )
8759
8760 self.logger.debug(
8761 "Initial config primitive list #2 > {}".format(
8762 initial_config_primitive_list
8763 )
8764 )
8765 # n2vc_redesign STEP 3.1
8766 # find old ee_id if exists
8767 ee_id = vca_deployed.get("ee_id")
8768
8769 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8770 # create or register execution environment in VCA. Only for native charms when healing
8771 if vca_type == "native_charm":
8772 step = "Waiting to VM being up and getting IP address"
8773 self.logger.debug(logging_text + step)
8774 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8775 logging_text,
8776 nsr_id,
8777 vnfr_id,
8778 vdu_id,
8779 vdu_index,
8780 user=None,
8781 pub_key=None,
8782 )
8783 credentials = {"hostname": rw_mgmt_ip}
8784 # get username
8785 username = deep_get(
8786 config_descriptor, ("config-access", "ssh-access", "default-user")
8787 )
8788 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8789 # merged. Meanwhile let's get username from initial-config-primitive
8790 if not username and initial_config_primitive_list:
8791 for config_primitive in initial_config_primitive_list:
8792 for param in config_primitive.get("parameter", ()):
8793 if param["name"] == "ssh-username":
8794 username = param["value"]
8795 break
8796 if not username:
8797 raise LcmException(
8798 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8799 "'config-access.ssh-access.default-user'"
8800 )
8801 credentials["username"] = username
8802
8803 # n2vc_redesign STEP 3.2
8804 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8805 self._write_configuration_status(
8806 nsr_id=nsr_id,
8807 vca_index=vca_index,
8808 status="REGISTERING",
8809 element_under_configuration=element_under_configuration,
8810 element_type=element_type,
8811 )
8812
8813 step = "register execution environment {}".format(credentials)
8814 self.logger.debug(logging_text + step)
8815 ee_id = await self.vca_map[vca_type].register_execution_environment(
8816 credentials=credentials,
8817 namespace=namespace,
8818 db_dict=db_dict,
8819 vca_id=vca_id,
8820 )
8821
8822 # update ee_id en db
8823 db_dict_ee_id = {
8824 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8825 }
8826 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8827
8828 # for compatibility with MON/POL modules, the need model and application name at database
8829 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8830 # Not sure if this need to be done when healing
8831 """
8832 ee_id_parts = ee_id.split(".")
8833 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8834 if len(ee_id_parts) >= 2:
8835 model_name = ee_id_parts[0]
8836 application_name = ee_id_parts[1]
8837 db_nsr_update[db_update_entry + "model"] = model_name
8838 db_nsr_update[db_update_entry + "application"] = application_name
8839 """
8840
8841 # n2vc_redesign STEP 3.3
8842 # Install configuration software. Only for native charms.
8843 step = "Install configuration Software"
8844
8845 self._write_configuration_status(
8846 nsr_id=nsr_id,
8847 vca_index=vca_index,
8848 status="INSTALLING SW",
8849 element_under_configuration=element_under_configuration,
8850 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008851 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008852 other_update=None,
8853 )
8854
8855 # TODO check if already done
8856 self.logger.debug(logging_text + step)
8857 config = None
8858 if vca_type == "native_charm":
8859 config_primitive = next(
8860 (p for p in initial_config_primitive_list if p["name"] == "config"),
8861 None,
8862 )
8863 if config_primitive:
8864 config = self._map_primitive_params(
8865 config_primitive, {}, deploy_params
8866 )
8867 await self.vca_map[vca_type].install_configuration_sw(
8868 ee_id=ee_id,
8869 artifact_path=artifact_path,
8870 db_dict=db_dict,
8871 config=config,
8872 num_units=1,
8873 vca_id=vca_id,
8874 vca_type=vca_type,
8875 )
8876
8877 # write in db flag of configuration_sw already installed
8878 self.update_db_2(
8879 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8880 )
8881
8882 # Not sure if this need to be done when healing
8883 """
8884 # add relations for this VCA (wait for other peers related with this VCA)
8885 await self._add_vca_relations(
8886 logging_text=logging_text,
8887 nsr_id=nsr_id,
8888 vca_type=vca_type,
8889 vca_index=vca_index,
8890 )
8891 """
8892
8893 # if SSH access is required, then get execution environment SSH public
8894 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00008895 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008896 pub_key = None
8897 user = None
8898 # self.logger.debug("get ssh key block")
8899 if deep_get(
8900 config_descriptor, ("config-access", "ssh-access", "required")
8901 ):
8902 # self.logger.debug("ssh key needed")
8903 # Needed to inject a ssh key
8904 user = deep_get(
8905 config_descriptor,
8906 ("config-access", "ssh-access", "default-user"),
8907 )
8908 step = "Install configuration Software, getting public ssh key"
8909 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8910 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8911 )
8912
8913 step = "Insert public key into VM user={} ssh_key={}".format(
8914 user, pub_key
8915 )
8916 else:
8917 # self.logger.debug("no need to get ssh key")
8918 step = "Waiting to VM being up and getting IP address"
8919 self.logger.debug(logging_text + step)
8920
8921 # n2vc_redesign STEP 5.1
8922 # wait for RO (ip-address) Insert pub_key into VM
8923 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008924 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008925 if vnfr_id:
8926 if kdu_name:
8927 rw_mgmt_ip = await self.wait_kdu_up(
8928 logging_text, nsr_id, vnfr_id, kdu_name
8929 )
8930 else:
8931 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8932 logging_text,
8933 nsr_id,
8934 vnfr_id,
8935 vdu_id,
8936 vdu_index,
8937 user=user,
8938 pub_key=pub_key,
8939 )
8940 else:
8941 rw_mgmt_ip = None # This is for a NS configuration
8942
8943 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8944
8945 # store rw_mgmt_ip in deploy params for later replacement
8946 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8947
8948 # Day1 operations.
8949 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008950 runDay1 = deploy_params.get("run-day1", False)
8951 self.logger.debug(
8952 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8953 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008954 if runDay1:
8955 # n2vc_redesign STEP 6 Execute initial config primitive
8956 step = "execute initial config primitive"
8957
8958 # wait for dependent primitives execution (NS -> VNF -> VDU)
8959 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008960 await self._wait_dependent_n2vc(
8961 nsr_id, vca_deployed_list, vca_index
8962 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008963
8964 # stage, in function of element type: vdu, kdu, vnf or ns
8965 my_vca = vca_deployed_list[vca_index]
8966 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8967 # VDU or KDU
8968 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8969 elif my_vca.get("member-vnf-index"):
8970 # VNF
8971 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8972 else:
8973 # NS
8974 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8975
8976 self._write_configuration_status(
8977 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8978 )
8979
8980 self._write_op_status(op_id=nslcmop_id, stage=stage)
8981
8982 check_if_terminated_needed = True
8983 for initial_config_primitive in initial_config_primitive_list:
8984 # adding information on the vca_deployed if it is a NS execution environment
8985 if not vca_deployed["member-vnf-index"]:
8986 deploy_params["ns_config_info"] = json.dumps(
8987 self._get_ns_config_info(nsr_id)
8988 )
8989 # TODO check if already done
8990 primitive_params_ = self._map_primitive_params(
8991 initial_config_primitive, {}, deploy_params
8992 )
8993
8994 step = "execute primitive '{}' params '{}'".format(
8995 initial_config_primitive["name"], primitive_params_
8996 )
8997 self.logger.debug(logging_text + step)
8998 await self.vca_map[vca_type].exec_primitive(
8999 ee_id=ee_id,
9000 primitive_name=initial_config_primitive["name"],
9001 params_dict=primitive_params_,
9002 db_dict=db_dict,
9003 vca_id=vca_id,
9004 vca_type=vca_type,
9005 )
9006 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
9007 if check_if_terminated_needed:
9008 if config_descriptor.get("terminate-config-primitive"):
9009 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00009010 "nsrs",
9011 nsr_id,
9012 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02009013 )
9014 check_if_terminated_needed = False
9015
9016 # TODO register in database that primitive is done
9017
9018 # STEP 7 Configure metrics
9019 # Not sure if this need to be done when healing
9020 """
9021 if vca_type == "helm" or vca_type == "helm-v3":
9022 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
9023 ee_id=ee_id,
9024 artifact_path=artifact_path,
9025 ee_config_descriptor=ee_config_descriptor,
9026 vnfr_id=vnfr_id,
9027 nsr_id=nsr_id,
9028 target_ip=rw_mgmt_ip,
9029 )
9030 if prometheus_jobs:
9031 self.update_db_2(
9032 "nsrs",
9033 nsr_id,
9034 {db_update_entry + "prometheus_jobs": prometheus_jobs},
9035 )
9036
9037 for job in prometheus_jobs:
9038 self.db.set_one(
9039 "prometheus_jobs",
9040 {"job_name": job["job_name"]},
9041 job,
9042 upsert=True,
9043 fail_on_empty=False,
9044 )
9045
9046 """
9047 step = "instantiated at VCA"
9048 self.logger.debug(logging_text + step)
9049
9050 self._write_configuration_status(
9051 nsr_id=nsr_id, vca_index=vca_index, status="READY"
9052 )
9053
9054 except Exception as e: # TODO not use Exception but N2VC exception
9055 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
9056 if not isinstance(
9057 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
9058 ):
9059 self.logger.error(
9060 "Exception while {} : {}".format(step, e), exc_info=True
9061 )
9062 self._write_configuration_status(
9063 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
9064 )
9065 raise LcmException("{} {}".format(step, e)) from e
9066
9067 async def _wait_heal_ro(
9068 self,
9069 nsr_id,
9070 timeout=600,
9071 ):
9072 start_time = time()
9073 while time() <= start_time + timeout:
9074 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009075 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9076 "operational-status"
9077 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009078 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9079 if operational_status_ro != "healing":
9080 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009081 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009082 else: # timeout_ns_deploy
9083 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309084
9085 async def vertical_scale(self, nsr_id, nslcmop_id):
9086 """
9087 Vertical Scale the VDUs in a NS
9088
9089 :param: nsr_id: NS Instance ID
9090 :param: nslcmop_id: nslcmop ID of migrate
9091
9092 """
govindarajul4ff4b512022-05-02 20:02:41 +05309093 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05309094 self.logger.info(logging_text + "Enter")
9095 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05309096 # get all needed from database
9097 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05309098 db_nsr_update = {}
9099 target = {}
9100 exc = None
9101 # in case of error, indicates what part of scale was failed to put nsr at error status
9102 start_deploy = time()
9103
9104 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05309105 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9106 operationParams = db_nslcmop.get("operationParams")
9107 vertical_scale_data = operationParams["verticalScaleVnf"]
9108 vnfd_id = vertical_scale_data["vnfdId"]
9109 count_index = vertical_scale_data["countIndex"]
9110 vdu_id_ref = vertical_scale_data["vduId"]
9111 vnfr_id = vertical_scale_data["vnfInstanceId"]
9112 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9113 db_flavor = db_nsr.get("flavor")
9114 db_flavor_index = str(len(db_flavor))
9115
9116 def set_flavor_refrence_to_vdur(diff=0):
9117 """
9118 Utility function to add and remove the
9119 ref to new ns-flavor-id to vdurs
9120 :param: diff: default 0
9121 """
9122 q_filter = {}
9123 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9124 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9125 if (
9126 vdur.get("count-index") == count_index
9127 and vdur.get("vdu-id-ref") == vdu_id_ref
9128 ):
9129 filter_text = {
9130 "_id": vnfr_id,
9131 "vdur.count-index": count_index,
9132 "vdur.vdu-id-ref": vdu_id_ref,
9133 }
9134 q_filter.update(filter_text)
9135 db_update = {}
9136 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9137 int(db_flavor_index) - diff
9138 )
9139 self.db.set_one(
9140 "vnfrs",
9141 q_filter=q_filter,
9142 update_dict=db_update,
9143 fail_on_empty=True,
9144 )
9145
govindarajul4ff4b512022-05-02 20:02:41 +05309146 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309147 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009148 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309149
9150 self._write_ns_status(
9151 nsr_id=nsr_id,
9152 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309153 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009154 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309155 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309156 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009157 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309158 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009159 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309160 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9161 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9162 virtual_compute = vnfd["virtual-compute-desc"][0]
9163 virtual_memory = round(
9164 float(virtual_compute["virtual-memory"]["size"]) * 1024
9165 )
9166 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9167 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009168 flavor_dict_update = {
9169 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309170 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009171 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309172 "storage-gb": str(virtual_storage),
9173 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009174 }
9175 db_flavor.append(flavor_dict_update)
9176 db_update = {}
9177 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309178 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009179 "_id": nsr_id,
9180 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309181 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009182 self.db.set_one(
9183 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309184 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009185 update_dict=db_update,
9186 fail_on_empty=True,
9187 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309188 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309189 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309190 new_operationParams = {
9191 "lcmOperationType": "verticalscale",
9192 "verticalScale": "CHANGE_VNFFLAVOR",
9193 "nsInstanceId": nsr_id,
9194 "changeVnfFlavorData": {
9195 "vnfInstanceId": vnfr_id,
9196 "additionalParams": {
9197 "vduid": vdu_id_ref,
9198 "vduCountIndex": count_index,
9199 "virtualMemory": virtual_memory,
9200 "numVirtualCpu": int(virtual_cpu),
9201 "sizeOfStorage": int(virtual_storage),
9202 },
9203 },
9204 }
9205 target.update(new_operationParams)
9206
9207 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9208 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9209 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309210 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309211 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309212 action_id = desc["action_id"]
9213 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009214 nsr_id,
9215 action_id,
9216 nslcmop_id,
9217 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009218 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009219 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309220 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009221 except (
9222 NgRoException,
9223 ROclient.ROClientException,
9224 DbException,
9225 LcmException,
9226 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309227 self.logger.error("Exit Exception {}".format(e))
9228 exc = e
9229 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309230 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309231 exc = "Operation was cancelled"
9232 except Exception as e:
9233 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009234 self.logger.critical(
9235 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9236 )
govindarajul4ff4b512022-05-02 20:02:41 +05309237 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309238 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009239 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309240 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009241 )
9242 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309243 "nsrs",
9244 {"_id": nsr_id},
9245 None,
9246 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009247 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309248 set_flavor_refrence_to_vdur(diff=1)
9249 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9250 else:
9251 return "COMPLETED", "Done"