blob: 3a10364076f984ddd4e0171e97d9685d6bb25a50 [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
David Garciab4ebcd02021-10-28 02:00:43 +0200101from n2vc.definitions import RelationEndpoint
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000102from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -0500103from 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
quilesj7e13aeb2019-10-08 13:34:55 +0200116from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000117from 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):
693 nonlocal db_vims
694 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 )
tierno2357f4e2020-10-19 16:38:59 +00001079 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001080
1081 # flavor
1082 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001083 if target_vim not in ns_flavor["vim_info"]:
1084 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001085
1086 # deal with images
1087 # in case alternative images are provided we must check if they should be applied
1088 # for the vim_type, modify the vim_type taking into account
1089 ns_image_id = int(vdur["ns-image-id"])
1090 if vdur.get("alt-image-ids"):
1091 db_vim = get_vim_account(vnfr["vim-account-id"])
1092 vim_type = db_vim["vim_type"]
1093 for alt_image_id in vdur.get("alt-image-ids"):
1094 ns_alt_image = target["image"][int(alt_image_id)]
1095 if vim_type == ns_alt_image.get("vim-type"):
1096 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001097 self.logger.debug(
1098 "use alternative image id: {}".format(alt_image_id)
1099 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001100 ns_image_id = alt_image_id
1101 vdur["ns-image-id"] = ns_image_id
1102 break
1103 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001104 if target_vim not in ns_image["vim_info"]:
1105 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001106
Alexis Romero305b5c42022-03-11 15:29:18 +01001107 # Affinity groups
1108 if vdur.get("affinity-or-anti-affinity-group-id"):
1109 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1110 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1111 if target_vim not in ns_ags["vim_info"]:
1112 ns_ags["vim_info"][target_vim] = {}
1113
vegall63162192023-03-06 14:19:16 +00001114 # shared-volumes
1115 if vdur.get("shared-volumes-id"):
1116 for sv_id in vdur["shared-volumes-id"]:
1117 ns_sv = find_in_list(
1118 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1119 )
1120 if ns_sv:
1121 ns_sv["vim_info"][target_vim] = {}
1122
tierno2357f4e2020-10-19 16:38:59 +00001123 vdur["vim_info"] = {target_vim: {}}
1124 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001125 if vnf_params:
1126 vdu_instantiation_params = find_in_list(
1127 get_iterable(vnf_params, "vdu"),
1128 lambda i_vdu: i_vdu["id"] == vdud["id"],
1129 )
1130 if vdu_instantiation_params:
1131 # Parse the vdu_volumes from the instantiation params
1132 vdu_volumes = get_volumes_from_instantiation_params(
1133 vdu_instantiation_params, vdud
1134 )
1135 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001136 vdur["additionalParams"]["OSM"][
1137 "vim_flavor_id"
1138 ] = vdu_instantiation_params.get("vim-flavor-id")
kayal20011028e362024-06-27 08:23:36 +05301139 vdur["additionalParams"]["OSM"][
kayal2001de102fe2024-11-28 10:51:52 +05301140 "vim_flavor_name"
1141 ] = vdu_instantiation_params.get("vim-flavor-name")
1142 vdur["additionalParams"]["OSM"][
kayal20011028e362024-06-27 08:23:36 +05301143 "instance_name"
1144 ] = vdu_instantiation_params.get("instance_name")
tierno2357f4e2020-10-19 16:38:59 +00001145 vdur_list.append(vdur)
1146 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001147 target["vnf"].append(target_vnf)
1148
garciadeblas07f4e4c2022-06-09 09:42:58 +02001149 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001150 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001151 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001152 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001153 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001154 nsr_id,
1155 action_id,
1156 nslcmop_id,
1157 start_deploy,
1158 timeout_ns_deploy,
1159 stage,
1160 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001161 )
tierno69f0d382020-05-07 13:08:09 +00001162
1163 # Updating NSR
1164 db_nsr_update = {
1165 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001166 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001167 }
1168 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1169 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1170 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001171 self.logger.debug(
1172 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1173 )
tierno69f0d382020-05-07 13:08:09 +00001174 return
1175
garciadeblas5697b8b2021-03-24 09:17:02 +01001176 async def _wait_ng_ro(
1177 self,
1178 nsr_id,
1179 action_id,
1180 nslcmop_id=None,
1181 start_time=None,
1182 timeout=600,
1183 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001184 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001185 ):
tierno69f0d382020-05-07 13:08:09 +00001186 detailed_status_old = None
1187 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001188 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001189 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001190 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001191 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001192 if desc_status["status"] == "FAILED":
1193 raise NgRoException(desc_status["details"])
1194 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001195 if stage:
1196 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001197 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001198 if stage:
1199 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001200 break
1201 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001202 assert False, "ROclient.check_ns_status returns unknown {}".format(
1203 desc_status["status"]
1204 )
tierno2357f4e2020-10-19 16:38:59 +00001205 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001206 detailed_status_old = stage[2]
1207 db_nsr_update["detailed-status"] = " ".join(stage)
1208 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1209 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001210 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001211 else: # timeout_ns_deploy
1212 raise NgRoException("Timeout waiting ns to deploy")
1213
garciadeblas5697b8b2021-03-24 09:17:02 +01001214 async def _terminate_ng_ro(
1215 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1216 ):
tierno69f0d382020-05-07 13:08:09 +00001217 db_nsr_update = {}
1218 failed_detail = []
1219 action_id = None
1220 start_deploy = time()
1221 try:
1222 target = {
1223 "ns": {"vld": []},
1224 "vnf": [],
1225 "image": [],
1226 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001227 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001228 }
1229 desc = await self.RO.deploy(nsr_id, target)
1230 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001231 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001232 self.logger.debug(
1233 logging_text
1234 + "ns terminate action at RO. action_id={}".format(action_id)
1235 )
tierno69f0d382020-05-07 13:08:09 +00001236
1237 # wait until done
1238 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001239 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001240 nsr_id,
1241 action_id,
1242 nslcmop_id,
1243 start_deploy,
1244 delete_timeout,
1245 stage,
1246 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001247 )
tierno69f0d382020-05-07 13:08:09 +00001248 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1249 # delete all nsr
1250 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001251 except NgRoException as e:
1252 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001253 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1254 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001255 self.logger.debug(
1256 logging_text + "RO_action_id={} already deleted".format(action_id)
1257 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001258 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001259 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001260 self.logger.debug(
1261 logging_text
1262 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1263 )
tierno69f0d382020-05-07 13:08:09 +00001264 else:
1265 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001266 self.logger.error(
1267 logging_text
1268 + "RO_action_id={} delete error: {}".format(action_id, e)
1269 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001270 except Exception as e:
1271 failed_detail.append("delete error: {}".format(e))
1272 self.logger.error(
1273 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1274 )
tierno69f0d382020-05-07 13:08:09 +00001275
1276 if failed_detail:
1277 stage[2] = "Error deleting from VIM"
1278 else:
1279 stage[2] = "Deleted from VIM"
1280 db_nsr_update["detailed-status"] = " ".join(stage)
1281 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1282 self._write_op_status(nslcmop_id, stage)
1283
1284 if failed_detail:
1285 raise LcmException("; ".join(failed_detail))
1286 return
1287
garciadeblas5697b8b2021-03-24 09:17:02 +01001288 async def instantiate_RO(
1289 self,
1290 logging_text,
1291 nsr_id,
1292 nsd,
1293 db_nsr,
1294 db_nslcmop,
1295 db_vnfrs,
1296 db_vnfds,
1297 n2vc_key_list,
1298 stage,
1299 ):
tiernoe95ed362020-04-23 08:24:57 +00001300 """
1301 Instantiate at RO
1302 :param logging_text: preffix text to use at logging
1303 :param nsr_id: nsr identity
1304 :param nsd: database content of ns descriptor
1305 :param db_nsr: database content of ns record
1306 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1307 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001308 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001309 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1310 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1311 :return: None or exception
1312 """
tiernoe876f672020-02-13 14:34:48 +00001313 try:
tiernoe876f672020-02-13 14:34:48 +00001314 start_deploy = time()
1315 ns_params = db_nslcmop.get("operationParams")
1316 if ns_params and ns_params.get("timeout_ns_deploy"):
1317 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1318 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001319 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001320
tiernoe876f672020-02-13 14:34:48 +00001321 # Check for and optionally request placement optimization. Database will be updated if placement activated
1322 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001323 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1324 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1325 for vnfr in db_vnfrs.values():
1326 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1327 break
1328 else:
1329 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001330
garciadeblas5697b8b2021-03-24 09:17:02 +01001331 return await self._instantiate_ng_ro(
1332 logging_text,
1333 nsr_id,
1334 nsd,
1335 db_nsr,
1336 db_nslcmop,
1337 db_vnfrs,
1338 db_vnfds,
1339 n2vc_key_list,
1340 stage,
1341 start_deploy,
1342 timeout_ns_deploy,
1343 )
tierno2357f4e2020-10-19 16:38:59 +00001344 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001345 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001346 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001347 self.logger.error(
1348 "Error deploying at VIM {}".format(e),
1349 exc_info=not isinstance(
1350 e,
1351 (
1352 ROclient.ROClientException,
1353 LcmException,
1354 DbException,
1355 NgRoException,
1356 ),
1357 ),
1358 )
tiernoe876f672020-02-13 14:34:48 +00001359 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001360
tierno7ecbc342020-09-21 14:05:39 +00001361 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1362 """
1363 Wait for kdu to be up, get ip address
1364 :param logging_text: prefix use for logging
1365 :param nsr_id:
1366 :param vnfr_id:
1367 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001368 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001369 """
1370
1371 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1372 nb_tries = 0
1373
1374 while nb_tries < 360:
1375 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001376 kdur = next(
1377 (
1378 x
1379 for x in get_iterable(db_vnfr, "kdur")
1380 if x.get("kdu-name") == kdu_name
1381 ),
1382 None,
1383 )
tierno7ecbc342020-09-21 14:05:39 +00001384 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001385 raise LcmException(
1386 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1387 )
tierno7ecbc342020-09-21 14:05:39 +00001388 if kdur.get("status"):
1389 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001390 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001391 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001392 raise LcmException(
1393 "target KDU={} is in error state".format(kdu_name)
1394 )
tierno7ecbc342020-09-21 14:05:39 +00001395
Gabriel Cubae7898982023-05-11 01:57:21 -05001396 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001397 nb_tries += 1
1398 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1399
garciadeblas5697b8b2021-03-24 09:17:02 +01001400 async def wait_vm_up_insert_key_ro(
1401 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1402 ):
tiernoa5088192019-11-26 16:12:53 +00001403 """
1404 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1405 :param logging_text: prefix use for logging
1406 :param nsr_id:
1407 :param vnfr_id:
1408 :param vdu_id:
1409 :param vdu_index:
1410 :param pub_key: public ssh key to inject, None to skip
1411 :param user: user to apply the public ssh key
1412 :return: IP address
1413 """
quilesj7e13aeb2019-10-08 13:34:55 +02001414
tierno2357f4e2020-10-19 16:38:59 +00001415 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001416 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001417 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001418 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001419
tiernod8323042019-08-09 11:32:23 +00001420 while True:
quilesj3149f262019-12-03 10:58:10 +00001421 ro_retries += 1
1422 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001423 raise LcmException(
1424 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1425 )
quilesj3149f262019-12-03 10:58:10 +00001426
Gabriel Cubae7898982023-05-11 01:57:21 -05001427 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001428
1429 # get ip address
tiernod8323042019-08-09 11:32:23 +00001430 if not target_vdu_id:
1431 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001432
1433 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001434 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001435 raise LcmException(
1436 "Cannot inject ssh-key because target VNF is in error state"
1437 )
tiernod8323042019-08-09 11:32:23 +00001438 ip_address = db_vnfr.get("ip-address")
1439 if not ip_address:
1440 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001441 vdur = next(
1442 (
1443 x
1444 for x in get_iterable(db_vnfr, "vdur")
1445 if x.get("ip-address") == ip_address
1446 ),
1447 None,
1448 )
quilesj3149f262019-12-03 10:58:10 +00001449 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001450 vdur = next(
1451 (
1452 x
1453 for x in get_iterable(db_vnfr, "vdur")
1454 if x.get("vdu-id-ref") == vdu_id
1455 and x.get("count-index") == vdu_index
1456 ),
1457 None,
1458 )
quilesj3149f262019-12-03 10:58:10 +00001459
garciadeblas5697b8b2021-03-24 09:17:02 +01001460 if (
1461 not vdur and len(db_vnfr.get("vdur", ())) == 1
1462 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001463 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001464 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001465 raise LcmException(
1466 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1467 vnfr_id, vdu_id, vdu_index
1468 )
1469 )
tierno2357f4e2020-10-19 16:38:59 +00001470 # New generation RO stores information at "vim_info"
1471 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001472 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001473 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001474 target_vim = next(
1475 t for t in vdur["vim_info"]
1476 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001477 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001478 if (
1479 vdur.get("pdu-type")
1480 or vdur.get("status") == "ACTIVE"
1481 or ng_ro_status == "ACTIVE"
1482 ):
quilesj3149f262019-12-03 10:58:10 +00001483 ip_address = vdur.get("ip-address")
1484 if not ip_address:
1485 continue
1486 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001487 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001488 raise LcmException(
1489 "Cannot inject ssh-key because target VM is in error state"
1490 )
quilesj3149f262019-12-03 10:58:10 +00001491
tiernod8323042019-08-09 11:32:23 +00001492 if not target_vdu_id:
1493 continue
tiernod8323042019-08-09 11:32:23 +00001494
quilesj7e13aeb2019-10-08 13:34:55 +02001495 # inject public key into machine
1496 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001497 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001498 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001499 if vdur.get("pdu-type"):
1500 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1501 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001502 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001503 target = {
1504 "action": {
1505 "action": "inject_ssh_key",
1506 "key": pub_key,
1507 "user": user,
1508 },
1509 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1510 }
1511 desc = await self.RO.deploy(nsr_id, target)
1512 action_id = desc["action_id"]
1513 await self._wait_ng_ro(
1514 nsr_id, action_id, timeout=600, operation="instantiation"
1515 )
1516 break
tierno69f0d382020-05-07 13:08:09 +00001517 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001518 raise LcmException(
1519 "Reaching max tries injecting key. Error: {}".format(e)
1520 )
quilesj7e13aeb2019-10-08 13:34:55 +02001521 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001522 break
1523
1524 return ip_address
1525
tierno5ee02052019-12-05 19:55:02 +00001526 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1527 """
1528 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1529 """
1530 my_vca = vca_deployed_list[vca_index]
1531 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001532 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001533 return
1534 timeout = 300
1535 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001536 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1537 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1538 configuration_status_list = db_nsr["configurationStatus"]
1539 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001540 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001541 # myself
tierno5ee02052019-12-05 19:55:02 +00001542 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001543 if not my_vca.get("member-vnf-index") or (
1544 vca_deployed.get("member-vnf-index")
1545 == my_vca.get("member-vnf-index")
1546 ):
quilesj3655ae02019-12-12 16:08:35 +00001547 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001548 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001549 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001550 elif internal_status == "BROKEN":
1551 raise LcmException(
1552 "Configuration aborted because dependent charm/s has failed"
1553 )
quilesj3655ae02019-12-12 16:08:35 +00001554 else:
1555 break
tierno5ee02052019-12-05 19:55:02 +00001556 else:
quilesj3655ae02019-12-12 16:08:35 +00001557 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001558 return
1559 await asyncio.sleep(10)
1560 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001561
1562 raise LcmException("Configuration aborted because dependent charm/s timeout")
1563
David Garciac1fe90a2021-03-31 19:12:02 +02001564 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001565 vca_id = None
1566 if db_vnfr:
1567 vca_id = deep_get(db_vnfr, ("vca-id",))
1568 elif db_nsr:
1569 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1570 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1571 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001572
garciadeblas5697b8b2021-03-24 09:17:02 +01001573 async def instantiate_N2VC(
1574 self,
1575 logging_text,
1576 vca_index,
1577 nsi_id,
1578 db_nsr,
1579 db_vnfr,
1580 vdu_id,
1581 kdu_name,
1582 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001583 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001584 config_descriptor,
1585 deploy_params,
1586 base_folder,
1587 nslcmop_id,
1588 stage,
1589 vca_type,
1590 vca_name,
1591 ee_config_descriptor,
1592 ):
tiernod8323042019-08-09 11:32:23 +00001593 nsr_id = db_nsr["_id"]
1594 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001595 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001596 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001597 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001598 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001599 "collection": "nsrs",
1600 "filter": {"_id": nsr_id},
1601 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001602 }
tiernod8323042019-08-09 11:32:23 +00001603 step = ""
1604 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001605 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001606 element_under_configuration = nsr_id
1607
tiernod8323042019-08-09 11:32:23 +00001608 vnfr_id = None
1609 if db_vnfr:
1610 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001611 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001612
garciadeblas5697b8b2021-03-24 09:17:02 +01001613 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001614
aktas98488ed2021-07-29 17:42:49 +03001615 if vca_type == "native_charm":
1616 index_number = 0
1617 else:
1618 index_number = vdu_index or 0
1619
tiernod8323042019-08-09 11:32:23 +00001620 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001621 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001622 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001623 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001624 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001625 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001626 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001627 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001628 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001629 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001630 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001631 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001632 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001633 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001634
1635 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001636 if base_folder["pkg-dir"]:
1637 artifact_path = "{}/{}/{}/{}".format(
1638 base_folder["folder"],
1639 base_folder["pkg-dir"],
1640 "charms"
aticig15db6142022-01-24 12:51:26 +03001641 if vca_type
1642 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001643 else "helm-charts",
1644 vca_name,
1645 )
1646 else:
1647 artifact_path = "{}/Scripts/{}/{}/".format(
1648 base_folder["folder"],
1649 "charms"
aticig15db6142022-01-24 12:51:26 +03001650 if vca_type
1651 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001652 else "helm-charts",
1653 vca_name,
1654 )
bravof922c4172020-11-24 21:21:43 -03001655
1656 self.logger.debug("Artifact path > {}".format(artifact_path))
1657
tiernoa278b842020-07-08 15:33:55 +00001658 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001659 initial_config_primitive_list = config_descriptor.get(
1660 "initial-config-primitive"
1661 )
tiernoa278b842020-07-08 15:33:55 +00001662
garciadeblas5697b8b2021-03-24 09:17:02 +01001663 self.logger.debug(
1664 "Initial config primitive list > {}".format(
1665 initial_config_primitive_list
1666 )
1667 )
bravof922c4172020-11-24 21:21:43 -03001668
tiernoa278b842020-07-08 15:33:55 +00001669 # add config if not present for NS charm
1670 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001671 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001672 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1673 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1674 )
tiernod8323042019-08-09 11:32:23 +00001675
garciadeblas5697b8b2021-03-24 09:17:02 +01001676 self.logger.debug(
1677 "Initial config primitive list #2 > {}".format(
1678 initial_config_primitive_list
1679 )
1680 )
tierno588547c2020-07-01 15:30:20 +00001681 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001682 # find old ee_id if exists
1683 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001684
David Garciac1fe90a2021-03-31 19:12:02 +02001685 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001686 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001687 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001688 self._write_configuration_status(
1689 nsr_id=nsr_id,
1690 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001691 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001692 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001693 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001694 )
tiernod8323042019-08-09 11:32:23 +00001695
tierno588547c2020-07-01 15:30:20 +00001696 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001697 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001698
1699 ee_id = None
1700 credentials = None
1701 if vca_type == "k8s_proxy_charm":
1702 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001703 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001704 namespace=namespace,
1705 artifact_path=artifact_path,
1706 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001707 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001708 )
Luis Vegae11384e2023-10-10 22:36:33 +00001709 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001710 ee_id, credentials = await self.vca_map[
1711 vca_type
1712 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001713 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001714 reuse_ee_id=ee_id,
1715 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001716 config=osm_config,
1717 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001718 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001719 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001720 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001721 else:
1722 ee_id, credentials = await self.vca_map[
1723 vca_type
1724 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001725 namespace=namespace,
1726 reuse_ee_id=ee_id,
1727 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001728 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001729 )
quilesj3655ae02019-12-12 16:08:35 +00001730
tierno588547c2020-07-01 15:30:20 +00001731 elif vca_type == "native_charm":
1732 step = "Waiting to VM being up and getting IP address"
1733 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001734 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1735 logging_text,
1736 nsr_id,
1737 vnfr_id,
1738 vdu_id,
1739 vdu_index,
1740 user=None,
1741 pub_key=None,
1742 )
tierno588547c2020-07-01 15:30:20 +00001743 credentials = {"hostname": rw_mgmt_ip}
1744 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001745 username = deep_get(
1746 config_descriptor, ("config-access", "ssh-access", "default-user")
1747 )
tierno588547c2020-07-01 15:30:20 +00001748 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1749 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001750 if not username and initial_config_primitive_list:
1751 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001752 for param in config_primitive.get("parameter", ()):
1753 if param["name"] == "ssh-username":
1754 username = param["value"]
1755 break
1756 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001757 raise LcmException(
1758 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1759 "'config-access.ssh-access.default-user'"
1760 )
tierno588547c2020-07-01 15:30:20 +00001761 credentials["username"] = username
1762 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001763
tierno588547c2020-07-01 15:30:20 +00001764 self._write_configuration_status(
1765 nsr_id=nsr_id,
1766 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001767 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001768 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001769 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001770 )
quilesj3655ae02019-12-12 16:08:35 +00001771
tierno588547c2020-07-01 15:30:20 +00001772 step = "register execution environment {}".format(credentials)
1773 self.logger.debug(logging_text + step)
1774 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001775 credentials=credentials,
1776 namespace=namespace,
1777 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001778 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001779 )
tierno3bedc9b2019-11-27 15:46:57 +00001780
tierno588547c2020-07-01 15:30:20 +00001781 # for compatibility with MON/POL modules, the need model and application name at database
1782 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001783 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001784 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1785 if len(ee_id_parts) >= 2:
1786 model_name = ee_id_parts[0]
1787 application_name = ee_id_parts[1]
1788 db_nsr_update[db_update_entry + "model"] = model_name
1789 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001790
1791 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001792 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001793
tiernoc231a872020-01-21 08:49:05 +00001794 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001795 nsr_id=nsr_id,
1796 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001797 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001798 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001799 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001800 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001801 )
1802
tierno3bedc9b2019-11-27 15:46:57 +00001803 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001804 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001805 config = None
tierno588547c2020-07-01 15:30:20 +00001806 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001807 config_primitive = next(
1808 (p for p in initial_config_primitive_list if p["name"] == "config"),
1809 None,
1810 )
tiernoa278b842020-07-08 15:33:55 +00001811 if config_primitive:
1812 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001813 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001814 )
tierno588547c2020-07-01 15:30:20 +00001815 num_units = 1
1816 if vca_type == "lxc_proxy_charm":
1817 if element_type == "NS":
1818 num_units = db_nsr.get("config-units") or 1
1819 elif element_type == "VNF":
1820 num_units = db_vnfr.get("config-units") or 1
1821 elif element_type == "VDU":
1822 for v in db_vnfr["vdur"]:
1823 if vdu_id == v["vdu-id-ref"]:
1824 num_units = v.get("config-units") or 1
1825 break
David Garciaaae391f2020-11-09 11:12:54 +01001826 if vca_type != "k8s_proxy_charm":
1827 await self.vca_map[vca_type].install_configuration_sw(
1828 ee_id=ee_id,
1829 artifact_path=artifact_path,
1830 db_dict=db_dict,
1831 config=config,
1832 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001833 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001834 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001835 )
quilesj7e13aeb2019-10-08 13:34:55 +02001836
quilesj63f90042020-01-17 09:53:55 +00001837 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001838 self.update_db_2(
1839 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1840 )
quilesj63f90042020-01-17 09:53:55 +00001841
1842 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001843 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001844 logging_text=logging_text,
1845 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001846 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001847 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001848 )
quilesj63f90042020-01-17 09:53:55 +00001849
Patricia Reinosob4312c02023-01-06 22:28:44 +00001850 if not is_relation_added:
1851 raise LcmException("Relations could not be added to VCA.")
1852
quilesj7e13aeb2019-10-08 13:34:55 +02001853 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001854 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001855 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001856 pub_key = None
1857 user = None
tierno588547c2020-07-01 15:30:20 +00001858 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001859 if deep_get(
1860 config_descriptor, ("config-access", "ssh-access", "required")
1861 ):
tierno588547c2020-07-01 15:30:20 +00001862 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001863 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001864 user = deep_get(
1865 config_descriptor,
1866 ("config-access", "ssh-access", "default-user"),
1867 )
tierno3bedc9b2019-11-27 15:46:57 +00001868 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001869 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001870 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001871 )
quilesj7e13aeb2019-10-08 13:34:55 +02001872
garciadeblas5697b8b2021-03-24 09:17:02 +01001873 step = "Insert public key into VM user={} ssh_key={}".format(
1874 user, pub_key
1875 )
tierno3bedc9b2019-11-27 15:46:57 +00001876 else:
tierno588547c2020-07-01 15:30:20 +00001877 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001878 step = "Waiting to VM being up and getting IP address"
1879 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001880
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001881 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1882 rw_mgmt_ip = None
1883
tierno3bedc9b2019-11-27 15:46:57 +00001884 # n2vc_redesign STEP 5.1
1885 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001886 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001887 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001888 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001889 logging_text, nsr_id, vnfr_id, kdu_name
1890 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001891 vnfd = self.db.get_one(
1892 "vnfds_revisions",
1893 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1894 )
1895 kdu = get_kdu(vnfd, kdu_name)
1896 kdu_services = [
1897 service["name"] for service in get_kdu_services(kdu)
1898 ]
1899 exposed_services = []
1900 for service in services:
1901 if any(s in service["name"] for s in kdu_services):
1902 exposed_services.append(service)
1903 await self.vca_map[vca_type].exec_primitive(
1904 ee_id=ee_id,
1905 primitive_name="config",
1906 params_dict={
1907 "osm-config": json.dumps(
1908 OsmConfigBuilder(
1909 k8s={"services": exposed_services}
1910 ).build()
1911 )
1912 },
1913 vca_id=vca_id,
1914 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001915
1916 # This verification is needed in order to avoid trying to add a public key
1917 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1918 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1919 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1920 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001921 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001922 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1923 logging_text,
1924 nsr_id,
1925 vnfr_id,
1926 vdu_id,
1927 vdu_index,
1928 user=user,
1929 pub_key=pub_key,
1930 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001931
garciadeblas5697b8b2021-03-24 09:17:02 +01001932 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001933
tiernoa5088192019-11-26 16:12:53 +00001934 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001935 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001936
1937 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001938 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001939
1940 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001941 if initial_config_primitive_list:
1942 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001943
1944 # stage, in function of element type: vdu, kdu, vnf or ns
1945 my_vca = vca_deployed_list[vca_index]
1946 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1947 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001948 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001949 elif my_vca.get("member-vnf-index"):
1950 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001951 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001952 else:
1953 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001954 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00001955
tiernoc231a872020-01-21 08:49:05 +00001956 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01001957 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00001958 )
1959
garciadeblas5697b8b2021-03-24 09:17:02 +01001960 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00001961
tiernoe876f672020-02-13 14:34:48 +00001962 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001963 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001964 # adding information on the vca_deployed if it is a NS execution environment
1965 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001966 deploy_params["ns_config_info"] = json.dumps(
1967 self._get_ns_config_info(nsr_id)
1968 )
tiernod8323042019-08-09 11:32:23 +00001969 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01001970 primitive_params_ = self._map_primitive_params(
1971 initial_config_primitive, {}, deploy_params
1972 )
tierno3bedc9b2019-11-27 15:46:57 +00001973
garciadeblas5697b8b2021-03-24 09:17:02 +01001974 step = "execute primitive '{}' params '{}'".format(
1975 initial_config_primitive["name"], primitive_params_
1976 )
tiernod8323042019-08-09 11:32:23 +00001977 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001978 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001979 ee_id=ee_id,
1980 primitive_name=initial_config_primitive["name"],
1981 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02001982 db_dict=db_dict,
1983 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001984 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02001985 )
tiernoe876f672020-02-13 14:34:48 +00001986 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1987 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01001988 if config_descriptor.get("terminate-config-primitive"):
1989 self.update_db_2(
1990 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
1991 )
tiernoe876f672020-02-13 14:34:48 +00001992 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001993
tiernod8323042019-08-09 11:32:23 +00001994 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001995
tiernob996d942020-07-03 14:52:28 +00001996 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00001997 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02001998 # TODO: review for those cases where the helm chart is a reference and
1999 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002000 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002001 ee_id=ee_id,
2002 artifact_path=artifact_path,
2003 ee_config_descriptor=ee_config_descriptor,
2004 vnfr_id=vnfr_id,
2005 nsr_id=nsr_id,
2006 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002007 element_type=element_type,
2008 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2009 vdu_id=vdu_id,
2010 vdu_index=vdu_index,
2011 kdu_name=kdu_name,
2012 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002013 )
2014 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002015 self.update_db_2(
2016 "nsrs",
2017 nsr_id,
2018 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2019 )
tiernob996d942020-07-03 14:52:28 +00002020
bravof73bac502021-05-11 07:38:47 -04002021 for job in prometheus_jobs:
2022 self.db.set_one(
2023 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002024 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002025 job,
2026 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002027 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002028 )
2029
quilesj7e13aeb2019-10-08 13:34:55 +02002030 step = "instantiated at VCA"
2031 self.logger.debug(logging_text + step)
2032
tiernoc231a872020-01-21 08:49:05 +00002033 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002034 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002035 )
2036
tiernod8323042019-08-09 11:32:23 +00002037 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002038 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002039 if not isinstance(
2040 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2041 ):
2042 self.logger.error(
2043 "Exception while {} : {}".format(step, e), exc_info=True
2044 )
tiernoc231a872020-01-21 08:49:05 +00002045 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002046 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002047 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002048 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002049
garciadeblas5697b8b2021-03-24 09:17:02 +01002050 def _write_ns_status(
2051 self,
2052 nsr_id: str,
2053 ns_state: str,
2054 current_operation: str,
2055 current_operation_id: str,
2056 error_description: str = None,
2057 error_detail: str = None,
2058 other_update: dict = None,
2059 ):
tiernoe876f672020-02-13 14:34:48 +00002060 """
2061 Update db_nsr fields.
2062 :param nsr_id:
2063 :param ns_state:
2064 :param current_operation:
2065 :param current_operation_id:
2066 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002067 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002068 :param other_update: Other required changes at database if provided, will be cleared
2069 :return:
2070 """
quilesj4cda56b2019-12-05 10:02:20 +00002071 try:
tiernoe876f672020-02-13 14:34:48 +00002072 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002073 db_dict[
2074 "_admin.nslcmop"
2075 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002076 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002077 db_dict["_admin.operation-type"] = (
2078 current_operation if current_operation != "IDLE" else None
2079 )
quilesj4cda56b2019-12-05 10:02:20 +00002080 db_dict["currentOperation"] = current_operation
2081 db_dict["currentOperationID"] = current_operation_id
2082 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002083 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002084
2085 if ns_state:
2086 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002087 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002088 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002089 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002090
garciadeblas5697b8b2021-03-24 09:17:02 +01002091 def _write_op_status(
2092 self,
2093 op_id: str,
2094 stage: list = None,
2095 error_message: str = None,
2096 queuePosition: int = 0,
2097 operation_state: str = None,
2098 other_update: dict = None,
2099 ):
quilesj3655ae02019-12-12 16:08:35 +00002100 try:
tiernoe876f672020-02-13 14:34:48 +00002101 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002102 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002103 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002104 db_dict["stage"] = stage[0]
2105 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002106 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002107 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002108
2109 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002110 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002111 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002112 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002113 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002114 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002115 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002116 self.logger.warn(
2117 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2118 )
quilesj3655ae02019-12-12 16:08:35 +00002119
tierno51183952020-04-03 15:48:18 +00002120 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002121 try:
tierno51183952020-04-03 15:48:18 +00002122 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002123 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002124 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002125 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002126 db_nsr_update = {
2127 "configurationStatus.{}.status".format(index): status
2128 for index, v in enumerate(config_status)
2129 if v
2130 }
quilesj3655ae02019-12-12 16:08:35 +00002131 # update status
tierno51183952020-04-03 15:48:18 +00002132 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002133
tiernoe876f672020-02-13 14:34:48 +00002134 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002135 self.logger.warn(
2136 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2137 )
quilesj3655ae02019-12-12 16:08:35 +00002138
garciadeblas5697b8b2021-03-24 09:17:02 +01002139 def _write_configuration_status(
2140 self,
2141 nsr_id: str,
2142 vca_index: int,
2143 status: str = None,
2144 element_under_configuration: str = None,
2145 element_type: str = None,
2146 other_update: dict = None,
2147 ):
quilesj3655ae02019-12-12 16:08:35 +00002148 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2149 # .format(vca_index, status))
2150
2151 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002152 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002153 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002154 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002155 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002156 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002157 db_dict[
2158 db_path + "elementUnderConfiguration"
2159 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002160 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002161 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002162 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002163 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002164 self.logger.warn(
2165 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2166 status, nsr_id, vca_index, e
2167 )
2168 )
quilesj4cda56b2019-12-05 10:02:20 +00002169
tierno38089af2020-04-16 07:56:58 +00002170 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2171 """
2172 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2173 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2174 Database is used because the result can be obtained from a different LCM worker in case of HA.
2175 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2176 :param db_nslcmop: database content of nslcmop
2177 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002178 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2179 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002180 """
tierno8790a3d2020-04-23 22:49:52 +00002181 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002182 nslcmop_id = db_nslcmop["_id"]
2183 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002184 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002185 self.logger.debug(
2186 logging_text + "Invoke and wait for placement optimization"
2187 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002188 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002189 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002190 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002191 pla_result = None
2192 while not pla_result and wait >= 0:
2193 await asyncio.sleep(db_poll_interval)
2194 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002195 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002196 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002197
2198 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002199 raise LcmException(
2200 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2201 )
magnussonle9198bb2020-01-21 13:00:51 +01002202
garciadeblas5697b8b2021-03-24 09:17:02 +01002203 for pla_vnf in pla_result["vnf"]:
2204 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2205 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002206 continue
tierno8790a3d2020-04-23 22:49:52 +00002207 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002208 self.db.set_one(
2209 "vnfrs",
2210 {"_id": vnfr["_id"]},
2211 {"vim-account-id": pla_vnf["vimAccountId"]},
2212 )
tierno38089af2020-04-16 07:56:58 +00002213 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002214 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002215 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002216
aguilard1ae3c562023-02-16 17:24:35 +00002217 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2218 alerts = []
2219 nsr_id = vnfr["nsr-id-ref"]
2220 df = vnfd.get("df", [{}])[0]
2221 # Checking for auto-healing configuration
2222 if "healing-aspect" in df:
2223 healing_aspects = df["healing-aspect"]
2224 for healing in healing_aspects:
2225 for healing_policy in healing.get("healing-policy", ()):
2226 vdu_id = healing_policy["vdu-id"]
2227 vdur = next(
2228 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2229 {},
2230 )
2231 if not vdur:
2232 continue
2233 metric_name = "vm_status"
2234 vdu_name = vdur.get("name")
2235 vnf_member_index = vnfr["member-vnf-index-ref"]
2236 uuid = str(uuid4())
2237 name = f"healing_{uuid}"
2238 action = healing_policy
2239 # action_on_recovery = healing.get("action-on-recovery")
2240 # cooldown_time = healing.get("cooldown-time")
2241 # day1 = healing.get("day1")
2242 alert = {
2243 "uuid": uuid,
2244 "name": name,
2245 "metric": metric_name,
2246 "tags": {
2247 "ns_id": nsr_id,
2248 "vnf_member_index": vnf_member_index,
2249 "vdu_name": vdu_name,
2250 },
2251 "alarm_status": "ok",
2252 "action_type": "healing",
2253 "action": action,
2254 }
2255 alerts.append(alert)
2256 return alerts
2257
2258 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2259 alerts = []
2260 nsr_id = vnfr["nsr-id-ref"]
2261 df = vnfd.get("df", [{}])[0]
2262 # Checking for auto-scaling configuration
2263 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002264 scaling_aspects = df["scaling-aspect"]
2265 all_vnfd_monitoring_params = {}
2266 for ivld in vnfd.get("int-virtual-link-desc", ()):
2267 for mp in ivld.get("monitoring-parameters", ()):
2268 all_vnfd_monitoring_params[mp.get("id")] = mp
2269 for vdu in vnfd.get("vdu", ()):
2270 for mp in vdu.get("monitoring-parameter", ()):
2271 all_vnfd_monitoring_params[mp.get("id")] = mp
2272 for df in vnfd.get("df", ()):
2273 for mp in df.get("monitoring-parameter", ()):
2274 all_vnfd_monitoring_params[mp.get("id")] = mp
2275 for scaling_aspect in scaling_aspects:
2276 scaling_group_name = scaling_aspect.get("name", "")
2277 # Get monitored VDUs
2278 all_monitored_vdus = set()
2279 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2280 "deltas", ()
2281 ):
2282 for vdu_delta in delta.get("vdu-delta", ()):
2283 all_monitored_vdus.add(vdu_delta.get("id"))
2284 monitored_vdurs = list(
2285 filter(
2286 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2287 vnfr["vdur"],
2288 )
2289 )
2290 if not monitored_vdurs:
2291 self.logger.error(
2292 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2293 )
2294 continue
2295 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2296 if scaling_policy["scaling-type"] != "automatic":
2297 continue
2298 threshold_time = scaling_policy.get("threshold-time", "1")
2299 cooldown_time = scaling_policy.get("cooldown-time", "0")
2300 for scaling_criteria in scaling_policy["scaling-criteria"]:
2301 monitoring_param_ref = scaling_criteria.get(
2302 "vnf-monitoring-param-ref"
2303 )
2304 vnf_monitoring_param = all_vnfd_monitoring_params[
2305 monitoring_param_ref
2306 ]
2307 for vdur in monitored_vdurs:
2308 vdu_id = vdur["vdu-id-ref"]
2309 metric_name = vnf_monitoring_param.get("performance-metric")
Rahul Kumar54671c52024-05-09 15:34:01 +05302310 if "exporters-endpoints" not in df:
2311 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002312 vnf_member_index = vnfr["member-vnf-index-ref"]
2313 scalein_threshold = scaling_criteria.get(
2314 "scale-in-threshold"
2315 )
2316 scaleout_threshold = scaling_criteria.get(
2317 "scale-out-threshold"
2318 )
2319 # Looking for min/max-number-of-instances
2320 instances_min_number = 1
2321 instances_max_number = 1
2322 vdu_profile = df["vdu-profile"]
2323 if vdu_profile:
2324 profile = next(
2325 item for item in vdu_profile if item["id"] == vdu_id
2326 )
2327 instances_min_number = profile.get(
2328 "min-number-of-instances", 1
2329 )
2330 instances_max_number = profile.get(
2331 "max-number-of-instances", 1
2332 )
2333
2334 if scalein_threshold:
2335 uuid = str(uuid4())
2336 name = f"scalein_{uuid}"
2337 operation = scaling_criteria[
2338 "scale-in-relational-operation"
2339 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002340 rel_operator = self.rel_operation_types.get(
2341 operation, "<="
2342 )
aguilard1ae3c562023-02-16 17:24:35 +00002343 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2344 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302345 if (
2346 "exporters-endpoints" in df
2347 and metric_name.startswith("kpi_")
2348 ):
2349 new_metric_name = (
2350 f'osm_{metric_name.replace("kpi_", "").strip()}'
2351 )
2352 metric_port = df["exporters-endpoints"].get(
2353 "metric-port", 9100
2354 )
2355 vdu_ip = vdur["ip-address"]
2356 ip_port = str(vdu_ip) + ":" + str(metric_port)
2357 metric_selector = (
2358 f'{new_metric_name}{{instance="{ip_port}"}}'
2359 )
2360 expression = f"({metric_selector} {rel_operator} {scalein_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002361 labels = {
2362 "ns_id": nsr_id,
2363 "vnf_member_index": vnf_member_index,
2364 "vdu_id": vdu_id,
2365 }
2366 prom_cfg = {
2367 "alert": name,
2368 "expr": expression,
2369 "for": str(threshold_time) + "m",
2370 "labels": labels,
2371 }
2372 action = scaling_policy
2373 action = {
2374 "scaling-group": scaling_group_name,
2375 "cooldown-time": cooldown_time,
2376 }
2377 alert = {
2378 "uuid": uuid,
2379 "name": name,
2380 "metric": metric_name,
2381 "tags": {
2382 "ns_id": nsr_id,
2383 "vnf_member_index": vnf_member_index,
2384 "vdu_id": vdu_id,
2385 },
2386 "alarm_status": "ok",
2387 "action_type": "scale_in",
2388 "action": action,
2389 "prometheus_config": prom_cfg,
2390 }
2391 alerts.append(alert)
2392
2393 if scaleout_threshold:
2394 uuid = str(uuid4())
2395 name = f"scaleout_{uuid}"
2396 operation = scaling_criteria[
2397 "scale-out-relational-operation"
2398 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002399 rel_operator = self.rel_operation_types.get(
2400 operation, "<="
2401 )
aguilard1ae3c562023-02-16 17:24:35 +00002402 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2403 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302404 if (
2405 "exporters-endpoints" in df
2406 and metric_name.startswith("kpi_")
2407 ):
2408 new_metric_name = (
2409 f'osm_{metric_name.replace("kpi_", "").strip()}'
2410 )
2411 metric_port = df["exporters-endpoints"].get(
2412 "metric-port", 9100
2413 )
2414 vdu_ip = vdur["ip-address"]
2415 ip_port = str(vdu_ip) + ":" + str(metric_port)
2416 metric_selector = (
2417 f'{new_metric_name}{{instance="{ip_port}"}}'
2418 )
2419 expression = f"({metric_selector} {rel_operator} {scaleout_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002420 labels = {
2421 "ns_id": nsr_id,
2422 "vnf_member_index": vnf_member_index,
2423 "vdu_id": vdu_id,
2424 }
2425 prom_cfg = {
2426 "alert": name,
2427 "expr": expression,
2428 "for": str(threshold_time) + "m",
2429 "labels": labels,
2430 }
2431 action = scaling_policy
2432 action = {
2433 "scaling-group": scaling_group_name,
2434 "cooldown-time": cooldown_time,
2435 }
2436 alert = {
2437 "uuid": uuid,
2438 "name": name,
2439 "metric": metric_name,
2440 "tags": {
2441 "ns_id": nsr_id,
2442 "vnf_member_index": vnf_member_index,
2443 "vdu_id": vdu_id,
2444 },
2445 "alarm_status": "ok",
2446 "action_type": "scale_out",
2447 "action": action,
2448 "prometheus_config": prom_cfg,
2449 }
2450 alerts.append(alert)
2451 return alerts
2452
garciadeblas9148fa82023-05-30 12:51:14 +02002453 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2454 alerts = []
2455 nsr_id = vnfr["nsr-id-ref"]
2456 vnf_member_index = vnfr["member-vnf-index-ref"]
2457
2458 # Checking for VNF alarm configuration
2459 for vdur in vnfr["vdur"]:
2460 vdu_id = vdur["vdu-id-ref"]
2461 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2462 if "alarm" in vdu:
2463 # Get VDU monitoring params, since alerts are based on them
2464 vdu_monitoring_params = {}
2465 for mp in vdu.get("monitoring-parameter", []):
2466 vdu_monitoring_params[mp.get("id")] = mp
2467 if not vdu_monitoring_params:
2468 self.logger.error(
2469 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2470 )
2471 continue
2472 # Get alarms in the VDU
2473 alarm_descriptors = vdu["alarm"]
2474 # Create VDU alarms for each alarm in the VDU
2475 for alarm_descriptor in alarm_descriptors:
2476 # Check that the VDU alarm refers to a proper monitoring param
2477 alarm_monitoring_param = alarm_descriptor.get(
2478 "vnf-monitoring-param-ref", ""
2479 )
2480 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2481 alarm_monitoring_param, {}
2482 )
2483 if not vdu_specific_monitoring_param:
2484 self.logger.error(
2485 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2486 )
2487 continue
2488 metric_name = vdu_specific_monitoring_param.get(
2489 "performance-metric"
2490 )
2491 if not metric_name:
2492 self.logger.error(
2493 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2494 )
2495 continue
2496 # Set params of the alarm to be created in Prometheus
2497 metric_name = f"osm_{metric_name}"
2498 metric_threshold = alarm_descriptor.get("value")
2499 uuid = str(uuid4())
2500 alert_name = f"vdu_alarm_{uuid}"
2501 operation = alarm_descriptor["operation"]
2502 rel_operator = self.rel_operation_types.get(operation, "<=")
2503 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 +00002504 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002505 labels = {
2506 "ns_id": nsr_id,
2507 "vnf_member_index": vnf_member_index,
2508 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002509 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002510 }
2511 prom_cfg = {
2512 "alert": alert_name,
2513 "expr": expression,
2514 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2515 "labels": labels,
2516 }
2517 alarm_action = dict()
2518 for action_type in ["ok", "insufficient-data", "alarm"]:
2519 if (
2520 "actions" in alarm_descriptor
2521 and action_type in alarm_descriptor["actions"]
2522 ):
aguilardeb076722023-05-31 09:45:00 +00002523 alarm_action[action_type] = alarm_descriptor["actions"][
2524 action_type
2525 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002526 alert = {
2527 "uuid": uuid,
2528 "name": alert_name,
2529 "metric": metric_name,
2530 "tags": {
2531 "ns_id": nsr_id,
2532 "vnf_member_index": vnf_member_index,
2533 "vdu_id": vdu_id,
2534 },
2535 "alarm_status": "ok",
2536 "action_type": "vdu_alarm",
2537 "action": alarm_action,
2538 "prometheus_config": prom_cfg,
2539 }
2540 alerts.append(alert)
2541 return alerts
2542
magnussonle9198bb2020-01-21 13:00:51 +01002543 def update_nsrs_with_pla_result(self, params):
2544 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002545 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2546 self.update_db_2(
2547 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2548 )
magnussonle9198bb2020-01-21 13:00:51 +01002549 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002550 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002551
tierno59d22d22018-09-25 18:10:19 +02002552 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002553 """
2554
2555 :param nsr_id: ns instance to deploy
2556 :param nslcmop_id: operation to run
2557 :return:
2558 """
kuused124bfe2019-06-18 12:09:24 +02002559
2560 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002561 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002562 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002563 self.logger.debug(
2564 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2565 )
kuused124bfe2019-06-18 12:09:24 +02002566 return
2567
tierno59d22d22018-09-25 18:10:19 +02002568 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2569 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002570
tierno59d22d22018-09-25 18:10:19 +02002571 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002572
2573 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002574 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002575
2576 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002577 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002578
2579 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002580 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002581 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002582 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002583
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002584 timeout_ns_deploy = self.timeout.ns_deploy
2585
tierno59d22d22018-09-25 18:10:19 +02002586 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002587 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002588 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002589 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002590 exc = None
tiernoe876f672020-02-13 14:34:48 +00002591 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002592 stage = [
2593 "Stage 1/5: preparation of the environment.",
2594 "Waiting for previous operations to terminate.",
2595 "",
2596 ]
tiernoe876f672020-02-13 14:34:48 +00002597 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002598 try:
kuused124bfe2019-06-18 12:09:24 +02002599 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002600 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002601
quilesj7e13aeb2019-10-08 13:34:55 +02002602 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002603 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002604 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002605 db_nsr_update["detailed-status"] = "creating"
2606 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002607 self._write_ns_status(
2608 nsr_id=nsr_id,
2609 ns_state="BUILDING",
2610 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002611 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002612 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002613 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002614 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002615
quilesj7e13aeb2019-10-08 13:34:55 +02002616 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002617 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002618 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002619 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2620 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2621 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2622 )
tierno744303e2020-01-13 16:46:31 +00002623 ns_params = db_nslcmop.get("operationParams")
2624 if ns_params and ns_params.get("timeout_ns_deploy"):
2625 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002626
2627 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002628 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002629 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002630 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002631 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002632 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002633 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002634 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002635 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002636 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002637
quilesj7e13aeb2019-10-08 13:34:55 +02002638 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002639 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002640 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002641 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002642
quilesj7e13aeb2019-10-08 13:34:55 +02002643 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002644 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002645
2646 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002647 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002648 if vnfr.get("kdur"):
2649 kdur_list = []
2650 for kdur in vnfr["kdur"]:
2651 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002652 kdur["additionalParams"] = json.loads(
2653 kdur["additionalParams"]
2654 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002655 kdur_list.append(kdur)
2656 vnfr["kdur"] = kdur_list
2657
bravof922c4172020-11-24 21:21:43 -03002658 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2659 vnfd_id = vnfr["vnfd-id"]
2660 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002661 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002662
quilesj7e13aeb2019-10-08 13:34:55 +02002663 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002664 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002665 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002666 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2667 vnfd_id, vnfd_ref
2668 )
tiernoe876f672020-02-13 14:34:48 +00002669 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002670 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002671
quilesj7e13aeb2019-10-08 13:34:55 +02002672 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002673 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002674
2675 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002676 vca_deployed_list = None
2677 if db_nsr["_admin"].get("deployed"):
2678 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2679 if vca_deployed_list is None:
2680 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002681 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002682 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002683 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002684 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002685 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002686 elif isinstance(vca_deployed_list, dict):
2687 # maintain backward compatibility. Change a dict to list at database
2688 vca_deployed_list = list(vca_deployed_list.values())
2689 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002690 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002691
garciadeblas5697b8b2021-03-24 09:17:02 +01002692 if not isinstance(
2693 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2694 ):
tiernoa009e552019-01-30 16:45:44 +00002695 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2696 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002697
tiernobaa51102018-12-14 13:16:18 +00002698 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2699 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2700 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002701 self.db.set_list(
2702 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2703 )
quilesj3655ae02019-12-12 16:08:35 +00002704
2705 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002706 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2707 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002708
tiernob5203912020-08-11 11:20:13 +00002709 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002710 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002711 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002712 await self.deploy_kdus(
2713 logging_text=logging_text,
2714 nsr_id=nsr_id,
2715 nslcmop_id=nslcmop_id,
2716 db_vnfrs=db_vnfrs,
2717 db_vnfds=db_vnfds,
2718 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002719 )
tiernoe876f672020-02-13 14:34:48 +00002720
2721 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002722 # n2vc_redesign STEP 1 Get VCA public ssh-key
2723 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002724 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002725 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002726 if self.vca_config.public_key:
2727 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002728
tiernoe876f672020-02-13 14:34:48 +00002729 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002730 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002731 self.instantiate_RO(
2732 logging_text=logging_text,
2733 nsr_id=nsr_id,
2734 nsd=nsd,
2735 db_nsr=db_nsr,
2736 db_nslcmop=db_nslcmop,
2737 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002738 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002739 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002740 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002741 )
tiernod8323042019-08-09 11:32:23 +00002742 )
2743 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002744 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002745
tiernod8323042019-08-09 11:32:23 +00002746 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002747 stage[1] = "Deploying Execution Environments."
2748 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002749
Gabriel Cuba1411a002022-10-07 11:38:23 -05002750 # create namespace and certificate if any helm based EE is present in the NS
2751 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002752 await self.vca_map["helm-v3"].setup_ns_namespace(
2753 name=nsr_id,
2754 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002755 # create TLS certificates
2756 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002757 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002758 dns_prefix="*",
2759 nsr_id=nsr_id,
2760 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002761 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002762 )
2763
tiernod8323042019-08-09 11:32:23 +00002764 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002765 for vnf_profile in get_vnf_profiles(nsd):
2766 vnfd_id = vnf_profile["vnfd-id"]
2767 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2768 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002769 db_vnfr = db_vnfrs[member_vnf_index]
2770 base_folder = vnfd["_admin"]["storage"]
2771 vdu_id = None
2772 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002773 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002774 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002775 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002776
tierno8a518872018-12-21 13:42:14 +00002777 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002778 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002779 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002780 deploy_params.update(
2781 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2782 )
tierno8a518872018-12-21 13:42:14 +00002783
bravofe5a31bc2021-02-17 19:09:12 -03002784 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002785 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002786 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002787 logging_text=logging_text
2788 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002789 db_nsr=db_nsr,
2790 db_vnfr=db_vnfr,
2791 nslcmop_id=nslcmop_id,
2792 nsr_id=nsr_id,
2793 nsi_id=nsi_id,
2794 vnfd_id=vnfd_id,
2795 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002796 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002797 member_vnf_index=member_vnf_index,
2798 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002799 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002800 vdu_name=vdu_name,
2801 deploy_params=deploy_params,
2802 descriptor_config=descriptor_config,
2803 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002804 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002805 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002806 )
tierno59d22d22018-09-25 18:10:19 +02002807
2808 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002809 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002810 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002811 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002812 vdur = find_in_list(
2813 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2814 )
bravof922c4172020-11-24 21:21:43 -03002815
tierno626e0152019-11-29 14:16:16 +00002816 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002817 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002818 else:
2819 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002820 deploy_params_vdu["OSM"] = get_osm_params(
2821 db_vnfr, vdu_id, vdu_count_index=0
2822 )
endika76ba9232021-06-21 18:55:07 +02002823 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002824
2825 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002826 self.logger.debug(
2827 "Descriptor config > {}".format(descriptor_config)
2828 )
tierno588547c2020-07-01 15:30:20 +00002829 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002830 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002831 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002832 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002833 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002834 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002835 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002836 logging_text=logging_text
2837 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2838 member_vnf_index, vdu_id, vdu_index
2839 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002840 db_nsr=db_nsr,
2841 db_vnfr=db_vnfr,
2842 nslcmop_id=nslcmop_id,
2843 nsr_id=nsr_id,
2844 nsi_id=nsi_id,
2845 vnfd_id=vnfd_id,
2846 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002847 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002848 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002849 member_vnf_index=member_vnf_index,
2850 vdu_index=vdu_index,
2851 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002852 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002853 descriptor_config=descriptor_config,
2854 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002855 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002856 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002857 )
bravof922c4172020-11-24 21:21:43 -03002858 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002859 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002860 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002861 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002862 vdu_id = None
2863 vdu_index = 0
2864 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002865 kdu_index, kdur = next(
2866 x
2867 for x in enumerate(db_vnfr["kdur"])
2868 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002869 )
bravof922c4172020-11-24 21:21:43 -03002870 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002871 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002872 deploy_params_kdu.update(
2873 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002874 )
tierno59d22d22018-09-25 18:10:19 +02002875
calvinosanch9f9c6f22019-11-04 13:37:39 +01002876 self._deploy_n2vc(
2877 logging_text=logging_text,
2878 db_nsr=db_nsr,
2879 db_vnfr=db_vnfr,
2880 nslcmop_id=nslcmop_id,
2881 nsr_id=nsr_id,
2882 nsi_id=nsi_id,
2883 vnfd_id=vnfd_id,
2884 vdu_id=vdu_id,
2885 kdu_name=kdu_name,
2886 member_vnf_index=member_vnf_index,
2887 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002888 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002889 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002890 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002891 descriptor_config=descriptor_config,
2892 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002893 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002894 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002895 )
tierno59d22d22018-09-25 18:10:19 +02002896
k4.rahul74944982023-04-19 17:00:52 +05302897 # Check if each vnf has exporter for metric collection if so update prometheus job records
2898 if "exporters-endpoints" in vnfd.get("df")[0]:
2899 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2900 self.logger.debug("exporter config :{}".format(exporter_config))
2901 artifact_path = "{}/{}/{}".format(
2902 base_folder["folder"],
2903 base_folder["pkg-dir"],
2904 "exporter-endpoint",
2905 )
2906 ee_id = None
2907 ee_config_descriptor = exporter_config
2908 vnfr_id = db_vnfr["id"]
2909 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2910 logging_text,
2911 nsr_id,
2912 vnfr_id,
2913 vdu_id=None,
2914 vdu_index=None,
2915 user=None,
2916 pub_key=None,
2917 )
2918 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2919 self.logger.debug("Artifact_path:{}".format(artifact_path))
2920 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2921 vdu_id_for_prom = None
2922 vdu_index_for_prom = None
2923 for x in get_iterable(db_vnfr, "vdur"):
2924 vdu_id_for_prom = x.get("vdu-id-ref")
2925 vdu_index_for_prom = x.get("count-index")
2926 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2927 ee_id=ee_id,
2928 artifact_path=artifact_path,
2929 ee_config_descriptor=ee_config_descriptor,
2930 vnfr_id=vnfr_id,
2931 nsr_id=nsr_id,
2932 target_ip=rw_mgmt_ip,
2933 element_type="VDU",
2934 vdu_id=vdu_id_for_prom,
2935 vdu_index=vdu_index_for_prom,
2936 )
2937
2938 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2939 if prometheus_jobs:
2940 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2941 self.update_db_2(
2942 "nsrs",
2943 nsr_id,
2944 db_nsr_update,
2945 )
2946
2947 for job in prometheus_jobs:
2948 self.db.set_one(
2949 "prometheus_jobs",
2950 {"job_name": job["job_name"]},
2951 job,
2952 upsert=True,
2953 fail_on_empty=False,
2954 )
2955
tierno1b633412019-02-25 16:48:23 +00002956 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002957 descriptor_config = nsd.get("ns-configuration")
2958 if descriptor_config and descriptor_config.get("juju"):
2959 vnfd_id = None
2960 db_vnfr = None
2961 member_vnf_index = None
2962 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002963 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002964 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00002965 vdu_index = 0
2966 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002967
tiernod8323042019-08-09 11:32:23 +00002968 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002969 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002970 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002971 deploy_params.update(
2972 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2973 )
tiernod8323042019-08-09 11:32:23 +00002974 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002975 self._deploy_n2vc(
2976 logging_text=logging_text,
2977 db_nsr=db_nsr,
2978 db_vnfr=db_vnfr,
2979 nslcmop_id=nslcmop_id,
2980 nsr_id=nsr_id,
2981 nsi_id=nsi_id,
2982 vnfd_id=vnfd_id,
2983 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002984 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002985 member_vnf_index=member_vnf_index,
2986 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002987 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002988 vdu_name=vdu_name,
2989 deploy_params=deploy_params,
2990 descriptor_config=descriptor_config,
2991 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002992 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002993 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002994 )
tierno1b633412019-02-25 16:48:23 +00002995
tiernoe876f672020-02-13 14:34:48 +00002996 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002997
garciadeblas5697b8b2021-03-24 09:17:02 +01002998 except (
2999 ROclient.ROClientException,
3000 DbException,
3001 LcmException,
3002 N2VCException,
3003 ) as e:
3004 self.logger.error(
3005 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3006 )
tierno59d22d22018-09-25 18:10:19 +02003007 exc = e
3008 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003009 self.logger.error(
3010 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3011 )
tierno59d22d22018-09-25 18:10:19 +02003012 exc = "Operation was cancelled"
3013 except Exception as e:
3014 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003015 self.logger.critical(
3016 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3017 exc_info=True,
3018 )
tierno59d22d22018-09-25 18:10:19 +02003019 finally:
3020 if exc:
tiernoe876f672020-02-13 14:34:48 +00003021 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003022 try:
tiernoe876f672020-02-13 14:34:48 +00003023 # wait for pending tasks
3024 if tasks_dict_info:
3025 stage[1] = "Waiting for instantiate pending tasks."
3026 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003027 error_list += await self._wait_for_tasks(
3028 logging_text,
3029 tasks_dict_info,
3030 timeout_ns_deploy,
3031 stage,
3032 nslcmop_id,
3033 nsr_id=nsr_id,
3034 )
tiernoe876f672020-02-13 14:34:48 +00003035 stage[1] = stage[2] = ""
3036 except asyncio.CancelledError:
3037 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003038 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3039 await self._wait_for_tasks(
3040 logging_text,
3041 tasks_dict_info,
3042 timeout_ns_deploy,
3043 stage,
3044 nslcmop_id,
3045 nsr_id=nsr_id,
3046 )
tiernoe876f672020-02-13 14:34:48 +00003047 except Exception as exc:
3048 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003049
tiernoe876f672020-02-13 14:34:48 +00003050 # update operation-status
3051 db_nsr_update["operational-status"] = "running"
3052 # let's begin with VCA 'configured' status (later we can change it)
3053 db_nsr_update["config-status"] = "configured"
3054 for task, task_name in tasks_dict_info.items():
3055 if not task.done() or task.cancelled() or task.exception():
3056 if task_name.startswith(self.task_name_deploy_vca):
3057 # A N2VC task is pending
3058 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003059 else:
tiernoe876f672020-02-13 14:34:48 +00003060 # RO or KDU task is pending
3061 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003062
tiernoe876f672020-02-13 14:34:48 +00003063 # update status at database
3064 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003065 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003066 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003067 error_description_nslcmop = "{} Detail: {}".format(
3068 stage[0], error_detail
3069 )
3070 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3071 nslcmop_id, stage[0]
3072 )
quilesj3655ae02019-12-12 16:08:35 +00003073
garciadeblas5697b8b2021-03-24 09:17:02 +01003074 db_nsr_update["detailed-status"] = (
3075 error_description_nsr + " Detail: " + error_detail
3076 )
tiernoe876f672020-02-13 14:34:48 +00003077 db_nslcmop_update["detailed-status"] = error_detail
3078 nslcmop_operation_state = "FAILED"
3079 ns_state = "BROKEN"
3080 else:
tiernoa2143262020-03-27 16:20:40 +00003081 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003082 error_description_nsr = error_description_nslcmop = None
3083 ns_state = "READY"
3084 db_nsr_update["detailed-status"] = "Done"
3085 db_nslcmop_update["detailed-status"] = "Done"
3086 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003087 # Gather auto-healing and auto-scaling alerts for each vnfr
3088 healing_alerts = []
3089 scaling_alerts = []
3090 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3091 vnfd = next(
3092 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3093 )
3094 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3095 for alert in healing_alerts:
3096 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3097 self.db.create("alerts", alert)
3098
3099 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3100 for alert in scaling_alerts:
3101 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3102 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003103
garciadeblas9148fa82023-05-30 12:51:14 +02003104 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3105 for alert in alarm_alerts:
3106 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3107 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003108 if db_nsr:
3109 self._write_ns_status(
3110 nsr_id=nsr_id,
3111 ns_state=ns_state,
3112 current_operation="IDLE",
3113 current_operation_id=None,
3114 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003115 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003116 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003117 )
tiernoa17d4f42020-04-28 09:59:23 +00003118 self._write_op_status(
3119 op_id=nslcmop_id,
3120 stage="",
3121 error_message=error_description_nslcmop,
3122 operation_state=nslcmop_operation_state,
3123 other_update=db_nslcmop_update,
3124 )
quilesj3655ae02019-12-12 16:08:35 +00003125
tierno59d22d22018-09-25 18:10:19 +02003126 if nslcmop_operation_state:
3127 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003128 await self.msg.aiowrite(
3129 "ns",
3130 "instantiated",
3131 {
3132 "nsr_id": nsr_id,
3133 "nslcmop_id": nslcmop_id,
3134 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003135 "startTime": db_nslcmop["startTime"],
3136 "links": db_nslcmop["links"],
3137 "operationParams": {
3138 "nsInstanceId": nsr_id,
3139 "nsdId": db_nsr["nsd-id"],
3140 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003141 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003142 )
tierno59d22d22018-09-25 18:10:19 +02003143 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003144 self.logger.error(
3145 logging_text + "kafka_write notification Exception {}".format(e)
3146 )
tierno59d22d22018-09-25 18:10:19 +02003147
3148 self.logger.debug(logging_text + "Exit")
3149 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3150
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003151 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003152 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003153 cached_vnfds[vnfd_id] = self.db.get_one(
3154 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3155 )
David Garciab4ebcd02021-10-28 02:00:43 +02003156 return cached_vnfds[vnfd_id]
3157
3158 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3159 if vnf_profile_id not in cached_vnfrs:
3160 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3161 "vnfrs",
3162 {
3163 "member-vnf-index-ref": vnf_profile_id,
3164 "nsr-id-ref": nsr_id,
3165 },
3166 )
3167 return cached_vnfrs[vnf_profile_id]
3168
3169 def _is_deployed_vca_in_relation(
3170 self, vca: DeployedVCA, relation: Relation
3171 ) -> bool:
3172 found = False
3173 for endpoint in (relation.provider, relation.requirer):
3174 if endpoint["kdu-resource-profile-id"]:
3175 continue
3176 found = (
3177 vca.vnf_profile_id == endpoint.vnf_profile_id
3178 and vca.vdu_profile_id == endpoint.vdu_profile_id
3179 and vca.execution_environment_ref == endpoint.execution_environment_ref
3180 )
3181 if found:
3182 break
3183 return found
3184
3185 def _update_ee_relation_data_with_implicit_data(
3186 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3187 ):
3188 ee_relation_data = safe_get_ee_relation(
3189 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3190 )
3191 ee_relation_level = EELevel.get_level(ee_relation_data)
3192 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3193 "execution-environment-ref"
3194 ]:
3195 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3196 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003197 project = nsd["_admin"]["projects_read"][0]
3198 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003199 entity_id = (
3200 vnfd_id
3201 if ee_relation_level == EELevel.VNF
3202 else ee_relation_data["vdu-profile-id"]
3203 )
3204 ee = get_juju_ee_ref(db_vnfd, entity_id)
3205 if not ee:
3206 raise Exception(
3207 f"not execution environments found for ee_relation {ee_relation_data}"
3208 )
3209 ee_relation_data["execution-environment-ref"] = ee["id"]
3210 return ee_relation_data
3211
3212 def _get_ns_relations(
3213 self,
3214 nsr_id: str,
3215 nsd: Dict[str, Any],
3216 vca: DeployedVCA,
3217 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003218 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003219 relations = []
3220 db_ns_relations = get_ns_configuration_relation_list(nsd)
3221 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003222 provider_dict = None
3223 requirer_dict = None
3224 if all(key in r for key in ("provider", "requirer")):
3225 provider_dict = r["provider"]
3226 requirer_dict = r["requirer"]
3227 elif "entities" in r:
3228 provider_id = r["entities"][0]["id"]
3229 provider_dict = {
3230 "nsr-id": nsr_id,
3231 "endpoint": r["entities"][0]["endpoint"],
3232 }
3233 if provider_id != nsd["id"]:
3234 provider_dict["vnf-profile-id"] = provider_id
3235 requirer_id = r["entities"][1]["id"]
3236 requirer_dict = {
3237 "nsr-id": nsr_id,
3238 "endpoint": r["entities"][1]["endpoint"],
3239 }
3240 if requirer_id != nsd["id"]:
3241 requirer_dict["vnf-profile-id"] = requirer_id
3242 else:
aticig15db6142022-01-24 12:51:26 +03003243 raise Exception(
3244 "provider/requirer or entities must be included in the relation."
3245 )
David Garciab4ebcd02021-10-28 02:00:43 +02003246 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003247 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003248 )
3249 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003250 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003251 )
3252 provider = EERelation(relation_provider)
3253 requirer = EERelation(relation_requirer)
3254 relation = Relation(r["name"], provider, requirer)
3255 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3256 if vca_in_relation:
3257 relations.append(relation)
3258 return relations
3259
3260 def _get_vnf_relations(
3261 self,
3262 nsr_id: str,
3263 nsd: Dict[str, Any],
3264 vca: DeployedVCA,
3265 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003266 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003267 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003268 if vca.target_element == "ns":
3269 self.logger.debug("VCA is a NS charm, not a VNF.")
3270 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003271 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3272 vnf_profile_id = vnf_profile["id"]
3273 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003274 project = nsd["_admin"]["projects_read"][0]
3275 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003276 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3277 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003278 provider_dict = None
3279 requirer_dict = None
3280 if all(key in r for key in ("provider", "requirer")):
3281 provider_dict = r["provider"]
3282 requirer_dict = r["requirer"]
3283 elif "entities" in r:
3284 provider_id = r["entities"][0]["id"]
3285 provider_dict = {
3286 "nsr-id": nsr_id,
3287 "vnf-profile-id": vnf_profile_id,
3288 "endpoint": r["entities"][0]["endpoint"],
3289 }
3290 if provider_id != vnfd_id:
3291 provider_dict["vdu-profile-id"] = provider_id
3292 requirer_id = r["entities"][1]["id"]
3293 requirer_dict = {
3294 "nsr-id": nsr_id,
3295 "vnf-profile-id": vnf_profile_id,
3296 "endpoint": r["entities"][1]["endpoint"],
3297 }
3298 if requirer_id != vnfd_id:
3299 requirer_dict["vdu-profile-id"] = requirer_id
3300 else:
aticig15db6142022-01-24 12:51:26 +03003301 raise Exception(
3302 "provider/requirer or entities must be included in the relation."
3303 )
David Garciab4ebcd02021-10-28 02:00:43 +02003304 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003305 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003306 )
3307 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003308 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003309 )
3310 provider = EERelation(relation_provider)
3311 requirer = EERelation(relation_requirer)
3312 relation = Relation(r["name"], provider, requirer)
3313 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3314 if vca_in_relation:
3315 relations.append(relation)
3316 return relations
3317
3318 def _get_kdu_resource_data(
3319 self,
3320 ee_relation: EERelation,
3321 db_nsr: Dict[str, Any],
3322 cached_vnfds: Dict[str, Any],
3323 ) -> DeployedK8sResource:
3324 nsd = get_nsd(db_nsr)
3325 vnf_profiles = get_vnf_profiles(nsd)
3326 vnfd_id = find_in_list(
3327 vnf_profiles,
3328 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3329 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003330 project = nsd["_admin"]["projects_read"][0]
3331 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003332 kdu_resource_profile = get_kdu_resource_profile(
3333 db_vnfd, ee_relation.kdu_resource_profile_id
3334 )
3335 kdu_name = kdu_resource_profile["kdu-name"]
3336 deployed_kdu, _ = get_deployed_kdu(
3337 db_nsr.get("_admin", ()).get("deployed", ()),
3338 kdu_name,
3339 ee_relation.vnf_profile_id,
3340 )
3341 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3342 return deployed_kdu
3343
3344 def _get_deployed_component(
3345 self,
3346 ee_relation: EERelation,
3347 db_nsr: Dict[str, Any],
3348 cached_vnfds: Dict[str, Any],
3349 ) -> DeployedComponent:
3350 nsr_id = db_nsr["_id"]
3351 deployed_component = None
3352 ee_level = EELevel.get_level(ee_relation)
3353 if ee_level == EELevel.NS:
3354 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3355 if vca:
3356 deployed_component = DeployedVCA(nsr_id, vca)
3357 elif ee_level == EELevel.VNF:
3358 vca = get_deployed_vca(
3359 db_nsr,
3360 {
3361 "vdu_id": None,
3362 "member-vnf-index": ee_relation.vnf_profile_id,
3363 "ee_descriptor_id": ee_relation.execution_environment_ref,
3364 },
3365 )
3366 if vca:
3367 deployed_component = DeployedVCA(nsr_id, vca)
3368 elif ee_level == EELevel.VDU:
3369 vca = get_deployed_vca(
3370 db_nsr,
3371 {
3372 "vdu_id": ee_relation.vdu_profile_id,
3373 "member-vnf-index": ee_relation.vnf_profile_id,
3374 "ee_descriptor_id": ee_relation.execution_environment_ref,
3375 },
3376 )
3377 if vca:
3378 deployed_component = DeployedVCA(nsr_id, vca)
3379 elif ee_level == EELevel.KDU:
3380 kdu_resource_data = self._get_kdu_resource_data(
3381 ee_relation, db_nsr, cached_vnfds
3382 )
3383 if kdu_resource_data:
3384 deployed_component = DeployedK8sResource(kdu_resource_data)
3385 return deployed_component
3386
3387 async def _add_relation(
3388 self,
3389 relation: Relation,
3390 vca_type: str,
3391 db_nsr: Dict[str, Any],
3392 cached_vnfds: Dict[str, Any],
3393 cached_vnfrs: Dict[str, Any],
3394 ) -> bool:
3395 deployed_provider = self._get_deployed_component(
3396 relation.provider, db_nsr, cached_vnfds
3397 )
3398 deployed_requirer = self._get_deployed_component(
3399 relation.requirer, db_nsr, cached_vnfds
3400 )
3401 if (
3402 deployed_provider
3403 and deployed_requirer
3404 and deployed_provider.config_sw_installed
3405 and deployed_requirer.config_sw_installed
3406 ):
3407 provider_db_vnfr = (
3408 self._get_vnfr(
3409 relation.provider.nsr_id,
3410 relation.provider.vnf_profile_id,
3411 cached_vnfrs,
3412 )
3413 if relation.provider.vnf_profile_id
3414 else None
3415 )
3416 requirer_db_vnfr = (
3417 self._get_vnfr(
3418 relation.requirer.nsr_id,
3419 relation.requirer.vnf_profile_id,
3420 cached_vnfrs,
3421 )
3422 if relation.requirer.vnf_profile_id
3423 else None
3424 )
3425 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3426 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3427 provider_relation_endpoint = RelationEndpoint(
3428 deployed_provider.ee_id,
3429 provider_vca_id,
3430 relation.provider.endpoint,
3431 )
3432 requirer_relation_endpoint = RelationEndpoint(
3433 deployed_requirer.ee_id,
3434 requirer_vca_id,
3435 relation.requirer.endpoint,
3436 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003437 try:
3438 await self.vca_map[vca_type].add_relation(
3439 provider=provider_relation_endpoint,
3440 requirer=requirer_relation_endpoint,
3441 )
3442 except N2VCException as exception:
3443 self.logger.error(exception)
3444 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003445 return True
3446 return False
3447
David Garciac1fe90a2021-03-31 19:12:02 +02003448 async def _add_vca_relations(
3449 self,
3450 logging_text,
3451 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003452 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003453 vca_index: int,
3454 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003455 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003456 # steps:
3457 # 1. find all relations for this VCA
3458 # 2. wait for other peers related
3459 # 3. add relations
3460
3461 try:
quilesj63f90042020-01-17 09:53:55 +00003462 # STEP 1: find all relations for this VCA
3463
3464 # read nsr record
3465 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003466 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003467
3468 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003469 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3470 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003471
David Garciab4ebcd02021-10-28 02:00:43 +02003472 cached_vnfds = {}
3473 cached_vnfrs = {}
3474 relations = []
3475 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3476 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003477
3478 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003479 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003480 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003481 return True
3482
David Garciab4ebcd02021-10-28 02:00:43 +02003483 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003484
3485 # add all relations
3486 start = time()
3487 while True:
3488 # check timeout
3489 now = time()
3490 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003491 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003492 return False
3493
David Garciab4ebcd02021-10-28 02:00:43 +02003494 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003495 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3496
David Garciab4ebcd02021-10-28 02:00:43 +02003497 # for each relation, find the VCA's related
3498 for relation in relations.copy():
3499 added = await self._add_relation(
3500 relation,
3501 vca_type,
3502 db_nsr,
3503 cached_vnfds,
3504 cached_vnfrs,
3505 )
3506 if added:
3507 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003508
David Garciab4ebcd02021-10-28 02:00:43 +02003509 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003510 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003511 break
David Garciab4ebcd02021-10-28 02:00:43 +02003512 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003513
3514 return True
3515
3516 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003517 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003518 return False
3519
garciadeblas5697b8b2021-03-24 09:17:02 +01003520 async def _install_kdu(
3521 self,
3522 nsr_id: str,
3523 nsr_db_path: str,
3524 vnfr_data: dict,
3525 kdu_index: int,
3526 kdud: dict,
3527 vnfd: dict,
3528 k8s_instance_info: dict,
3529 k8params: dict = None,
3530 timeout: int = 600,
3531 vca_id: str = None,
3532 ):
tiernob9018152020-04-16 14:18:24 +00003533 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003534 k8sclustertype = k8s_instance_info["k8scluster-type"]
3535 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003536 db_dict_install = {
3537 "collection": "nsrs",
3538 "filter": {"_id": nsr_id},
3539 "path": nsr_db_path,
3540 }
lloretgalleg7c121132020-07-08 07:53:22 +00003541
romeromonser4554a702021-05-28 12:00:08 +02003542 if k8s_instance_info.get("kdu-deployment-name"):
3543 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3544 else:
3545 kdu_instance = self.k8scluster_map[
3546 k8sclustertype
3547 ].generate_kdu_instance_name(
3548 db_dict=db_dict_install,
3549 kdu_model=k8s_instance_info["kdu-model"],
3550 kdu_name=k8s_instance_info["kdu-name"],
3551 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003552
3553 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003554 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003555 item="nsrs",
3556 _id=nsr_id,
3557 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003558 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003559
3560 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3561 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3562 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3563 # namespace, this first verification could be removed, and the next step would be done for any kind
3564 # of KNF.
3565 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3566 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3567 if k8sclustertype in ("juju", "juju-bundle"):
3568 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3569 # that the user passed a namespace which he wants its KDU to be deployed in)
3570 if (
3571 self.db.count(
3572 table="nsrs",
3573 q_filter={
3574 "_id": nsr_id,
3575 "_admin.projects_write": k8s_instance_info["namespace"],
3576 "_admin.projects_read": k8s_instance_info["namespace"],
3577 },
3578 )
3579 > 0
3580 ):
3581 self.logger.debug(
3582 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3583 )
3584 self.update_db_2(
3585 item="nsrs",
3586 _id=nsr_id,
3587 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3588 )
3589 k8s_instance_info["namespace"] = kdu_instance
3590
David Garciad64e2742021-02-25 20:19:18 +01003591 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003592 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3593 kdu_model=k8s_instance_info["kdu-model"],
3594 atomic=True,
3595 params=k8params,
3596 db_dict=db_dict_install,
3597 timeout=timeout,
3598 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003599 namespace=k8s_instance_info["namespace"],
3600 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003601 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003602 )
lloretgalleg7c121132020-07-08 07:53:22 +00003603
3604 # Obtain services to obtain management service ip
3605 services = await self.k8scluster_map[k8sclustertype].get_services(
3606 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3607 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003608 namespace=k8s_instance_info["namespace"],
3609 )
lloretgalleg7c121132020-07-08 07:53:22 +00003610
3611 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003612 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003613 kdu_config = get_configuration(vnfd, kdud["name"])
3614 if kdu_config:
3615 target_ee_list = kdu_config.get("execution-environment-list", [])
3616 else:
3617 target_ee_list = []
3618
lloretgalleg7c121132020-07-08 07:53:22 +00003619 if services:
tierno7ecbc342020-09-21 14:05:39 +00003620 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003621 mgmt_services = [
3622 service
3623 for service in kdud.get("service", [])
3624 if service.get("mgmt-service")
3625 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003626 for mgmt_service in mgmt_services:
3627 for service in services:
3628 if service["name"].startswith(mgmt_service["name"]):
3629 # Mgmt service found, Obtain service ip
3630 ip = service.get("external_ip", service.get("cluster_ip"))
3631 if isinstance(ip, list) and len(ip) == 1:
3632 ip = ip[0]
3633
garciadeblas5697b8b2021-03-24 09:17:02 +01003634 vnfr_update_dict[
3635 "kdur.{}.ip-address".format(kdu_index)
3636 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003637
3638 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003639 service_external_cp = mgmt_service.get(
3640 "external-connection-point-ref"
3641 )
lloretgalleg7c121132020-07-08 07:53:22 +00003642 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003643 if (
3644 deep_get(vnfd, ("mgmt-interface", "cp"))
3645 == service_external_cp
3646 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003647 vnfr_update_dict["ip-address"] = ip
3648
bravof6ec62b72021-02-25 17:20:35 -03003649 if find_in_list(
3650 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003651 lambda ee: ee.get(
3652 "external-connection-point-ref", ""
3653 )
3654 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003655 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003656 vnfr_update_dict[
3657 "kdur.{}.ip-address".format(kdu_index)
3658 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003659 break
3660 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003661 self.logger.warn(
3662 "Mgmt service name: {} not found".format(
3663 mgmt_service["name"]
3664 )
3665 )
lloretgalleg7c121132020-07-08 07:53:22 +00003666
tierno7ecbc342020-09-21 14:05:39 +00003667 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3668 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003669
bravof9a256db2021-02-22 18:02:07 -03003670 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003671 if (
3672 kdu_config
3673 and kdu_config.get("initial-config-primitive")
3674 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
jegan99448902024-12-06 07:19:34 +00003675 and get_helm_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
garciadeblas5697b8b2021-03-24 09:17:02 +01003676 ):
3677 initial_config_primitive_list = kdu_config.get(
3678 "initial-config-primitive"
3679 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003680 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3681
3682 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003683 primitive_params_ = self._map_primitive_params(
3684 initial_config_primitive, {}, {}
3685 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003686
3687 await asyncio.wait_for(
3688 self.k8scluster_map[k8sclustertype].exec_primitive(
3689 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3690 kdu_instance=kdu_instance,
3691 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003692 params=primitive_params_,
3693 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003694 vca_id=vca_id,
3695 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003696 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003697 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003698
tiernob9018152020-04-16 14:18:24 +00003699 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003700 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003701 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003702 self.update_db_2(
3703 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3704 )
3705 self.update_db_2(
3706 "vnfrs",
3707 vnfr_data.get("_id"),
3708 {"kdur.{}.status".format(kdu_index): "ERROR"},
3709 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003710 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003711 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003712 self.logger.warning(
3713 f"An exception occurred while updating DB: {str(error)}"
3714 )
lloretgalleg7c121132020-07-08 07:53:22 +00003715 # reraise original error
3716 raise
3717
3718 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003719
garciadeblas5697b8b2021-03-24 09:17:02 +01003720 async def deploy_kdus(
3721 self,
3722 logging_text,
3723 nsr_id,
3724 nslcmop_id,
3725 db_vnfrs,
3726 db_vnfds,
3727 task_instantiation_info,
3728 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003729 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003730
garciadeblas5697b8b2021-03-24 09:17:02 +01003731 k8scluster_id_2_uuic = {
3732 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003733 "juju-bundle": {},
3734 }
tierno626e0152019-11-29 14:16:16 +00003735
tierno16f4a4e2020-07-20 09:05:51 +00003736 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003737 nonlocal k8scluster_id_2_uuic
3738 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3739 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3740
tierno16f4a4e2020-07-20 09:05:51 +00003741 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003742 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3743 "k8scluster", cluster_id
3744 )
tierno16f4a4e2020-07-20 09:05:51 +00003745 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003746 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3747 task_name, cluster_id
3748 )
tierno16f4a4e2020-07-20 09:05:51 +00003749 self.logger.debug(logging_text + text)
3750 await asyncio.wait(task_dependency, timeout=3600)
3751
garciadeblas5697b8b2021-03-24 09:17:02 +01003752 db_k8scluster = self.db.get_one(
3753 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3754 )
tierno626e0152019-11-29 14:16:16 +00003755 if not db_k8scluster:
3756 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003757
tierno626e0152019-11-29 14:16:16 +00003758 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3759 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003760 if cluster_type == "helm-chart-v3":
3761 try:
3762 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003763 k8s_credentials = yaml.safe_dump(
3764 db_k8scluster.get("credentials")
3765 )
3766 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3767 k8s_credentials, reuse_cluster_uuid=cluster_id
3768 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003769 db_k8scluster_update = {}
3770 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3771 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003772 db_k8scluster_update[
3773 "_admin.helm-chart-v3.created"
3774 ] = uninstall_sw
3775 db_k8scluster_update[
3776 "_admin.helm-chart-v3.operationalState"
3777 ] = "ENABLED"
3778 self.update_db_2(
3779 "k8sclusters", cluster_id, db_k8scluster_update
3780 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003781 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003782 self.logger.error(
3783 logging_text
3784 + "error initializing helm-v3 cluster: {}".format(str(e))
3785 )
3786 raise LcmException(
3787 "K8s cluster '{}' has not been initialized for '{}'".format(
3788 cluster_id, cluster_type
3789 )
3790 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003791 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003792 raise LcmException(
3793 "K8s cluster '{}' has not been initialized for '{}'".format(
3794 cluster_id, cluster_type
3795 )
3796 )
tierno626e0152019-11-29 14:16:16 +00003797 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3798 return k8s_id
3799
3800 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003801 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003802 try:
tierno626e0152019-11-29 14:16:16 +00003803 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003804 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003805
tierno626e0152019-11-29 14:16:16 +00003806 index = 0
tiernoe876f672020-02-13 14:34:48 +00003807 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003808 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003809
tierno626e0152019-11-29 14:16:16 +00003810 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003811 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003812 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3813 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003814 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003815 vnfd_id = vnfr_data.get("vnfd-id")
3816 vnfd_with_id = find_in_list(
3817 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3818 )
3819 kdud = next(
3820 kdud
3821 for kdud in vnfd_with_id["kdu"]
3822 if kdud["name"] == kdur["kdu-name"]
3823 )
tiernode1584f2020-04-07 09:07:33 +00003824 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003825 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003826 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003827 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003828 # Default version: helm3, if helm-version is v2 assign v2
3829 k8sclustertype = "helm-chart-v3"
3830 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003831 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003832 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003833 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003834 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003835 raise LcmException(
3836 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3837 "juju-bundle. Maybe an old NBI version is running".format(
3838 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3839 )
3840 )
quilesjacde94f2020-01-23 10:07:08 +00003841 # check if kdumodel is a file and exists
3842 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003843 vnfd_with_id = find_in_list(
3844 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3845 )
3846 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003847 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003848 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003849 if storage["pkg-dir"]:
3850 filename = "{}/{}/{}s/{}".format(
3851 storage["folder"],
3852 storage["pkg-dir"],
3853 k8sclustertype,
3854 kdumodel,
3855 )
3856 else:
3857 filename = "{}/Scripts/{}s/{}".format(
3858 storage["folder"],
3859 k8sclustertype,
3860 kdumodel,
3861 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003862 if self.fs.file_exists(
3863 filename, mode="file"
3864 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003865 kdumodel = self.fs.path + filename
3866 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003867 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003868 except Exception as e: # it is not a file
3869 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003870
tiernoe876f672020-02-13 14:34:48 +00003871 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003872 step = "Synchronize repos for k8s cluster '{}'".format(
3873 k8s_cluster_id
3874 )
tierno16f4a4e2020-07-20 09:05:51 +00003875 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003876
lloretgalleg7c121132020-07-08 07:53:22 +00003877 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003878 if (
3879 k8sclustertype == "helm-chart"
3880 and cluster_uuid not in updated_cluster_list
3881 ) or (
3882 k8sclustertype == "helm-chart-v3"
3883 and cluster_uuid not in updated_v3_cluster_list
3884 ):
tiernoe876f672020-02-13 14:34:48 +00003885 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003886 self.k8scluster_map[k8sclustertype].synchronize_repos(
3887 cluster_uuid=cluster_uuid
3888 )
3889 )
tiernoe876f672020-02-13 14:34:48 +00003890 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003891 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003892 unset = {
3893 "_admin.helm_charts_added." + item: None
3894 for item in del_repo_list
3895 }
3896 updated = {
3897 "_admin.helm_charts_added." + item: name
3898 for item, name in added_repo_dict.items()
3899 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003900 updated_cluster_list.append(cluster_uuid)
3901 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003902 unset = {
3903 "_admin.helm_charts_v3_added." + item: None
3904 for item in del_repo_list
3905 }
3906 updated = {
3907 "_admin.helm_charts_v3_added." + item: name
3908 for item, name in added_repo_dict.items()
3909 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003910 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003911 self.logger.debug(
3912 logging_text + "repos synchronized on k8s cluster "
3913 "'{}' to_delete: {}, to_add: {}".format(
3914 k8s_cluster_id, del_repo_list, added_repo_dict
3915 )
3916 )
3917 self.db.set_one(
3918 "k8sclusters",
3919 {"_id": k8s_cluster_id},
3920 updated,
3921 unset=unset,
3922 )
lloretgallegedc5f332020-02-20 11:50:50 +01003923
lloretgalleg7c121132020-07-08 07:53:22 +00003924 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003925 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3926 vnfr_data["member-vnf-index-ref"],
3927 kdur["kdu-name"],
3928 k8s_cluster_id,
3929 )
3930 k8s_instance_info = {
3931 "kdu-instance": None,
3932 "k8scluster-uuid": cluster_uuid,
3933 "k8scluster-type": k8sclustertype,
3934 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3935 "kdu-name": kdur["kdu-name"],
3936 "kdu-model": kdumodel,
3937 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003938 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003939 }
tiernob9018152020-04-16 14:18:24 +00003940 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003941 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003942 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003943 vnfd_with_id = find_in_list(
3944 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3945 )
tiernoa2143262020-03-27 16:20:40 +00003946 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003947 self._install_kdu(
3948 nsr_id,
3949 db_path,
3950 vnfr_data,
3951 kdu_index,
3952 kdud,
3953 vnfd_with_id,
3954 k8s_instance_info,
3955 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003956 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003957 vca_id=vca_id,
3958 )
3959 )
3960 self.lcm_tasks.register(
3961 "ns",
3962 nsr_id,
3963 nslcmop_id,
3964 "instantiate_KDU-{}".format(index),
3965 task,
3966 )
3967 task_instantiation_info[task] = "Deploying KDU {}".format(
3968 kdur["kdu-name"]
3969 )
tiernoe876f672020-02-13 14:34:48 +00003970
tierno626e0152019-11-29 14:16:16 +00003971 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003972
tiernoe876f672020-02-13 14:34:48 +00003973 except (LcmException, asyncio.CancelledError):
3974 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003975 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003976 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3977 if isinstance(e, (N2VCException, DbException)):
3978 self.logger.error(logging_text + msg)
3979 else:
3980 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003981 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003982 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003983 if db_nsr_update:
3984 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003985
garciadeblas5697b8b2021-03-24 09:17:02 +01003986 def _deploy_n2vc(
3987 self,
3988 logging_text,
3989 db_nsr,
3990 db_vnfr,
3991 nslcmop_id,
3992 nsr_id,
3993 nsi_id,
3994 vnfd_id,
3995 vdu_id,
3996 kdu_name,
3997 member_vnf_index,
3998 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003999 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004000 vdu_name,
4001 deploy_params,
4002 descriptor_config,
4003 base_folder,
4004 task_instantiation_info,
4005 stage,
4006 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004007 # launch instantiate_N2VC in a asyncio task and register task object
4008 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4009 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004010 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004011
garciadeblas5697b8b2021-03-24 09:17:02 +01004012 self.logger.debug(
4013 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4014 )
aticig9bc63ac2022-07-27 09:32:06 +03004015
4016 charm_name = ""
4017 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004018 if "execution-environment-list" in descriptor_config:
4019 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004020 elif "juju" in descriptor_config:
4021 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004022 if "execution-environment-list" not in descriptor_config:
4023 # charm name is only required for ns charms
4024 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004025 else: # other types as script are not supported
4026 ee_list = []
4027
4028 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004029 self.logger.debug(
4030 logging_text
4031 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4032 ee_item.get("juju"), ee_item.get("helm-chart")
4033 )
4034 )
tiernoa278b842020-07-08 15:33:55 +00004035 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05004036 vca_name, charm_name, vca_type = self.get_vca_info(
4037 ee_item, db_nsr, get_charm_name
4038 )
4039 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004040 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004041 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004042 )
quilesj7e13aeb2019-10-08 13:34:55 +02004043 continue
quilesj3655ae02019-12-12 16:08:35 +00004044
tierno588547c2020-07-01 15:30:20 +00004045 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004046 for vca_index, vca_deployed in enumerate(
4047 db_nsr["_admin"]["deployed"]["VCA"]
4048 ):
tierno588547c2020-07-01 15:30:20 +00004049 if not vca_deployed:
4050 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004051 if (
4052 vca_deployed.get("member-vnf-index") == member_vnf_index
4053 and vca_deployed.get("vdu_id") == vdu_id
4054 and vca_deployed.get("kdu_name") == kdu_name
4055 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4056 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4057 ):
tierno588547c2020-07-01 15:30:20 +00004058 break
4059 else:
4060 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004061 target = (
4062 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4063 )
tiernoa278b842020-07-08 15:33:55 +00004064 if vdu_id:
4065 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4066 elif kdu_name:
4067 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004068 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004069 "target_element": target,
4070 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004071 "member-vnf-index": member_vnf_index,
4072 "vdu_id": vdu_id,
4073 "kdu_name": kdu_name,
4074 "vdu_count_index": vdu_index,
4075 "operational-status": "init", # TODO revise
4076 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004077 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004078 "vnfd_id": vnfd_id,
4079 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004080 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004081 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004082 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004083 }
4084 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004085
tierno588547c2020-07-01 15:30:20 +00004086 # create VCA and configurationStatus in db
4087 db_dict = {
4088 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004089 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004090 }
4091 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004092
tierno588547c2020-07-01 15:30:20 +00004093 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4094
bravof922c4172020-11-24 21:21:43 -03004095 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4096 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4097 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4098
tierno588547c2020-07-01 15:30:20 +00004099 # Launch task
4100 task_n2vc = asyncio.ensure_future(
4101 self.instantiate_N2VC(
4102 logging_text=logging_text,
4103 vca_index=vca_index,
4104 nsi_id=nsi_id,
4105 db_nsr=db_nsr,
4106 db_vnfr=db_vnfr,
4107 vdu_id=vdu_id,
4108 kdu_name=kdu_name,
4109 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004110 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004111 deploy_params=deploy_params,
4112 config_descriptor=descriptor_config,
4113 base_folder=base_folder,
4114 nslcmop_id=nslcmop_id,
4115 stage=stage,
4116 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004117 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004118 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004119 )
quilesj7e13aeb2019-10-08 13:34:55 +02004120 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004121 self.lcm_tasks.register(
4122 "ns",
4123 nsr_id,
4124 nslcmop_id,
4125 "instantiate_N2VC-{}".format(vca_index),
4126 task_n2vc,
4127 )
4128 task_instantiation_info[
4129 task_n2vc
4130 ] = self.task_name_deploy_vca + " {}.{}".format(
4131 member_vnf_index or "", vdu_id or ""
4132 )
tiernobaa51102018-12-14 13:16:18 +00004133
calvinosanch9f9c6f22019-11-04 13:37:39 +01004134 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004135 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004136 for key, value in params.items():
4137 if str(value).startswith("!!yaml "):
4138 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004139 return params
4140
kuuse8b998e42019-07-30 15:22:16 +02004141 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004142 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004143 primitive_params = {}
4144 params = {
4145 "member_vnf_index": vnf_index,
4146 "primitive": primitive,
4147 "primitive_params": primitive_params,
4148 }
4149 desc_params = {}
4150 return self._map_primitive_params(seq, params, desc_params)
4151
kuuseac3a8882019-10-03 10:48:06 +02004152 # sub-operations
4153
tierno51183952020-04-03 15:48:18 +00004154 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004155 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4156 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004157 # b. Skip sub-operation
4158 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4159 return self.SUBOPERATION_STATUS_SKIP
4160 else:
tierno7c4e24c2020-05-13 08:41:35 +00004161 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004162 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004163 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004164 operationState = "PROCESSING"
4165 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004166 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004167 db_nslcmop, op_index, operationState, detailed_status
4168 )
kuuseac3a8882019-10-03 10:48:06 +02004169 # Return the sub-operation index
4170 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4171 # with arguments extracted from the sub-operation
4172 return op_index
4173
4174 # Find a sub-operation where all keys in a matching dictionary must match
4175 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4176 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004177 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004178 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004179 for i, op in enumerate(op_list):
4180 if all(op.get(k) == match[k] for k in match):
4181 return i
4182 return self.SUBOPERATION_STATUS_NOT_FOUND
4183
4184 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004185 def _update_suboperation_status(
4186 self, db_nslcmop, op_index, operationState, detailed_status
4187 ):
kuuseac3a8882019-10-03 10:48:06 +02004188 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004189 q_filter = {"_id": db_nslcmop["_id"]}
4190 update_dict = {
4191 "_admin.operations.{}.operationState".format(op_index): operationState,
4192 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4193 }
4194 self.db.set_one(
4195 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4196 )
kuuseac3a8882019-10-03 10:48:06 +02004197
4198 # Add sub-operation, return the index of the added sub-operation
4199 # Optionally, set operationState, detailed-status, and operationType
4200 # Status and type are currently set for 'scale' sub-operations:
4201 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4202 # 'detailed-status' : status message
4203 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4204 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004205 def _add_suboperation(
4206 self,
4207 db_nslcmop,
4208 vnf_index,
4209 vdu_id,
4210 vdu_count_index,
4211 vdu_name,
4212 primitive,
4213 mapped_primitive_params,
4214 operationState=None,
4215 detailed_status=None,
4216 operationType=None,
4217 RO_nsr_id=None,
4218 RO_scaling_info=None,
4219 ):
tiernoe876f672020-02-13 14:34:48 +00004220 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004221 return self.SUBOPERATION_STATUS_NOT_FOUND
4222 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004223 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4224 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004225 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004226 new_op = {
4227 "member_vnf_index": vnf_index,
4228 "vdu_id": vdu_id,
4229 "vdu_count_index": vdu_count_index,
4230 "primitive": primitive,
4231 "primitive_params": mapped_primitive_params,
4232 }
kuuseac3a8882019-10-03 10:48:06 +02004233 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004234 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004235 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004236 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004237 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004238 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004239 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004240 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004241 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004242 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004243 if not op_list:
4244 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004245 db_nslcmop_admin.update({"operations": [new_op]})
4246 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004247 else:
4248 # Existing operations, append operation to list
4249 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004250
garciadeblas5697b8b2021-03-24 09:17:02 +01004251 db_nslcmop_update = {"_admin.operations": op_list}
4252 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004253 op_index = len(op_list) - 1
4254 return op_index
4255
4256 # Helper methods for scale() sub-operations
4257
4258 # pre-scale/post-scale:
4259 # Check for 3 different cases:
4260 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4261 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004262 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004263 def _check_or_add_scale_suboperation(
4264 self,
4265 db_nslcmop,
4266 vnf_index,
4267 vnf_config_primitive,
4268 primitive_params,
4269 operationType,
4270 RO_nsr_id=None,
4271 RO_scaling_info=None,
4272 ):
kuuseac3a8882019-10-03 10:48:06 +02004273 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004274 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004275 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004276 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004277 "member_vnf_index": vnf_index,
4278 "RO_nsr_id": RO_nsr_id,
4279 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004280 }
4281 else:
4282 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004283 "member_vnf_index": vnf_index,
4284 "primitive": vnf_config_primitive,
4285 "primitive_params": primitive_params,
4286 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004287 }
4288 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004289 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004290 # a. New sub-operation
4291 # The sub-operation does not exist, add it.
4292 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4293 # The following parameters are set to None for all kind of scaling:
4294 vdu_id = None
4295 vdu_count_index = None
4296 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004297 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004298 vnf_config_primitive = None
4299 primitive_params = None
4300 else:
4301 RO_nsr_id = None
4302 RO_scaling_info = None
4303 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004304 operationState = "PROCESSING"
4305 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004306 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004307 self._add_suboperation(
4308 db_nslcmop,
4309 vnf_index,
4310 vdu_id,
4311 vdu_count_index,
4312 vdu_name,
4313 vnf_config_primitive,
4314 primitive_params,
4315 operationState,
4316 detailed_status,
4317 operationType,
4318 RO_nsr_id,
4319 RO_scaling_info,
4320 )
kuuseac3a8882019-10-03 10:48:06 +02004321 return self.SUBOPERATION_STATUS_NEW
4322 else:
4323 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4324 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004325 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004326
preethika.pdf7d8e02019-12-10 13:10:48 +00004327 # Function to return execution_environment id
4328
David Garciac1fe90a2021-03-31 19:12:02 +02004329 async def destroy_N2VC(
4330 self,
4331 logging_text,
4332 db_nslcmop,
4333 vca_deployed,
4334 config_descriptor,
4335 vca_index,
4336 destroy_ee=True,
4337 exec_primitives=True,
4338 scaling_in=False,
4339 vca_id: str = None,
4340 ):
tiernoe876f672020-02-13 14:34:48 +00004341 """
4342 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4343 :param logging_text:
4344 :param db_nslcmop:
4345 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4346 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4347 :param vca_index: index in the database _admin.deployed.VCA
4348 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004349 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4350 not executed properly
aktas13251562021-02-12 22:19:10 +03004351 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004352 :return: None or exception
4353 """
tiernoe876f672020-02-13 14:34:48 +00004354
tierno588547c2020-07-01 15:30:20 +00004355 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004356 logging_text
4357 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004358 vca_index, vca_deployed, config_descriptor, destroy_ee
4359 )
4360 )
4361
4362 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4363
4364 # execute terminate_primitives
4365 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004366 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004367 config_descriptor.get("terminate-config-primitive"),
4368 vca_deployed.get("ee_descriptor_id"),
4369 )
tierno588547c2020-07-01 15:30:20 +00004370 vdu_id = vca_deployed.get("vdu_id")
4371 vdu_count_index = vca_deployed.get("vdu_count_index")
4372 vdu_name = vca_deployed.get("vdu_name")
4373 vnf_index = vca_deployed.get("member-vnf-index")
4374 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004375 for seq in terminate_primitives:
4376 # For each sequence in list, get primitive and call _ns_execute_primitive()
4377 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004378 vnf_index, seq.get("name")
4379 )
tierno588547c2020-07-01 15:30:20 +00004380 self.logger.debug(logging_text + step)
4381 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004382 primitive = seq.get("name")
4383 mapped_primitive_params = self._get_terminate_primitive_params(
4384 seq, vnf_index
4385 )
tierno588547c2020-07-01 15:30:20 +00004386
4387 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004388 self._add_suboperation(
4389 db_nslcmop,
4390 vnf_index,
4391 vdu_id,
4392 vdu_count_index,
4393 vdu_name,
4394 primitive,
4395 mapped_primitive_params,
4396 )
tierno588547c2020-07-01 15:30:20 +00004397 # Sub-operations: Call _ns_execute_primitive() instead of action()
4398 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004399 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004400 vca_deployed["ee_id"],
4401 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004402 mapped_primitive_params,
4403 vca_type=vca_type,
4404 vca_id=vca_id,
4405 )
tierno588547c2020-07-01 15:30:20 +00004406 except LcmException:
4407 # this happens when VCA is not deployed. In this case it is not needed to terminate
4408 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004409 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004410 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004411 raise LcmException(
4412 "terminate_primitive {} for vnf_member_index={} fails with "
4413 "error {}".format(seq.get("name"), vnf_index, result_detail)
4414 )
tierno588547c2020-07-01 15:30:20 +00004415 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004416 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4417 vca_index
4418 )
4419 self.update_db_2(
4420 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4421 )
tiernoe876f672020-02-13 14:34:48 +00004422
bravof73bac502021-05-11 07:38:47 -04004423 # Delete Prometheus Jobs if any
4424 # This uses NSR_ID, so it will destroy any jobs under this index
4425 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004426
tiernoe876f672020-02-13 14:34:48 +00004427 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004428 await self.vca_map[vca_type].delete_execution_environment(
4429 vca_deployed["ee_id"],
4430 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004431 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004432 vca_id=vca_id,
4433 )
kuuse0ca67472019-05-13 15:59:27 +02004434
David Garciac1fe90a2021-03-31 19:12:02 +02004435 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004436 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004437 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004438 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004439 await self.n2vc.delete_namespace(
4440 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004441 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004442 vca_id=vca_id,
4443 )
tiernof59ad6c2020-04-08 12:50:52 +00004444 except N2VCNotFound: # already deleted. Skip
4445 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004446 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004447
tiernoe876f672020-02-13 14:34:48 +00004448 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004449 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004450 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004451 if not task_is_locked_by_me:
4452 return
4453
tierno59d22d22018-09-25 18:10:19 +02004454 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4455 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004456 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004457 db_nsr = None
4458 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004459 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004460 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004461 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004462 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004463 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004464 tasks_dict_info = {}
4465 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004466 stage = [
4467 "Stage 1/3: Preparing task.",
4468 "Waiting for previous operations to terminate.",
4469 "",
4470 ]
tiernoe876f672020-02-13 14:34:48 +00004471 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004472 try:
kuused124bfe2019-06-18 12:09:24 +02004473 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004474 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004475
tiernoe876f672020-02-13 14:34:48 +00004476 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4477 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4478 operation_params = db_nslcmop.get("operationParams") or {}
4479 if operation_params.get("timeout_ns_terminate"):
4480 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4481 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4482 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4483
4484 db_nsr_update["operational-status"] = "terminating"
4485 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004486 self._write_ns_status(
4487 nsr_id=nsr_id,
4488 ns_state="TERMINATING",
4489 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004490 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004491 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004492 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004493 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004494 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004495 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4496 return
tierno59d22d22018-09-25 18:10:19 +02004497
tiernoe876f672020-02-13 14:34:48 +00004498 stage[1] = "Getting vnf descriptors from db."
4499 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004500 db_vnfrs_dict = {
4501 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4502 }
tiernoe876f672020-02-13 14:34:48 +00004503 db_vnfds_from_id = {}
4504 db_vnfds_from_member_index = {}
4505 # Loop over VNFRs
4506 for vnfr in db_vnfrs_list:
4507 vnfd_id = vnfr["vnfd-id"]
4508 if vnfd_id not in db_vnfds_from_id:
4509 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4510 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004511 db_vnfds_from_member_index[
4512 vnfr["member-vnf-index-ref"]
4513 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004514
tiernoe876f672020-02-13 14:34:48 +00004515 # Destroy individual execution environments when there are terminating primitives.
4516 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004517 # TODO - check before calling _destroy_N2VC
4518 # if not operation_params.get("skip_terminate_primitives"):#
4519 # or not vca.get("needed_terminate"):
4520 stage[0] = "Stage 2/3 execute terminating primitives."
4521 self.logger.debug(logging_text + stage[0])
4522 stage[1] = "Looking execution environment that needs terminate."
4523 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004524
tierno588547c2020-07-01 15:30:20 +00004525 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004526 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004527 vca_member_vnf_index = vca.get("member-vnf-index")
4528 vca_id = self.get_vca_id(
4529 db_vnfrs_dict.get(vca_member_vnf_index)
4530 if vca_member_vnf_index
4531 else None,
4532 db_nsr,
4533 )
tierno588547c2020-07-01 15:30:20 +00004534 if not vca or not vca.get("ee_id"):
4535 continue
4536 if not vca.get("member-vnf-index"):
4537 # ns
4538 config_descriptor = db_nsr.get("ns-configuration")
4539 elif vca.get("vdu_id"):
4540 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004541 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004542 elif vca.get("kdu_name"):
4543 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004544 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004545 else:
bravofe5a31bc2021-02-17 19:09:12 -03004546 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004547 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004548 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004549 exec_terminate_primitives = not operation_params.get(
4550 "skip_terminate_primitives"
4551 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004552 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4553 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004554 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004555 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4556 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004557 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004558 self.destroy_N2VC(
4559 logging_text,
4560 db_nslcmop,
4561 vca,
4562 config_descriptor,
4563 vca_index,
4564 destroy_ee,
4565 exec_terminate_primitives,
4566 vca_id=vca_id,
4567 )
4568 )
tierno588547c2020-07-01 15:30:20 +00004569 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004570
tierno588547c2020-07-01 15:30:20 +00004571 # wait for pending tasks of terminate primitives
4572 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004573 self.logger.debug(
4574 logging_text
4575 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4576 )
4577 error_list = await self._wait_for_tasks(
4578 logging_text,
4579 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004580 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004581 stage,
4582 nslcmop_id,
4583 )
tierno86e33612020-09-16 14:13:06 +00004584 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004585 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004586 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004587
tiernoe876f672020-02-13 14:34:48 +00004588 # remove All execution environments at once
4589 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004590
tierno49676be2020-04-07 16:34:35 +00004591 if nsr_deployed.get("VCA"):
4592 stage[1] = "Deleting all execution environments."
4593 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004594 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4595 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004596 # Delete Namespace and Certificates
4597 await self.vca_map["helm-v3"].delete_tls_certificate(
4598 namespace=db_nslcmop["nsInstanceId"],
4599 certificate_name=self.EE_TLS_NAME,
4600 )
4601 await self.vca_map["helm-v3"].delete_namespace(
4602 namespace=db_nslcmop["nsInstanceId"],
4603 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004604 else:
4605 vca_id = self.get_vca_id({}, db_nsr)
4606 task_delete_ee = asyncio.ensure_future(
4607 asyncio.wait_for(
4608 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4609 timeout=self.timeout.charm_delete,
4610 )
4611 )
4612 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004613
tiernoe876f672020-02-13 14:34:48 +00004614 # Delete from k8scluster
4615 stage[1] = "Deleting KDUs."
4616 self.logger.debug(logging_text + stage[1])
4617 # print(nsr_deployed)
4618 for kdu in get_iterable(nsr_deployed, "K8s"):
4619 if not kdu or not kdu.get("kdu-instance"):
4620 continue
4621 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004622 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004623 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4624 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004625 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004626 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4627 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004628 kdu_instance=kdu_instance,
4629 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004630 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004631 )
4632 )
tiernoe876f672020-02-13 14:34:48 +00004633 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004634 self.logger.error(
4635 logging_text
4636 + "Unknown k8s deployment type {}".format(
4637 kdu.get("k8scluster-type")
4638 )
4639 )
tiernoe876f672020-02-13 14:34:48 +00004640 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004641 tasks_dict_info[
4642 task_delete_kdu_instance
4643 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004644
4645 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004646 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004647 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004648 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004649 self._terminate_ng_ro(
4650 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4651 )
4652 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004653 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004654
tiernoe876f672020-02-13 14:34:48 +00004655 # rest of staff will be done at finally
4656
garciadeblas5697b8b2021-03-24 09:17:02 +01004657 except (
4658 ROclient.ROClientException,
4659 DbException,
4660 LcmException,
4661 N2VCException,
4662 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004663 self.logger.error(logging_text + "Exit Exception {}".format(e))
4664 exc = e
4665 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004666 self.logger.error(
4667 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4668 )
tiernoe876f672020-02-13 14:34:48 +00004669 exc = "Operation was cancelled"
4670 except Exception as e:
4671 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004672 self.logger.critical(
4673 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4674 exc_info=True,
4675 )
tiernoe876f672020-02-13 14:34:48 +00004676 finally:
4677 if exc:
4678 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004679 try:
tiernoe876f672020-02-13 14:34:48 +00004680 # wait for pending tasks
4681 if tasks_dict_info:
4682 stage[1] = "Waiting for terminate pending tasks."
4683 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004684 error_list += await self._wait_for_tasks(
4685 logging_text,
4686 tasks_dict_info,
4687 timeout_ns_terminate,
4688 stage,
4689 nslcmop_id,
4690 )
tiernoe876f672020-02-13 14:34:48 +00004691 stage[1] = stage[2] = ""
4692 except asyncio.CancelledError:
4693 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004694 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4695 await self._wait_for_tasks(
4696 logging_text,
4697 tasks_dict_info,
4698 timeout_ns_terminate,
4699 stage,
4700 nslcmop_id,
4701 )
tiernoe876f672020-02-13 14:34:48 +00004702 except Exception as exc:
4703 error_list.append(str(exc))
4704 # update status at database
4705 if error_list:
4706 error_detail = "; ".join(error_list)
4707 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004708 error_description_nslcmop = "{} Detail: {}".format(
4709 stage[0], error_detail
4710 )
4711 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4712 nslcmop_id, stage[0]
4713 )
tierno59d22d22018-09-25 18:10:19 +02004714
tierno59d22d22018-09-25 18:10:19 +02004715 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004716 db_nsr_update["detailed-status"] = (
4717 error_description_nsr + " Detail: " + error_detail
4718 )
tiernoe876f672020-02-13 14:34:48 +00004719 db_nslcmop_update["detailed-status"] = error_detail
4720 nslcmop_operation_state = "FAILED"
4721 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004722 else:
tiernoa2143262020-03-27 16:20:40 +00004723 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004724 error_description_nsr = error_description_nslcmop = None
4725 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004726 db_nsr_update["operational-status"] = "terminated"
4727 db_nsr_update["detailed-status"] = "Done"
4728 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4729 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004730 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004731
tiernoe876f672020-02-13 14:34:48 +00004732 if db_nsr:
4733 self._write_ns_status(
4734 nsr_id=nsr_id,
4735 ns_state=ns_state,
4736 current_operation="IDLE",
4737 current_operation_id=None,
4738 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004739 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004740 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004741 )
tiernoa17d4f42020-04-28 09:59:23 +00004742 self._write_op_status(
4743 op_id=nslcmop_id,
4744 stage="",
4745 error_message=error_description_nslcmop,
4746 operation_state=nslcmop_operation_state,
4747 other_update=db_nslcmop_update,
4748 )
Rahul Kumar54671c52024-05-09 15:34:01 +05304749 if nslcmop_operation_state == "COMPLETED":
4750 self.db.del_list("prometheus_jobs", {"nsr_id": nsr_id})
lloretgalleg6d488782020-07-22 10:13:46 +00004751 if ns_state == "NOT_INSTANTIATED":
4752 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004753 self.db.set_list(
4754 "vnfrs",
4755 {"nsr-id-ref": nsr_id},
4756 {"_admin.nsState": "NOT_INSTANTIATED"},
4757 )
lloretgalleg6d488782020-07-22 10:13:46 +00004758 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004759 self.logger.warn(
4760 logging_text
4761 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4762 nsr_id, e
4763 )
4764 )
tiernoa17d4f42020-04-28 09:59:23 +00004765 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004766 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004767 if nslcmop_operation_state:
4768 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004769 await self.msg.aiowrite(
4770 "ns",
4771 "terminated",
4772 {
4773 "nsr_id": nsr_id,
4774 "nslcmop_id": nslcmop_id,
4775 "operationState": nslcmop_operation_state,
4776 "autoremove": autoremove,
4777 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004778 )
tierno59d22d22018-09-25 18:10:19 +02004779 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004780 self.logger.error(
4781 logging_text + "kafka_write notification Exception {}".format(e)
4782 )
aguilard1ae3c562023-02-16 17:24:35 +00004783 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4784 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004785
tierno59d22d22018-09-25 18:10:19 +02004786 self.logger.debug(logging_text + "Exit")
4787 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4788
garciadeblas5697b8b2021-03-24 09:17:02 +01004789 async def _wait_for_tasks(
4790 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4791 ):
tiernoe876f672020-02-13 14:34:48 +00004792 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004793 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004794 error_list = []
4795 pending_tasks = list(created_tasks_info.keys())
4796 num_tasks = len(pending_tasks)
4797 num_done = 0
4798 stage[1] = "{}/{}.".format(num_done, num_tasks)
4799 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004800 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004801 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004802 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004803 done, pending_tasks = await asyncio.wait(
4804 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4805 )
tiernoe876f672020-02-13 14:34:48 +00004806 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004807 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004808 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004809 new_error = created_tasks_info[task] + ": Timeout"
4810 error_detail_list.append(new_error)
4811 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004812 break
4813 for task in done:
4814 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004815 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004816 else:
4817 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004818 if exc:
4819 if isinstance(exc, asyncio.TimeoutError):
4820 exc = "Timeout"
4821 new_error = created_tasks_info[task] + ": {}".format(exc)
4822 error_list.append(created_tasks_info[task])
4823 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004824 if isinstance(
4825 exc,
4826 (
4827 str,
4828 DbException,
4829 N2VCException,
4830 ROclient.ROClientException,
4831 LcmException,
4832 K8sException,
4833 NgRoException,
4834 ),
4835 ):
tierno067e04a2020-03-31 12:53:13 +00004836 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004837 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004838 exc_traceback = "".join(
4839 traceback.format_exception(None, exc, exc.__traceback__)
4840 )
4841 self.logger.error(
4842 logging_text
4843 + created_tasks_info[task]
4844 + " "
4845 + exc_traceback
4846 )
tierno067e04a2020-03-31 12:53:13 +00004847 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004848 self.logger.debug(
4849 logging_text + created_tasks_info[task] + ": Done"
4850 )
tiernoe876f672020-02-13 14:34:48 +00004851 stage[1] = "{}/{}.".format(num_done, num_tasks)
4852 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004853 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004854 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004855 self.update_db_2(
4856 "nsrs",
4857 nsr_id,
4858 {
4859 "errorDescription": "Error at: " + ", ".join(error_list),
4860 "errorDetail": ". ".join(error_detail_list),
4861 },
4862 )
tiernoe876f672020-02-13 14:34:48 +00004863 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004864 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004865
Gabriel Cubab6049d32023-10-30 13:44:49 -05004866 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4867 for task, name in created_tasks_info.items():
4868 self.logger.debug(logging_text + "Cancelling task: " + name)
4869 task.cancel()
4870
tiernoda1ff8c2020-10-22 14:12:46 +00004871 @staticmethod
4872 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004873 """
4874 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4875 The default-value is used. If it is between < > it look for a value at instantiation_params
4876 :param primitive_desc: portion of VNFD/NSD that describes primitive
4877 :param params: Params provided by user
4878 :param instantiation_params: Instantiation params provided by user
4879 :return: a dictionary with the calculated params
4880 """
4881 calculated_params = {}
4882 for parameter in primitive_desc.get("parameter", ()):
4883 param_name = parameter["name"]
4884 if param_name in params:
4885 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004886 elif "default-value" in parameter or "value" in parameter:
4887 if "value" in parameter:
4888 calculated_params[param_name] = parameter["value"]
4889 else:
4890 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004891 if (
4892 isinstance(calculated_params[param_name], str)
4893 and calculated_params[param_name].startswith("<")
4894 and calculated_params[param_name].endswith(">")
4895 ):
tierno98ad6ea2019-05-30 17:16:28 +00004896 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004897 calculated_params[param_name] = instantiation_params[
4898 calculated_params[param_name][1:-1]
4899 ]
tiernoda964822019-01-14 15:53:47 +00004900 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004901 raise LcmException(
4902 "Parameter {} needed to execute primitive {} not provided".format(
4903 calculated_params[param_name], primitive_desc["name"]
4904 )
4905 )
tiernoda964822019-01-14 15:53:47 +00004906 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004907 raise LcmException(
4908 "Parameter {} needed to execute primitive {} not provided".format(
4909 param_name, primitive_desc["name"]
4910 )
4911 )
tierno59d22d22018-09-25 18:10:19 +02004912
tiernoda964822019-01-14 15:53:47 +00004913 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004914 calculated_params[param_name] = yaml.safe_dump(
4915 calculated_params[param_name], default_flow_style=True, width=256
4916 )
4917 elif isinstance(calculated_params[param_name], str) and calculated_params[
4918 param_name
4919 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004920 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004921 if parameter.get("data-type") == "INTEGER":
4922 try:
4923 calculated_params[param_name] = int(calculated_params[param_name])
4924 except ValueError: # error converting string to int
4925 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004926 "Parameter {} of primitive {} must be integer".format(
4927 param_name, primitive_desc["name"]
4928 )
4929 )
tiernofa40e692020-10-14 14:59:36 +00004930 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004931 calculated_params[param_name] = not (
4932 (str(calculated_params[param_name])).lower() == "false"
4933 )
tiernoc3f2a822019-11-05 13:45:04 +00004934
4935 # add always ns_config_info if primitive name is config
4936 if primitive_desc["name"] == "config":
4937 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004938 calculated_params["ns_config_info"] = instantiation_params[
4939 "ns_config_info"
4940 ]
tiernoda964822019-01-14 15:53:47 +00004941 return calculated_params
4942
garciadeblas5697b8b2021-03-24 09:17:02 +01004943 def _look_for_deployed_vca(
4944 self,
4945 deployed_vca,
4946 member_vnf_index,
4947 vdu_id,
4948 vdu_count_index,
4949 kdu_name=None,
4950 ee_descriptor_id=None,
4951 ):
tiernoe876f672020-02-13 14:34:48 +00004952 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4953 for vca in deployed_vca:
4954 if not vca:
4955 continue
4956 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4957 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004958 if (
4959 vdu_count_index is not None
4960 and vdu_count_index != vca["vdu_count_index"]
4961 ):
tiernoe876f672020-02-13 14:34:48 +00004962 continue
4963 if kdu_name and kdu_name != vca["kdu_name"]:
4964 continue
tiernoa278b842020-07-08 15:33:55 +00004965 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4966 continue
tiernoe876f672020-02-13 14:34:48 +00004967 break
4968 else:
4969 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004970 raise LcmException(
4971 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4972 " is not deployed".format(
4973 member_vnf_index,
4974 vdu_id,
4975 vdu_count_index,
4976 kdu_name,
4977 ee_descriptor_id,
4978 )
4979 )
tiernoe876f672020-02-13 14:34:48 +00004980 # get ee_id
4981 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004982 vca_type = vca.get(
4983 "type", "lxc_proxy_charm"
4984 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004985 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004986 raise LcmException(
4987 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4988 "execution environment".format(
4989 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4990 )
4991 )
tierno588547c2020-07-01 15:30:20 +00004992 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004993
David Garciac1fe90a2021-03-31 19:12:02 +02004994 async def _ns_execute_primitive(
4995 self,
4996 ee_id,
4997 primitive,
4998 primitive_params,
4999 retries=0,
5000 retries_interval=30,
5001 timeout=None,
5002 vca_type=None,
5003 db_dict=None,
5004 vca_id: str = None,
5005 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005006 try:
tierno98ad6ea2019-05-30 17:16:28 +00005007 if primitive == "config":
5008 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005009
tierno588547c2020-07-01 15:30:20 +00005010 vca_type = vca_type or "lxc_proxy_charm"
5011
quilesj7e13aeb2019-10-08 13:34:55 +02005012 while retries >= 0:
5013 try:
tierno067e04a2020-03-31 12:53:13 +00005014 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005015 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005016 ee_id=ee_id,
5017 primitive_name=primitive,
5018 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005019 progress_timeout=self.timeout.progress_primitive,
5020 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005021 db_dict=db_dict,
5022 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005023 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005024 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005025 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005026 )
quilesj7e13aeb2019-10-08 13:34:55 +02005027 # execution was OK
5028 break
tierno067e04a2020-03-31 12:53:13 +00005029 except asyncio.CancelledError:
5030 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005031 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005032 retries -= 1
5033 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005034 self.logger.debug(
5035 "Error executing action {} on {} -> {}".format(
5036 primitive, ee_id, e
5037 )
5038 )
quilesj7e13aeb2019-10-08 13:34:55 +02005039 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005040 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005041 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005042 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005043 e = N2VCException(
5044 message="Timed out waiting for action to complete"
5045 )
5046 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005047
garciadeblas5697b8b2021-03-24 09:17:02 +01005048 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005049
tierno067e04a2020-03-31 12:53:13 +00005050 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005051 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005052 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005053 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005054
ksaikiranr3fde2c72021-03-15 10:39:06 +05305055 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5056 """
5057 Updating the vca_status with latest juju information in nsrs record
5058 :param: nsr_id: Id of the nsr
5059 :param: nslcmop_id: Id of the nslcmop
5060 :return: None
5061 """
5062
5063 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5064 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005065 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005066 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005067 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5068 cluster_uuid, kdu_instance, cluster_type = (
5069 k8s["k8scluster-uuid"],
5070 k8s["kdu-instance"],
5071 k8s["k8scluster-type"],
5072 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005073 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005074 cluster_uuid=cluster_uuid,
5075 kdu_instance=kdu_instance,
5076 filter={"_id": nsr_id},
5077 vca_id=vca_id,
5078 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005079 )
3697083243632024-06-07 05:44:08 +00005080 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005081 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305082 table, filter = "nsrs", {"_id": nsr_id}
5083 path = "_admin.deployed.VCA.{}.".format(vca_index)
5084 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305085
5086 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5087 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5088
tierno59d22d22018-09-25 18:10:19 +02005089 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005090 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005091 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005092 if not task_is_locked_by_me:
5093 return
5094
tierno59d22d22018-09-25 18:10:19 +02005095 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5096 self.logger.debug(logging_text + "Enter")
5097 # get all needed from database
5098 db_nsr = None
5099 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005100 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005101 db_nslcmop_update = {}
5102 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005103 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005104 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005105 step = ""
tierno59d22d22018-09-25 18:10:19 +02005106 try:
kuused124bfe2019-06-18 12:09:24 +02005107 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005108 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005109 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005110
quilesj4cda56b2019-12-05 10:02:20 +00005111 self._write_ns_status(
5112 nsr_id=nsr_id,
5113 ns_state=None,
5114 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005115 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005116 )
5117
tierno59d22d22018-09-25 18:10:19 +02005118 step = "Getting information from database"
5119 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5120 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005121 if db_nslcmop["operationParams"].get("primitive_params"):
5122 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5123 db_nslcmop["operationParams"]["primitive_params"]
5124 )
tiernoda964822019-01-14 15:53:47 +00005125
tiernoe4f7e6c2018-11-27 14:55:30 +00005126 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005127 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005128 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005129 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005130 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005131 primitive = db_nslcmop["operationParams"]["primitive"]
5132 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005133 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005134 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005135 )
tierno59d22d22018-09-25 18:10:19 +02005136
tierno1b633412019-02-25 16:48:23 +00005137 if vnf_index:
5138 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005139 db_vnfr = self.db.get_one(
5140 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5141 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005142 if db_vnfr.get("kdur"):
5143 kdur_list = []
5144 for kdur in db_vnfr["kdur"]:
5145 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005146 kdur["additionalParams"] = json.loads(
5147 kdur["additionalParams"]
5148 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005149 kdur_list.append(kdur)
5150 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005151 step = "Getting vnfd from database"
5152 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005153
5154 # Sync filesystem before running a primitive
5155 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005156 else:
tierno067e04a2020-03-31 12:53:13 +00005157 step = "Getting nsd from database"
5158 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005159
David Garciac1fe90a2021-03-31 19:12:02 +02005160 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005161 # for backward compatibility
5162 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5163 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5164 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5165 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5166
tiernoda964822019-01-14 15:53:47 +00005167 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005168 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005169 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005170 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005171 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005172 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005173 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005174 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005175 else:
tiernoa278b842020-07-08 15:33:55 +00005176 descriptor_configuration = db_nsd.get("ns-configuration")
5177
garciadeblas5697b8b2021-03-24 09:17:02 +01005178 if descriptor_configuration and descriptor_configuration.get(
5179 "config-primitive"
5180 ):
tiernoa278b842020-07-08 15:33:55 +00005181 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005182 if config_primitive["name"] == primitive:
5183 config_primitive_desc = config_primitive
5184 break
tiernoda964822019-01-14 15:53:47 +00005185
garciadeblas6bed6b32020-07-20 11:05:42 +00005186 if not config_primitive_desc:
5187 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005188 raise LcmException(
5189 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5190 primitive
5191 )
5192 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005193 primitive_name = primitive
5194 ee_descriptor_id = None
5195 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005196 primitive_name = config_primitive_desc.get(
5197 "execution-environment-primitive", primitive
5198 )
5199 ee_descriptor_id = config_primitive_desc.get(
5200 "execution-environment-ref"
5201 )
tierno1b633412019-02-25 16:48:23 +00005202
tierno1b633412019-02-25 16:48:23 +00005203 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005204 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005205 vdur = next(
5206 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5207 )
bravof922c4172020-11-24 21:21:43 -03005208 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005209 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005210 kdur = next(
5211 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5212 )
bravof922c4172020-11-24 21:21:43 -03005213 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005214 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005215 desc_params = parse_yaml_strings(
5216 db_vnfr.get("additionalParamsForVnf")
5217 )
tierno1b633412019-02-25 16:48:23 +00005218 else:
bravof922c4172020-11-24 21:21:43 -03005219 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005220 if kdu_name and get_configuration(db_vnfd, kdu_name):
5221 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005222 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005223 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005224 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005225 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005226 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005227 kdu = find_in_list(
5228 nsr_deployed["K8s"],
5229 lambda kdu: kdu_name == kdu["kdu-name"]
5230 and kdu["member-vnf-index"] == vnf_index,
5231 )
5232 kdu_action = (
5233 True
5234 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005235 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005236 else False
5237 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005238
tiernoda964822019-01-14 15:53:47 +00005239 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005240 if kdu_name and (
5241 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5242 ):
tierno067e04a2020-03-31 12:53:13 +00005243 # TODO Check if we will need something at vnf level
5244 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005245 if (
5246 kdu_name == kdu["kdu-name"]
5247 and kdu["member-vnf-index"] == vnf_index
5248 ):
tierno067e04a2020-03-31 12:53:13 +00005249 break
5250 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005251 raise LcmException(
5252 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5253 )
quilesj7e13aeb2019-10-08 13:34:55 +02005254
tierno067e04a2020-03-31 12:53:13 +00005255 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005256 msg = "unknown k8scluster-type '{}'".format(
5257 kdu.get("k8scluster-type")
5258 )
tierno067e04a2020-03-31 12:53:13 +00005259 raise LcmException(msg)
5260
garciadeblas5697b8b2021-03-24 09:17:02 +01005261 db_dict = {
5262 "collection": "nsrs",
5263 "filter": {"_id": nsr_id},
5264 "path": "_admin.deployed.K8s.{}".format(index),
5265 }
5266 self.logger.debug(
5267 logging_text
5268 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5269 )
tiernoa278b842020-07-08 15:33:55 +00005270 step = "Executing kdu {}".format(primitive_name)
garciadeblas8eb84d52024-07-19 12:08:07 +02005271 if primitive_name == "upgrade" and primitive_params:
5272 if primitive_params.get("kdu_model"):
5273 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005274 else:
5275 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005276 if kdu_model.count("/") < 2: # helm chart is not embedded
5277 parts = kdu_model.split(sep=":")
5278 if len(parts) == 2:
5279 kdu_model = parts[0]
garciadeblas8eb84d52024-07-19 12:08:07 +02005280 if primitive_params.get("kdu_atomic_upgrade"):
5281 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005282 "kdu_atomic_upgrade"
5283 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005284 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005285 else:
5286 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005287 # Type of upgrade: reset, reuse, reset_then_reuse
5288 reset_values = False
5289 reuse_values = False
5290 reset_then_reuse_values = False
5291 # If no option is specified, default behaviour is reuse_values
5292 # Otherwise, options will be parsed and used
5293 if (
garciadeblas8eb84d52024-07-19 12:08:07 +02005294 ("kdu_reset_values" not in primitive_params)
5295 and ("kdu_reuse_values" not in primitive_params)
5296 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasb891d382024-02-08 14:11:51 +01005297 ):
5298 reuse_values = True
5299 else:
garciadeblas8eb84d52024-07-19 12:08:07 +02005300 if primitive_params.get("kdu_reset_values"):
5301 reset_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005302 "kdu_reset_values"
5303 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005304 if primitive_params.get("kdu_reuse_values"):
5305 reuse_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005306 "kdu_reuse_values"
5307 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005308 if primitive_params.get("kdu_reset_then_reuse_values"):
5309 reset_then_reuse_values = primitive_params.get(
garciadeblasb891d382024-02-08 14:11:51 +01005310 "kdu_reset_then_reuse_values"
5311 ).lower() in ("yes", "true", "1")
5312 # Two true options are not possible
5313 if (
5314 sum([reset_values, reuse_values, reset_then_reuse_values])
5315 >= 2
5316 ):
5317 raise LcmException(
5318 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5319 )
garciadeblas8eb84d52024-07-19 12:08:07 +02005320 # kdur and desc_params already set from before
5321 if reset_values:
5322 desc_params = primitive_params
5323 else:
5324 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005325 detailed_status = await asyncio.wait_for(
5326 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5327 cluster_uuid=kdu.get("k8scluster-uuid"),
5328 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005329 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005330 reset_values=reset_values,
5331 reuse_values=reuse_values,
5332 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005333 kdu_model=kdu_model,
5334 params=desc_params,
5335 db_dict=db_dict,
5336 timeout=timeout_ns_action,
5337 ),
5338 timeout=timeout_ns_action + 10,
5339 )
5340 self.logger.debug(
5341 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5342 )
tiernoa278b842020-07-08 15:33:55 +00005343 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005344 detailed_status = await asyncio.wait_for(
5345 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5346 cluster_uuid=kdu.get("k8scluster-uuid"),
5347 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005348 db_dict=db_dict,
5349 ),
5350 timeout=timeout_ns_action,
5351 )
tiernoa278b842020-07-08 15:33:55 +00005352 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005353 detailed_status = await asyncio.wait_for(
5354 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5355 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005356 kdu_instance=kdu.get("kdu-instance"),
5357 vca_id=vca_id,
5358 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005359 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005360 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005361 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005362 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5363 kdu["kdu-name"], nsr_id
5364 )
5365 params = self._map_primitive_params(
5366 config_primitive_desc, primitive_params, desc_params
5367 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005368
5369 detailed_status = await asyncio.wait_for(
5370 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5371 cluster_uuid=kdu.get("k8scluster-uuid"),
5372 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005373 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005374 params=params,
5375 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005376 timeout=timeout_ns_action,
5377 vca_id=vca_id,
5378 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005379 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005380 )
tierno067e04a2020-03-31 12:53:13 +00005381
5382 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005383 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005384 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005385 detailed_status = ""
5386 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005387 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005388 ee_id, vca_type = self._look_for_deployed_vca(
5389 nsr_deployed["VCA"],
5390 member_vnf_index=vnf_index,
5391 vdu_id=vdu_id,
5392 vdu_count_index=vdu_count_index,
5393 ee_descriptor_id=ee_descriptor_id,
5394 )
5395 for vca_index, vca_deployed in enumerate(
5396 db_nsr["_admin"]["deployed"]["VCA"]
5397 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305398 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005399 db_dict = {
5400 "collection": "nsrs",
5401 "filter": {"_id": nsr_id},
5402 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5403 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305404 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005405 (
5406 nslcmop_operation_state,
5407 detailed_status,
5408 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005409 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005410 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005411 primitive_params=self._map_primitive_params(
5412 config_primitive_desc, primitive_params, desc_params
5413 ),
tierno588547c2020-07-01 15:30:20 +00005414 timeout=timeout_ns_action,
5415 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005416 db_dict=db_dict,
5417 vca_id=vca_id,
5418 )
tierno067e04a2020-03-31 12:53:13 +00005419
5420 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005421 error_description_nslcmop = (
5422 detailed_status if nslcmop_operation_state == "FAILED" else ""
5423 )
5424 self.logger.debug(
5425 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005426 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005427 nslcmop_operation_state, detailed_status
5428 )
5429 )
tierno59d22d22018-09-25 18:10:19 +02005430 return # database update is called inside finally
5431
tiernof59ad6c2020-04-08 12:50:52 +00005432 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005433 self.logger.error(logging_text + "Exit Exception {}".format(e))
5434 exc = e
5435 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005436 self.logger.error(
5437 logging_text + "Cancelled Exception while '{}'".format(step)
5438 )
tierno59d22d22018-09-25 18:10:19 +02005439 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005440 except asyncio.TimeoutError:
5441 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5442 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005443 except Exception as e:
5444 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005445 self.logger.critical(
5446 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5447 exc_info=True,
5448 )
tierno59d22d22018-09-25 18:10:19 +02005449 finally:
tierno067e04a2020-03-31 12:53:13 +00005450 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005451 db_nslcmop_update[
5452 "detailed-status"
5453 ] = (
5454 detailed_status
5455 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005456 nslcmop_operation_state = "FAILED"
5457 if db_nsr:
5458 self._write_ns_status(
5459 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005460 ns_state=db_nsr[
5461 "nsState"
5462 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005463 current_operation="IDLE",
5464 current_operation_id=None,
5465 # error_description=error_description_nsr,
5466 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005467 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005468 )
5469
garciadeblas5697b8b2021-03-24 09:17:02 +01005470 self._write_op_status(
5471 op_id=nslcmop_id,
5472 stage="",
5473 error_message=error_description_nslcmop,
5474 operation_state=nslcmop_operation_state,
5475 other_update=db_nslcmop_update,
5476 )
tierno067e04a2020-03-31 12:53:13 +00005477
tierno59d22d22018-09-25 18:10:19 +02005478 if nslcmop_operation_state:
5479 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005480 await self.msg.aiowrite(
5481 "ns",
5482 "actioned",
5483 {
5484 "nsr_id": nsr_id,
5485 "nslcmop_id": nslcmop_id,
5486 "operationState": nslcmop_operation_state,
5487 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005488 )
tierno59d22d22018-09-25 18:10:19 +02005489 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005490 self.logger.error(
5491 logging_text + "kafka_write notification Exception {}".format(e)
5492 )
tierno59d22d22018-09-25 18:10:19 +02005493 self.logger.debug(logging_text + "Exit")
5494 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005495 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005496
elumalaica7ece02022-04-12 12:47:32 +05305497 async def terminate_vdus(
5498 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5499 ):
5500 """This method terminates VDUs
5501
5502 Args:
5503 db_vnfr: VNF instance record
5504 member_vnf_index: VNF index to identify the VDUs to be removed
5505 db_nsr: NS instance record
5506 update_db_nslcmops: Nslcmop update record
5507 """
5508 vca_scaling_info = []
5509 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5510 scaling_info["scaling_direction"] = "IN"
5511 scaling_info["vdu-delete"] = {}
5512 scaling_info["kdu-delete"] = {}
5513 db_vdur = db_vnfr.get("vdur")
5514 vdur_list = copy(db_vdur)
5515 count_index = 0
5516 for index, vdu in enumerate(vdur_list):
5517 vca_scaling_info.append(
5518 {
5519 "osm_vdu_id": vdu["vdu-id-ref"],
5520 "member-vnf-index": member_vnf_index,
5521 "type": "delete",
5522 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005523 }
5524 )
elumalaica7ece02022-04-12 12:47:32 +05305525 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5526 scaling_info["vdu"].append(
5527 {
5528 "name": vdu.get("name") or vdu.get("vdu-name"),
5529 "vdu_id": vdu["vdu-id-ref"],
5530 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005531 }
5532 )
elumalaica7ece02022-04-12 12:47:32 +05305533 for interface in vdu["interfaces"]:
5534 scaling_info["vdu"][index]["interface"].append(
5535 {
5536 "name": interface["name"],
5537 "ip_address": interface["ip-address"],
5538 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005539 }
5540 )
elumalaica7ece02022-04-12 12:47:32 +05305541 self.logger.info("NS update scaling info{}".format(scaling_info))
5542 stage[2] = "Terminating VDUs"
5543 if scaling_info.get("vdu-delete"):
5544 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005545 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305546 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005547 logging_text,
5548 db_nsr,
5549 update_db_nslcmops,
5550 db_vnfr,
5551 scaling_info,
5552 stage,
elumalaica7ece02022-04-12 12:47:32 +05305553 )
5554
preethika.p28b0bf82022-09-23 07:36:28 +00005555 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305556 """This method is to Remove VNF instances from NS.
5557
5558 Args:
5559 nsr_id: NS instance id
5560 nslcmop_id: nslcmop id of update
5561 vnf_instance_id: id of the VNF instance to be removed
5562
5563 Returns:
5564 result: (str, str) COMPLETED/FAILED, details
5565 """
5566 try:
5567 db_nsr_update = {}
5568 logging_text = "Task ns={} update ".format(nsr_id)
5569 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5570 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5571 if check_vnfr_count > 1:
5572 stage = ["", "", ""]
5573 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005574 self.logger.debug(
5575 step + " after having waited for previous tasks to be completed"
5576 )
elumalaica7ece02022-04-12 12:47:32 +05305577 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5578 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5579 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5580 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5581 """ db_vnfr = self.db.get_one(
5582 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5583
5584 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005585 await self.terminate_vdus(
5586 db_vnfr,
5587 member_vnf_index,
5588 db_nsr,
5589 update_db_nslcmops,
5590 stage,
5591 logging_text,
5592 )
elumalaica7ece02022-04-12 12:47:32 +05305593
5594 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5595 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005596 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5597 "constituent-vnfr-ref"
5598 )
elumalaica7ece02022-04-12 12:47:32 +05305599 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5600 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5601 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5602 return "COMPLETED", "Done"
5603 else:
5604 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005605 raise LcmException(
5606 "{} Cannot terminate the last VNF in this NS.".format(
5607 vnf_instance_id
5608 )
5609 )
elumalaica7ece02022-04-12 12:47:32 +05305610 except (LcmException, asyncio.CancelledError):
5611 raise
5612 except Exception as e:
5613 self.logger.debug("Error removing VNF {}".format(e))
5614 return "FAILED", "Error removing VNF {}".format(e)
5615
elumalaib9e357c2022-04-27 09:58:38 +05305616 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005617 self,
5618 nsr_id,
5619 nslcmop_id,
5620 db_vnfd,
5621 db_vnfr,
5622 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305623 ):
5624 """This method updates and redeploys VNF instances
5625
5626 Args:
5627 nsr_id: NS instance id
5628 nslcmop_id: nslcmop id
5629 db_vnfd: VNF descriptor
5630 db_vnfr: VNF instance record
5631 db_nsr: NS instance record
5632
5633 Returns:
5634 result: (str, str) COMPLETED/FAILED, details
5635 """
5636 try:
5637 count_index = 0
5638 stage = ["", "", ""]
5639 logging_text = "Task ns={} update ".format(nsr_id)
5640 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5641 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5642
5643 # Terminate old VNF resources
5644 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005645 await self.terminate_vdus(
5646 db_vnfr,
5647 member_vnf_index,
5648 db_nsr,
5649 update_db_nslcmops,
5650 stage,
5651 logging_text,
5652 )
elumalaib9e357c2022-04-27 09:58:38 +05305653
5654 # old_vnfd_id = db_vnfr["vnfd-id"]
5655 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5656 new_db_vnfd = db_vnfd
5657 # new_vnfd_ref = new_db_vnfd["id"]
5658 # new_vnfd_id = vnfd_id
5659
5660 # Create VDUR
5661 new_vnfr_cp = []
5662 for cp in new_db_vnfd.get("ext-cpd", ()):
5663 vnf_cp = {
5664 "name": cp.get("id"),
5665 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5666 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5667 "id": cp.get("id"),
5668 }
5669 new_vnfr_cp.append(vnf_cp)
5670 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5671 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5672 # 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 +00005673 new_vnfr_update = {
5674 "revision": latest_vnfd_revision,
5675 "connection-point": new_vnfr_cp,
5676 "vdur": new_vdur,
5677 "ip-address": "",
5678 }
elumalaib9e357c2022-04-27 09:58:38 +05305679 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5680 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005681 "vnfrs",
5682 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305683 )
5684
5685 # Instantiate new VNF resources
5686 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5687 vca_scaling_info = []
5688 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5689 scaling_info["scaling_direction"] = "OUT"
5690 scaling_info["vdu-create"] = {}
5691 scaling_info["kdu-create"] = {}
5692 vdud_instantiate_list = db_vnfd["vdu"]
5693 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005694 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305695 if cloud_init_text:
5696 additional_params = (
5697 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5698 or {}
5699 )
5700 cloud_init_list = []
5701 if cloud_init_text:
5702 # TODO Information of its own ip is not available because db_vnfr is not updated.
5703 additional_params["OSM"] = get_osm_params(
5704 updated_db_vnfr, vdud["id"], 1
5705 )
5706 cloud_init_list.append(
5707 self._parse_cloud_init(
5708 cloud_init_text,
5709 additional_params,
5710 db_vnfd["id"],
5711 vdud["id"],
5712 )
5713 )
5714 vca_scaling_info.append(
5715 {
5716 "osm_vdu_id": vdud["id"],
5717 "member-vnf-index": member_vnf_index,
5718 "type": "create",
5719 "vdu_index": count_index,
5720 }
5721 )
5722 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005723 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305724 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005725 "New Resources to be deployed: {}".format(scaling_info)
5726 )
elumalaib9e357c2022-04-27 09:58:38 +05305727 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005728 logging_text,
5729 db_nsr,
5730 update_db_nslcmops,
5731 updated_db_vnfr,
5732 scaling_info,
5733 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305734 )
5735 return "COMPLETED", "Done"
5736 except (LcmException, asyncio.CancelledError):
5737 raise
5738 except Exception as e:
5739 self.logger.debug("Error updating VNF {}".format(e))
5740 return "FAILED", "Error updating VNF {}".format(e)
5741
aticigdffa6212022-04-12 15:27:53 +03005742 async def _ns_charm_upgrade(
5743 self,
5744 ee_id,
5745 charm_id,
5746 charm_type,
5747 path,
5748 timeout: float = None,
5749 ) -> (str, str):
5750 """This method upgrade charms in VNF instances
5751
5752 Args:
5753 ee_id: Execution environment id
5754 path: Local path to the charm
5755 charm_id: charm-id
5756 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5757 timeout: (Float) Timeout for the ns update operation
5758
5759 Returns:
5760 result: (str, str) COMPLETED/FAILED, details
5761 """
5762 try:
5763 charm_type = charm_type or "lxc_proxy_charm"
5764 output = await self.vca_map[charm_type].upgrade_charm(
5765 ee_id=ee_id,
5766 path=path,
5767 charm_id=charm_id,
5768 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005769 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005770 )
5771
5772 if output:
5773 return "COMPLETED", output
5774
5775 except (LcmException, asyncio.CancelledError):
5776 raise
5777
5778 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005779 self.logger.debug("Error upgrading charm {}".format(path))
5780
5781 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5782
5783 async def update(self, nsr_id, nslcmop_id):
5784 """Update NS according to different update types
5785
5786 This method performs upgrade of VNF instances then updates the revision
5787 number in VNF record
5788
5789 Args:
5790 nsr_id: Network service will be updated
5791 nslcmop_id: ns lcm operation id
5792
5793 Returns:
5794 It may raise DbException, LcmException, N2VCException, K8sException
5795
5796 """
5797 # Try to lock HA task here
5798 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5799 if not task_is_locked_by_me:
5800 return
5801
5802 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5803 self.logger.debug(logging_text + "Enter")
5804
5805 # Set the required variables to be filled up later
5806 db_nsr = None
5807 db_nslcmop_update = {}
5808 vnfr_update = {}
5809 nslcmop_operation_state = None
5810 db_nsr_update = {}
5811 error_description_nslcmop = ""
5812 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305813 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005814 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005815 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005816
5817 try:
5818 # wait for any previous tasks in process
5819 step = "Waiting for previous operations to terminate"
5820 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5821 self._write_ns_status(
5822 nsr_id=nsr_id,
5823 ns_state=None,
5824 current_operation="UPDATING",
5825 current_operation_id=nslcmop_id,
5826 )
5827
5828 step = "Getting nslcmop from database"
5829 db_nslcmop = self.db.get_one(
5830 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5831 )
5832 update_type = db_nslcmop["operationParams"]["updateType"]
5833
5834 step = "Getting nsr from database"
5835 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5836 old_operational_status = db_nsr["operational-status"]
5837 db_nsr_update["operational-status"] = "updating"
5838 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5839 nsr_deployed = db_nsr["_admin"].get("deployed")
5840
5841 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005842 # Get the input parameters given through update request
5843 vnf_instance_id = db_nslcmop["operationParams"][
5844 "changeVnfPackageData"
5845 ].get("vnfInstanceId")
5846
5847 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5848 "vnfdId"
5849 )
5850 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5851
5852 step = "Getting vnfr from database"
5853 db_vnfr = self.db.get_one(
5854 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5855 )
5856
5857 step = "Getting vnfds from database"
5858 # Latest VNFD
5859 latest_vnfd = self.db.get_one(
5860 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5861 )
5862 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5863
5864 # Current VNFD
5865 current_vnf_revision = db_vnfr.get("revision", 1)
5866 current_vnfd = self.db.get_one(
5867 "vnfds_revisions",
5868 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5869 fail_on_empty=False,
5870 )
5871 # Charm artifact paths will be filled up later
5872 (
5873 current_charm_artifact_path,
5874 target_charm_artifact_path,
5875 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005876 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005877 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005878
5879 step = "Checking if revision has changed in VNFD"
5880 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305881 change_type = "policy_updated"
5882
aticigdffa6212022-04-12 15:27:53 +03005883 # There is new revision of VNFD, update operation is required
5884 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005885 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005886
5887 step = "Removing the VNFD packages if they exist in the local path"
5888 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5889 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5890
5891 step = "Get the VNFD packages from FSMongo"
5892 self.fs.sync(from_path=latest_vnfd_path)
5893 self.fs.sync(from_path=current_vnfd_path)
5894
5895 step = (
5896 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5897 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005898 current_base_folder = current_vnfd["_admin"]["storage"]
5899 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005900
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005901 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005902 get_iterable(nsr_deployed, "VCA")
5903 ):
5904 vnf_index = db_vnfr.get("member-vnf-index-ref")
5905
5906 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005907 if vca_deployed.get("member-vnf-index") == vnf_index:
5908 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5909 vca_type = vca_deployed.get("type")
5910 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005911
5912 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005913 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005914
5915 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005916 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005917 search_key = "kdu_name"
5918 else:
5919 search_key = "vnfd_id"
5920
5921 entity_id = vca_deployed.get(search_key)
5922
aticigdffa6212022-04-12 15:27:53 +03005923 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005924 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005925 )
5926
5927 if "execution-environment-list" in descriptor_config:
5928 ee_list = descriptor_config.get(
5929 "execution-environment-list", []
5930 )
5931 else:
5932 ee_list = []
5933
5934 # There could be several charm used in the same VNF
5935 for ee_item in ee_list:
5936 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005937 step = "Getting charm name"
5938 charm_name = ee_item["juju"].get("charm")
5939
5940 step = "Setting Charm artifact paths"
5941 current_charm_artifact_path.append(
5942 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005943 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005944 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005945 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005946 current_vnf_revision,
5947 )
5948 )
5949 target_charm_artifact_path.append(
5950 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005951 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005952 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005953 vca_type,
aticigd7083542022-05-30 20:45:55 +03005954 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005955 )
5956 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005957 elif ee_item.get("helm-chart"):
5958 # add chart to list and all parameters
5959 step = "Getting helm chart name"
5960 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00005961 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005962 step = "Setting Helm chart artifact paths"
5963
garciadeblasfb1e25f2022-11-18 14:36:22 +01005964 helm_artifacts.append(
5965 {
5966 "current_artifact_path": get_charm_artifact_path(
5967 current_base_folder,
5968 chart_name,
5969 vca_type,
5970 current_vnf_revision,
5971 ),
5972 "target_artifact_path": get_charm_artifact_path(
5973 latest_base_folder,
5974 chart_name,
5975 vca_type,
5976 latest_vnfd_revision,
5977 ),
5978 "ee_id": ee_id,
5979 "vca_index": vca_index,
5980 "vdu_index": vdu_count_index,
5981 }
5982 )
aticigdffa6212022-04-12 15:27:53 +03005983
5984 charm_artifact_paths = zip(
5985 current_charm_artifact_path, target_charm_artifact_path
5986 )
5987
5988 step = "Checking if software version has changed in VNFD"
5989 if find_software_version(current_vnfd) != find_software_version(
5990 latest_vnfd
5991 ):
aticigdffa6212022-04-12 15:27:53 +03005992 step = "Checking if existing VNF has charm"
5993 for current_charm_path, target_charm_path in list(
5994 charm_artifact_paths
5995 ):
5996 if current_charm_path:
5997 raise LcmException(
5998 "Software version change is not supported as VNF instance {} has charm.".format(
5999 vnf_instance_id
6000 )
6001 )
6002
kayal20010cd8af32024-03-13 10:23:16 +05306003 step = "Checking whether the descriptor has SFC"
6004 if db_nsr.get("nsd", {}).get("vnffgd"):
6005 raise LcmException(
6006 "Ns update is not allowed for NS with SFC"
6007 )
6008
aticigdffa6212022-04-12 15:27:53 +03006009 # There is no change in the charm package, then redeploy the VNF
6010 # based on new descriptor
6011 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306012 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006013 (result, detailed_status) = await self._ns_redeploy_vnf(
6014 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306015 )
6016 if result == "FAILED":
6017 nslcmop_operation_state = result
6018 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306019 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306020 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306021 db_nsr_update["detailed-status"] = detailed_status
6022 scaling_aspect = get_scaling_aspect(latest_vnfd)
6023 scaling_group_desc = db_nsr.get("_admin").get(
6024 "scaling-group", None
6025 )
6026 if scaling_group_desc:
6027 for aspect in scaling_aspect:
6028 scaling_group_id = aspect.get("id")
6029 for scale_index, scaling_group in enumerate(
6030 scaling_group_desc
6031 ):
6032 if scaling_group.get("name") == scaling_group_id:
6033 db_nsr_update[
6034 "_admin.scaling-group.{}.nb-scale-op".format(
6035 scale_index
6036 )
6037 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306038 self.logger.debug(
6039 logging_text
6040 + " step {} Done with result {} {}".format(
6041 step, nslcmop_operation_state, detailed_status
6042 )
6043 )
aticigdffa6212022-04-12 15:27:53 +03006044
6045 else:
6046 step = "Checking if any charm package has changed or not"
6047 for current_charm_path, target_charm_path in list(
6048 charm_artifact_paths
6049 ):
6050 if (
6051 current_charm_path
6052 and target_charm_path
6053 and self.check_charm_hash_changed(
6054 current_charm_path, target_charm_path
6055 )
6056 ):
aticigdffa6212022-04-12 15:27:53 +03006057 step = "Checking whether VNF uses juju bundle"
6058 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006059 raise LcmException(
6060 "Charm upgrade is not supported for the instance which"
6061 " uses juju-bundle: {}".format(
6062 check_juju_bundle_existence(current_vnfd)
6063 )
6064 )
6065
6066 step = "Upgrading Charm"
6067 (
6068 result,
6069 detailed_status,
6070 ) = await self._ns_charm_upgrade(
6071 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006072 charm_id=vca_id,
6073 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006074 path=self.fs.path + target_charm_path,
6075 timeout=timeout_seconds,
6076 )
6077
6078 if result == "FAILED":
6079 nslcmop_operation_state = result
6080 error_description_nslcmop = detailed_status
6081
6082 db_nslcmop_update["detailed-status"] = detailed_status
6083 self.logger.debug(
6084 logging_text
6085 + " step {} Done with result {} {}".format(
6086 step, nslcmop_operation_state, detailed_status
6087 )
6088 )
6089
6090 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306091 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6092 result = "COMPLETED"
6093 detailed_status = "Done"
6094 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006095
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006096 # helm base EE
6097 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006098 if not (
6099 item["current_artifact_path"]
6100 and item["target_artifact_path"]
6101 and self.check_charm_hash_changed(
6102 item["current_artifact_path"],
6103 item["target_artifact_path"],
6104 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006105 ):
6106 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006107 db_update_entry = "_admin.deployed.VCA.{}.".format(
6108 item["vca_index"]
6109 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006110 vnfr_id = db_vnfr["_id"]
6111 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6112 db_dict = {
6113 "collection": "nsrs",
6114 "filter": {"_id": nsr_id},
6115 "path": db_update_entry,
6116 }
6117 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006118 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006119 namespace=namespace,
6120 helm_id=helm_id,
6121 db_dict=db_dict,
6122 config=osm_config,
6123 artifact_path=item["target_artifact_path"],
6124 vca_type=vca_type,
6125 )
6126 vnf_id = db_vnfr.get("vnfd-ref")
6127 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6128 self.logger.debug("get ssh key block")
6129 rw_mgmt_ip = None
6130 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006131 config_descriptor,
6132 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006133 ):
6134 # Needed to inject a ssh key
6135 user = deep_get(
6136 config_descriptor,
6137 ("config-access", "ssh-access", "default-user"),
6138 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006139 step = (
6140 "Install configuration Software, getting public ssh key"
6141 )
6142 pub_key = await self.vca_map[
6143 vca_type
6144 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006145 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6146 )
6147
garciadeblasfb1e25f2022-11-18 14:36:22 +01006148 step = (
6149 "Insert public key into VM user={} ssh_key={}".format(
6150 user, pub_key
6151 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006152 )
6153 self.logger.debug(logging_text + step)
6154
6155 # wait for RO (ip-address) Insert pub_key into VM
6156 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6157 logging_text,
6158 nsr_id,
6159 vnfr_id,
6160 None,
6161 item["vdu_index"],
6162 user=user,
6163 pub_key=pub_key,
6164 )
6165
6166 initial_config_primitive_list = config_descriptor.get(
6167 "initial-config-primitive"
6168 )
6169 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006170 (
6171 p
6172 for p in initial_config_primitive_list
6173 if p["name"] == "config"
6174 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006175 None,
6176 )
6177 if not config_primitive:
6178 continue
6179
6180 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6181 if rw_mgmt_ip:
6182 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6183 if db_vnfr.get("additionalParamsForVnf"):
6184 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006185 parse_yaml_strings(
6186 db_vnfr["additionalParamsForVnf"].copy()
6187 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006188 )
6189 primitive_params_ = self._map_primitive_params(
6190 config_primitive, {}, deploy_params
6191 )
6192
6193 step = "execute primitive '{}' params '{}'".format(
6194 config_primitive["name"], primitive_params_
6195 )
6196 self.logger.debug(logging_text + step)
6197 await self.vca_map[vca_type].exec_primitive(
6198 ee_id=ee_id,
6199 primitive_name=config_primitive["name"],
6200 params_dict=primitive_params_,
6201 db_dict=db_dict,
6202 vca_id=vca_id,
6203 vca_type=vca_type,
6204 )
6205
6206 step = "Updating policies"
6207 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6208 detailed_status = "Done"
6209 db_nslcmop_update["detailed-status"] = "Done"
6210
aticigdffa6212022-04-12 15:27:53 +03006211 # If nslcmop_operation_state is None, so any operation is not failed.
6212 if not nslcmop_operation_state:
6213 nslcmop_operation_state = "COMPLETED"
6214
6215 # If update CHANGE_VNFPKG nslcmop_operation is successful
6216 # vnf revision need to be updated
6217 vnfr_update["revision"] = latest_vnfd_revision
6218 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6219
6220 self.logger.debug(
6221 logging_text
6222 + " task Done with result {} {}".format(
6223 nslcmop_operation_state, detailed_status
6224 )
6225 )
6226 elif update_type == "REMOVE_VNF":
6227 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306228 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6229 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6230 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6231 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006232 (result, detailed_status) = await self.remove_vnf(
6233 nsr_id, nslcmop_id, vnf_instance_id
6234 )
elumalaica7ece02022-04-12 12:47:32 +05306235 if result == "FAILED":
6236 nslcmop_operation_state = result
6237 error_description_nslcmop = detailed_status
6238 db_nslcmop_update["detailed-status"] = detailed_status
6239 change_type = "vnf_terminated"
6240 if not nslcmop_operation_state:
6241 nslcmop_operation_state = "COMPLETED"
6242 self.logger.debug(
6243 logging_text
6244 + " task Done with result {} {}".format(
6245 nslcmop_operation_state, detailed_status
6246 )
6247 )
aticigdffa6212022-04-12 15:27:53 +03006248
k4.rahulb827de92022-05-02 16:35:02 +00006249 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006250 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6251 "vnfInstanceId"
6252 ]
6253 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6254 "changeStateTo"
6255 ]
6256 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6257 "additionalParam"
6258 ]
k4.rahulb827de92022-05-02 16:35:02 +00006259 (result, detailed_status) = await self.rebuild_start_stop(
6260 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006261 )
k4.rahulb827de92022-05-02 16:35:02 +00006262 if result == "FAILED":
6263 nslcmop_operation_state = result
6264 error_description_nslcmop = detailed_status
6265 db_nslcmop_update["detailed-status"] = detailed_status
6266 if not nslcmop_operation_state:
6267 nslcmop_operation_state = "COMPLETED"
6268 self.logger.debug(
6269 logging_text
6270 + " task Done with result {} {}".format(
6271 nslcmop_operation_state, detailed_status
6272 )
6273 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306274 elif update_type == "VERTICAL_SCALE":
6275 self.logger.debug(
6276 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6277 )
6278 # Get the input parameters given through update request
6279 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6280 "vnfInstanceId"
6281 )
6282
6283 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6284 "vnfdId"
6285 )
6286 step = "Getting vnfr from database"
6287 db_vnfr = self.db.get_one(
6288 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6289 )
6290 self.logger.debug(step)
6291 step = "Getting vnfds from database"
6292 self.logger.debug("Start" + step)
6293 # Latest VNFD
6294 latest_vnfd = self.db.get_one(
6295 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6296 )
6297 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6298 # Current VNFD
6299 current_vnf_revision = db_vnfr.get("revision", 1)
6300 current_vnfd = self.db.get_one(
6301 "vnfds_revisions",
6302 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6303 fail_on_empty=False,
6304 )
6305 self.logger.debug("End" + step)
6306 # verify flavor changes
6307 step = "Checking for flavor change"
6308 if find_software_version(current_vnfd) != find_software_version(
6309 latest_vnfd
6310 ):
6311 self.logger.debug("Start" + step)
6312 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6313 "virtual-compute-desc"
6314 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6315 "virtual-storage-desc"
6316 ):
6317 raise LcmException(
6318 "No change in flavor check vnfd {}".format(vnfd_id)
6319 )
6320 else:
6321 raise LcmException(
6322 "No change in software_version of vnfd {}".format(vnfd_id)
6323 )
6324
6325 self.logger.debug("End" + step)
6326
6327 (result, detailed_status) = await self.vertical_scale(
6328 nsr_id, nslcmop_id
6329 )
6330 self.logger.debug(
6331 "vertical_scale result: {} detailed_status :{}".format(
6332 result, detailed_status
6333 )
6334 )
6335 if result == "FAILED":
6336 nslcmop_operation_state = result
6337 error_description_nslcmop = detailed_status
6338 db_nslcmop_update["detailed-status"] = detailed_status
6339 if not nslcmop_operation_state:
6340 nslcmop_operation_state = "COMPLETED"
6341 self.logger.debug(
6342 logging_text
6343 + " task Done with result {} {}".format(
6344 nslcmop_operation_state, detailed_status
6345 )
6346 )
k4.rahulb827de92022-05-02 16:35:02 +00006347
aticigdffa6212022-04-12 15:27:53 +03006348 # If nslcmop_operation_state is None, so any operation is not failed.
6349 # All operations are executed in overall.
6350 if not nslcmop_operation_state:
6351 nslcmop_operation_state = "COMPLETED"
6352 db_nsr_update["operational-status"] = old_operational_status
6353
6354 except (DbException, LcmException, N2VCException, K8sException) as e:
6355 self.logger.error(logging_text + "Exit Exception {}".format(e))
6356 exc = e
6357 except asyncio.CancelledError:
6358 self.logger.error(
6359 logging_text + "Cancelled Exception while '{}'".format(step)
6360 )
6361 exc = "Operation was cancelled"
6362 except asyncio.TimeoutError:
6363 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6364 exc = "Timeout"
6365 except Exception as e:
6366 exc = traceback.format_exc()
6367 self.logger.critical(
6368 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6369 exc_info=True,
6370 )
6371 finally:
6372 if exc:
6373 db_nslcmop_update[
6374 "detailed-status"
6375 ] = (
6376 detailed_status
6377 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6378 nslcmop_operation_state = "FAILED"
6379 db_nsr_update["operational-status"] = old_operational_status
6380 if db_nsr:
6381 self._write_ns_status(
6382 nsr_id=nsr_id,
6383 ns_state=db_nsr["nsState"],
6384 current_operation="IDLE",
6385 current_operation_id=None,
6386 other_update=db_nsr_update,
6387 )
6388
6389 self._write_op_status(
6390 op_id=nslcmop_id,
6391 stage="",
6392 error_message=error_description_nslcmop,
6393 operation_state=nslcmop_operation_state,
6394 other_update=db_nslcmop_update,
6395 )
6396
6397 if nslcmop_operation_state:
6398 try:
elumalaica7ece02022-04-12 12:47:32 +05306399 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306400 "nsr_id": nsr_id,
6401 "nslcmop_id": nslcmop_id,
6402 "operationState": nslcmop_operation_state,
6403 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006404 if (
6405 change_type in ("vnf_terminated", "policy_updated")
6406 and member_vnf_index
6407 ):
elumalaica7ece02022-04-12 12:47:32 +05306408 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006409 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006410 except Exception as e:
6411 self.logger.error(
6412 logging_text + "kafka_write notification Exception {}".format(e)
6413 )
6414 self.logger.debug(logging_text + "Exit")
6415 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6416 return nslcmop_operation_state, detailed_status
6417
tierno59d22d22018-09-25 18:10:19 +02006418 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006419 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006420 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006421 if not task_is_locked_by_me:
6422 return
6423
tierno59d22d22018-09-25 18:10:19 +02006424 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006425 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006426 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006427 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006428 self.logger.debug(logging_text + "Enter")
6429 # get all needed from database
6430 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006431 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006432 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006433 exc = None
tierno9ab95942018-10-10 16:44:22 +02006434 # in case of error, indicates what part of scale was failed to put nsr at error status
6435 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006436 old_operational_status = ""
6437 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006438 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006439 prom_job_name = ""
tierno59d22d22018-09-25 18:10:19 +02006440 try:
kuused124bfe2019-06-18 12:09:24 +02006441 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006442 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006443 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6444 self._write_ns_status(
6445 nsr_id=nsr_id,
6446 ns_state=None,
6447 current_operation="SCALING",
6448 current_operation_id=nslcmop_id,
6449 )
quilesj4cda56b2019-12-05 10:02:20 +00006450
ikalyvas02d9e7b2019-05-27 18:16:01 +03006451 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006452 self.logger.debug(
6453 step + " after having waited for previous tasks to be completed"
6454 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006455 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006456
ikalyvas02d9e7b2019-05-27 18:16:01 +03006457 step = "Getting nsr from database"
6458 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006459 old_operational_status = db_nsr["operational-status"]
6460 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006461
kayal20010cd8af32024-03-13 10:23:16 +05306462 step = "Checking whether the descriptor has SFC"
6463 if db_nsr.get("nsd", {}).get("vnffgd"):
6464 raise LcmException("Scaling is not allowed for NS with SFC")
6465
tierno59d22d22018-09-25 18:10:19 +02006466 step = "Parsing scaling parameters"
6467 db_nsr_update["operational-status"] = "scaling"
6468 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006469 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006470
garciadeblas5697b8b2021-03-24 09:17:02 +01006471 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6472 "scaleByStepData"
6473 ]["member-vnf-index"]
6474 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6475 "scaleByStepData"
6476 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006477 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006478 # for backward compatibility
6479 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6480 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6481 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6482 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6483
tierno59d22d22018-09-25 18:10:19 +02006484 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006485 db_vnfr = self.db.get_one(
6486 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6487 )
bravof922c4172020-11-24 21:21:43 -03006488
David Garciac1fe90a2021-03-31 19:12:02 +02006489 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6490
tierno59d22d22018-09-25 18:10:19 +02006491 step = "Getting vnfd from database"
6492 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006493
aktas13251562021-02-12 22:19:10 +03006494 base_folder = db_vnfd["_admin"]["storage"]
6495
tierno59d22d22018-09-25 18:10:19 +02006496 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006497 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006498 get_scaling_aspect(db_vnfd),
6499 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006500 )
6501 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006502 raise LcmException(
6503 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6504 "at vnfd:scaling-group-descriptor".format(scaling_group)
6505 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006506
tierno15b1cf12019-08-29 13:21:40 +00006507 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006508 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006509 nb_scale_op = 0
6510 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006511 self.update_db_2(
6512 "nsrs",
6513 nsr_id,
6514 {
6515 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006516 {
6517 "name": scaling_group,
6518 "vnf_index": vnf_index,
6519 "nb-scale-op": 0,
6520 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006521 ]
6522 },
6523 )
tierno59d22d22018-09-25 18:10:19 +02006524 admin_scale_index = 0
6525 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006526 for admin_scale_index, admin_scale_info in enumerate(
6527 db_nsr["_admin"]["scaling-group"]
6528 ):
36970ef037852024-04-01 15:41:31 +00006529 if (
6530 admin_scale_info["name"] == scaling_group
6531 and admin_scale_info["vnf_index"] == vnf_index
6532 ):
tierno59d22d22018-09-25 18:10:19 +02006533 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6534 break
tierno9ab95942018-10-10 16:44:22 +02006535 else: # not found, set index one plus last element and add new entry with the name
6536 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006537 db_nsr_update[
6538 "_admin.scaling-group.{}.name".format(admin_scale_index)
6539 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006540 db_nsr_update[
6541 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6542 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006543
6544 vca_scaling_info = []
6545 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006546 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006547 if "aspect-delta-details" not in scaling_descriptor:
6548 raise LcmException(
6549 "Aspect delta details not fount in scaling descriptor {}".format(
6550 scaling_descriptor["name"]
6551 )
6552 )
tierno59d22d22018-09-25 18:10:19 +02006553 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006554 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006555
aktas5f75f102021-03-15 11:26:10 +03006556 scaling_info["scaling_direction"] = "OUT"
6557 scaling_info["vdu-create"] = {}
6558 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006559 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006560 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006561 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006562 # vdu_index also provides the number of instance of the targeted vdu
6563 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006564 if vdu_index <= len(db_vnfr["vdur"]):
6565 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6566 prom_job_name = (
6567 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6568 )
6569 prom_job_name = prom_job_name.replace("_", "")
6570 prom_job_name = prom_job_name.replace("-", "")
6571 else:
6572 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006573 cloud_init_text = self._get_vdu_cloud_init_content(
6574 vdud, db_vnfd
6575 )
tierno72ef84f2020-10-06 08:22:07 +00006576 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006577 additional_params = (
6578 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6579 or {}
6580 )
bravof832f8992020-12-07 12:57:31 -03006581 cloud_init_list = []
6582
6583 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6584 max_instance_count = 10
6585 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006586 max_instance_count = vdu_profile.get(
6587 "max-number-of-instances", 10
6588 )
6589
6590 default_instance_num = get_number_of_instances(
6591 db_vnfd, vdud["id"]
6592 )
aktas5f75f102021-03-15 11:26:10 +03006593 instances_number = vdu_delta.get("number-of-instances", 1)
6594 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006595
aktas5f75f102021-03-15 11:26:10 +03006596 new_instance_count = nb_scale_op + default_instance_num
6597 # Control if new count is over max and vdu count is less than max.
6598 # Then assign new instance count
6599 if new_instance_count > max_instance_count > vdu_count:
6600 instances_number = new_instance_count - max_instance_count
6601 else:
6602 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006603
aktas5f75f102021-03-15 11:26:10 +03006604 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006605 raise LcmException(
6606 "reached the limit of {} (max-instance-count) "
6607 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006608 "scaling-group-descriptor '{}'".format(
6609 nb_scale_op, scaling_group
6610 )
bravof922c4172020-11-24 21:21:43 -03006611 )
bravof832f8992020-12-07 12:57:31 -03006612 for x in range(vdu_delta.get("number-of-instances", 1)):
6613 if cloud_init_text:
6614 # TODO Information of its own ip is not available because db_vnfr is not updated.
6615 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006616 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006617 )
bravof832f8992020-12-07 12:57:31 -03006618 cloud_init_list.append(
6619 self._parse_cloud_init(
6620 cloud_init_text,
6621 additional_params,
6622 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006623 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006624 )
6625 )
aktas5f75f102021-03-15 11:26:10 +03006626 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006627 {
6628 "osm_vdu_id": vdu_delta["id"],
6629 "member-vnf-index": vnf_index,
6630 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006631 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006632 }
6633 )
aktas5f75f102021-03-15 11:26:10 +03006634 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6635 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006636 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006637 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006638 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006639
6640 # Might have different kdus in the same delta
6641 # Should have list for each kdu
6642 if not scaling_info["kdu-create"].get(kdu_name, None):
6643 scaling_info["kdu-create"][kdu_name] = []
6644
6645 kdur = get_kdur(db_vnfr, kdu_name)
6646 if kdur.get("helm-chart"):
6647 k8s_cluster_type = "helm-chart-v3"
6648 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006649 elif kdur.get("juju-bundle"):
6650 k8s_cluster_type = "juju-bundle"
6651 else:
6652 raise LcmException(
6653 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6654 "juju-bundle. Maybe an old NBI version is running".format(
6655 db_vnfr["member-vnf-index-ref"], kdu_name
6656 )
6657 )
6658
6659 max_instance_count = 10
6660 if kdu_profile and "max-number-of-instances" in kdu_profile:
6661 max_instance_count = kdu_profile.get(
6662 "max-number-of-instances", 10
6663 )
6664
6665 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6666 deployed_kdu, _ = get_deployed_kdu(
6667 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006668 )
aktas5f75f102021-03-15 11:26:10 +03006669 if deployed_kdu is None:
6670 raise LcmException(
6671 "KDU '{}' for vnf '{}' not deployed".format(
6672 kdu_name, vnf_index
6673 )
6674 )
6675 kdu_instance = deployed_kdu.get("kdu-instance")
6676 instance_num = await self.k8scluster_map[
6677 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006678 ].get_scale_count(
6679 resource_name,
6680 kdu_instance,
6681 vca_id=vca_id,
6682 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6683 kdu_model=deployed_kdu.get("kdu-model"),
6684 )
aktas5f75f102021-03-15 11:26:10 +03006685 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006686 "number-of-instances", 1
6687 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006688
aktas5f75f102021-03-15 11:26:10 +03006689 # Control if new count is over max and instance_num is less than max.
6690 # Then assign max instance number to kdu replica count
6691 if kdu_replica_count > max_instance_count > instance_num:
6692 kdu_replica_count = max_instance_count
6693 if kdu_replica_count > max_instance_count:
6694 raise LcmException(
6695 "reached the limit of {} (max-instance-count) "
6696 "scaling-out operations for the "
6697 "scaling-group-descriptor '{}'".format(
6698 instance_num, scaling_group
6699 )
6700 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006701
aktas5f75f102021-03-15 11:26:10 +03006702 for x in range(kdu_delta.get("number-of-instances", 1)):
6703 vca_scaling_info.append(
6704 {
6705 "osm_kdu_id": kdu_name,
6706 "member-vnf-index": vnf_index,
6707 "type": "create",
6708 "kdu_index": instance_num + x - 1,
6709 }
6710 )
6711 scaling_info["kdu-create"][kdu_name].append(
6712 {
6713 "member-vnf-index": vnf_index,
6714 "type": "create",
6715 "k8s-cluster-type": k8s_cluster_type,
6716 "resource-name": resource_name,
6717 "scale": kdu_replica_count,
6718 }
6719 )
6720 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006721 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006722
6723 scaling_info["scaling_direction"] = "IN"
6724 scaling_info["vdu-delete"] = {}
6725 scaling_info["kdu-delete"] = {}
6726
bravof832f8992020-12-07 12:57:31 -03006727 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006728 for vdu_delta in delta.get("vdu-delta", {}):
6729 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006730 min_instance_count = 0
6731 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6732 if vdu_profile and "min-number-of-instances" in vdu_profile:
6733 min_instance_count = vdu_profile["min-number-of-instances"]
6734
garciadeblas5697b8b2021-03-24 09:17:02 +01006735 default_instance_num = get_number_of_instances(
6736 db_vnfd, vdu_delta["id"]
6737 )
aktas5f75f102021-03-15 11:26:10 +03006738 instance_num = vdu_delta.get("number-of-instances", 1)
6739 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006740
aktas5f75f102021-03-15 11:26:10 +03006741 new_instance_count = nb_scale_op + default_instance_num
6742
6743 if new_instance_count < min_instance_count < vdu_count:
6744 instances_number = min_instance_count - new_instance_count
6745 else:
6746 instances_number = instance_num
6747
6748 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006749 raise LcmException(
6750 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006751 "scaling-group-descriptor '{}'".format(
6752 nb_scale_op, scaling_group
6753 )
bravof832f8992020-12-07 12:57:31 -03006754 )
aktas13251562021-02-12 22:19:10 +03006755 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006756 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006757 {
6758 "osm_vdu_id": vdu_delta["id"],
6759 "member-vnf-index": vnf_index,
6760 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006761 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006762 }
6763 )
aktas5f75f102021-03-15 11:26:10 +03006764 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6765 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006766 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006767 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006768 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006769
6770 if not scaling_info["kdu-delete"].get(kdu_name, None):
6771 scaling_info["kdu-delete"][kdu_name] = []
6772
6773 kdur = get_kdur(db_vnfr, kdu_name)
6774 if kdur.get("helm-chart"):
6775 k8s_cluster_type = "helm-chart-v3"
6776 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006777 elif kdur.get("juju-bundle"):
6778 k8s_cluster_type = "juju-bundle"
6779 else:
6780 raise LcmException(
6781 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6782 "juju-bundle. Maybe an old NBI version is running".format(
6783 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6784 )
6785 )
6786
6787 min_instance_count = 0
6788 if kdu_profile and "min-number-of-instances" in kdu_profile:
6789 min_instance_count = kdu_profile["min-number-of-instances"]
6790
6791 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6792 deployed_kdu, _ = get_deployed_kdu(
6793 nsr_deployed, kdu_name, vnf_index
6794 )
6795 if deployed_kdu is None:
6796 raise LcmException(
6797 "KDU '{}' for vnf '{}' not deployed".format(
6798 kdu_name, vnf_index
6799 )
6800 )
6801 kdu_instance = deployed_kdu.get("kdu-instance")
6802 instance_num = await self.k8scluster_map[
6803 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006804 ].get_scale_count(
6805 resource_name,
6806 kdu_instance,
6807 vca_id=vca_id,
6808 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6809 kdu_model=deployed_kdu.get("kdu-model"),
6810 )
aktas5f75f102021-03-15 11:26:10 +03006811 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006812 "number-of-instances", 1
6813 )
tierno59d22d22018-09-25 18:10:19 +02006814
aktas5f75f102021-03-15 11:26:10 +03006815 if kdu_replica_count < min_instance_count < instance_num:
6816 kdu_replica_count = min_instance_count
6817 if kdu_replica_count < min_instance_count:
6818 raise LcmException(
6819 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6820 "scaling-group-descriptor '{}'".format(
6821 instance_num, scaling_group
6822 )
6823 )
6824
6825 for x in range(kdu_delta.get("number-of-instances", 1)):
6826 vca_scaling_info.append(
6827 {
6828 "osm_kdu_id": kdu_name,
6829 "member-vnf-index": vnf_index,
6830 "type": "delete",
6831 "kdu_index": instance_num - x - 1,
6832 }
6833 )
6834 scaling_info["kdu-delete"][kdu_name].append(
6835 {
6836 "member-vnf-index": vnf_index,
6837 "type": "delete",
6838 "k8s-cluster-type": k8s_cluster_type,
6839 "resource-name": resource_name,
6840 "scale": kdu_replica_count,
6841 }
6842 )
6843
tierno59d22d22018-09-25 18:10:19 +02006844 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006845 vdu_delete = copy(scaling_info.get("vdu-delete"))
6846 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006847 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006848 if vdu_delete.get(vdur["vdu-id-ref"]):
6849 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006850 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006851 {
6852 "name": vdur.get("name") or vdur.get("vdu-name"),
6853 "vdu_id": vdur["vdu-id-ref"],
6854 "interface": [],
6855 }
6856 )
tierno59d22d22018-09-25 18:10:19 +02006857 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006858 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006859 {
6860 "name": interface["name"],
6861 "ip_address": interface["ip-address"],
6862 "mac_address": interface.get("mac-address"),
6863 }
6864 )
tierno2357f4e2020-10-19 16:38:59 +00006865 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006866
kuuseac3a8882019-10-03 10:48:06 +02006867 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006868 step = "Executing pre-scale vnf-config-primitive"
6869 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006870 for scaling_config_action in scaling_descriptor[
6871 "scaling-config-action"
6872 ]:
6873 if (
6874 scaling_config_action.get("trigger") == "pre-scale-in"
6875 and scaling_type == "SCALE_IN"
6876 ) or (
6877 scaling_config_action.get("trigger") == "pre-scale-out"
6878 and scaling_type == "SCALE_OUT"
6879 ):
6880 vnf_config_primitive = scaling_config_action[
6881 "vnf-config-primitive-name-ref"
6882 ]
6883 step = db_nslcmop_update[
6884 "detailed-status"
6885 ] = "executing pre-scale scaling-config-action '{}'".format(
6886 vnf_config_primitive
6887 )
tiernoda964822019-01-14 15:53:47 +00006888
tierno59d22d22018-09-25 18:10:19 +02006889 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006890 for config_primitive in (
6891 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6892 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006893 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006894 break
6895 else:
6896 raise LcmException(
6897 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006898 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006899 "primitive".format(scaling_group, vnf_config_primitive)
6900 )
tiernoda964822019-01-14 15:53:47 +00006901
aktas5f75f102021-03-15 11:26:10 +03006902 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006903 if db_vnfr.get("additionalParamsForVnf"):
6904 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006905
tierno9ab95942018-10-10 16:44:22 +02006906 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006907 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006908 primitive_params = self._map_primitive_params(
6909 config_primitive, {}, vnfr_params
6910 )
kuuseac3a8882019-10-03 10:48:06 +02006911
tierno7c4e24c2020-05-13 08:41:35 +00006912 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006913 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006914 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006915 vnf_index,
6916 vnf_config_primitive,
6917 primitive_params,
6918 "PRE-SCALE",
6919 )
tierno7c4e24c2020-05-13 08:41:35 +00006920 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006921 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006922 result = "COMPLETED"
6923 result_detail = "Done"
6924 self.logger.debug(
6925 logging_text
6926 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6927 vnf_config_primitive, result, result_detail
6928 )
6929 )
kuuseac3a8882019-10-03 10:48:06 +02006930 else:
tierno7c4e24c2020-05-13 08:41:35 +00006931 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006932 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006933 op_index = (
6934 len(db_nslcmop.get("_admin", {}).get("operations"))
6935 - 1
6936 )
6937 self.logger.debug(
6938 logging_text
6939 + "vnf_config_primitive={} New sub-operation".format(
6940 vnf_config_primitive
6941 )
6942 )
kuuseac3a8882019-10-03 10:48:06 +02006943 else:
tierno7c4e24c2020-05-13 08:41:35 +00006944 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006945 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6946 op_index
6947 ]
6948 vnf_index = op.get("member_vnf_index")
6949 vnf_config_primitive = op.get("primitive")
6950 primitive_params = op.get("primitive_params")
6951 self.logger.debug(
6952 logging_text
6953 + "vnf_config_primitive={} Sub-operation retry".format(
6954 vnf_config_primitive
6955 )
6956 )
tierno588547c2020-07-01 15:30:20 +00006957 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006958 ee_descriptor_id = config_primitive.get(
6959 "execution-environment-ref"
6960 )
6961 primitive_name = config_primitive.get(
6962 "execution-environment-primitive", vnf_config_primitive
6963 )
6964 ee_id, vca_type = self._look_for_deployed_vca(
6965 nsr_deployed["VCA"],
6966 member_vnf_index=vnf_index,
6967 vdu_id=None,
6968 vdu_count_index=None,
6969 ee_descriptor_id=ee_descriptor_id,
6970 )
kuuseac3a8882019-10-03 10:48:06 +02006971 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006972 ee_id,
6973 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006974 primitive_params,
6975 vca_type=vca_type,
6976 vca_id=vca_id,
6977 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006978 self.logger.debug(
6979 logging_text
6980 + "vnf_config_primitive={} Done with result {} {}".format(
6981 vnf_config_primitive, result, result_detail
6982 )
6983 )
kuuseac3a8882019-10-03 10:48:06 +02006984 # Update operationState = COMPLETED | FAILED
6985 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006986 db_nslcmop, op_index, result, result_detail
6987 )
kuuseac3a8882019-10-03 10:48:06 +02006988
tierno59d22d22018-09-25 18:10:19 +02006989 if result == "FAILED":
6990 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006991 db_nsr_update["config-status"] = old_config_status
6992 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006993 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006994
garciadeblas5697b8b2021-03-24 09:17:02 +01006995 db_nsr_update[
6996 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6997 ] = nb_scale_op
6998 db_nsr_update[
6999 "_admin.scaling-group.{}.time".format(admin_scale_index)
7000 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00007001
aktas13251562021-02-12 22:19:10 +03007002 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007003 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007004 step = db_nslcmop_update[
7005 "detailed-status"
7006 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007007 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007008 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007009 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007010 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007011 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007012 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007013 )
aktas5f75f102021-03-15 11:26:10 +03007014 if vca_info.get("osm_vdu_id"):
7015 vdu_id = vca_info["osm_vdu_id"]
7016 vdu_index = int(vca_info["vdu_index"])
7017 stage[
7018 1
7019 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7020 member_vnf_index, vdu_id, vdu_index
7021 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007022 stage[2] = step = "Scaling in VCA"
7023 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007024 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7025 config_update = db_nsr["configurationStatus"]
7026 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007027 if (
7028 (vca or vca.get("ee_id"))
7029 and vca["member-vnf-index"] == member_vnf_index
7030 and vca["vdu_count_index"] == vdu_index
7031 ):
aktas13251562021-02-12 22:19:10 +03007032 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007033 config_descriptor = get_configuration(
7034 db_vnfd, vca.get("vdu_id")
7035 )
aktas13251562021-02-12 22:19:10 +03007036 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007037 config_descriptor = get_configuration(
7038 db_vnfd, vca.get("kdu_name")
7039 )
aktas13251562021-02-12 22:19:10 +03007040 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007041 config_descriptor = get_configuration(
7042 db_vnfd, db_vnfd["id"]
7043 )
7044 operation_params = (
7045 db_nslcmop.get("operationParams") or {}
7046 )
7047 exec_terminate_primitives = not operation_params.get(
7048 "skip_terminate_primitives"
7049 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007050 task = asyncio.ensure_future(
7051 asyncio.wait_for(
7052 self.destroy_N2VC(
7053 logging_text,
7054 db_nslcmop,
7055 vca,
7056 config_descriptor,
7057 vca_index,
7058 destroy_ee=True,
7059 exec_primitives=exec_terminate_primitives,
7060 scaling_in=True,
7061 vca_id=vca_id,
7062 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007063 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007064 )
7065 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007066 tasks_dict_info[task] = "Terminating VCA {}".format(
7067 vca.get("ee_id")
7068 )
aktas13251562021-02-12 22:19:10 +03007069 del vca_update[vca_index]
7070 del config_update[vca_index]
7071 # wait for pending tasks of terminate primitives
7072 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007073 self.logger.debug(
7074 logging_text
7075 + "Waiting for tasks {}".format(
7076 list(tasks_dict_info.keys())
7077 )
7078 )
7079 error_list = await self._wait_for_tasks(
7080 logging_text,
7081 tasks_dict_info,
7082 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007083 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007084 ),
7085 stage,
7086 nslcmop_id,
7087 )
aktas13251562021-02-12 22:19:10 +03007088 tasks_dict_info.clear()
7089 if error_list:
7090 raise LcmException("; ".join(error_list))
7091
7092 db_vca_and_config_update = {
7093 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007094 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007095 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007096 self.update_db_2(
7097 "nsrs", db_nsr["_id"], db_vca_and_config_update
7098 )
aktas13251562021-02-12 22:19:10 +03007099 scale_process = None
7100 # SCALE-IN VCA - END
7101
kuuseac3a8882019-10-03 10:48:06 +02007102 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007103 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007104 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007105 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007106 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007107 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007108 )
aktas5f75f102021-03-15 11:26:10 +03007109 scaling_info.pop("vdu-create", None)
7110 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007111
tierno9ab95942018-10-10 16:44:22 +02007112 scale_process = None
aktas13251562021-02-12 22:19:10 +03007113 # SCALE RO - END
7114
aktas5f75f102021-03-15 11:26:10 +03007115 # SCALE KDU - BEGIN
7116 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7117 scale_process = "KDU"
7118 await self._scale_kdu(
7119 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7120 )
7121 scaling_info.pop("kdu-create", None)
7122 scaling_info.pop("kdu-delete", None)
7123
7124 scale_process = None
7125 # SCALE KDU - END
7126
7127 if db_nsr_update:
7128 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7129
aktas13251562021-02-12 22:19:10 +03007130 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007131 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007132 step = db_nslcmop_update[
7133 "detailed-status"
7134 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007135 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007136 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007137 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007138 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007139 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007140 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007141 )
aktas13251562021-02-12 22:19:10 +03007142 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007143 if vca_info.get("osm_vdu_id"):
7144 vdu_index = int(vca_info["vdu_index"])
7145 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7146 if db_vnfr.get("additionalParamsForVnf"):
7147 deploy_params.update(
7148 parse_yaml_strings(
7149 db_vnfr["additionalParamsForVnf"].copy()
7150 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007151 )
aktas5f75f102021-03-15 11:26:10 +03007152 descriptor_config = get_configuration(
7153 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007154 )
aktas5f75f102021-03-15 11:26:10 +03007155 if descriptor_config:
7156 vdu_id = None
7157 vdu_name = None
7158 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007159 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007160 self._deploy_n2vc(
7161 logging_text=logging_text
7162 + "member_vnf_index={} ".format(member_vnf_index),
7163 db_nsr=db_nsr,
7164 db_vnfr=db_vnfr,
7165 nslcmop_id=nslcmop_id,
7166 nsr_id=nsr_id,
7167 nsi_id=nsi_id,
7168 vnfd_id=vnfd_id,
7169 vdu_id=vdu_id,
7170 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007171 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007172 member_vnf_index=member_vnf_index,
7173 vdu_index=vdu_index,
7174 vdu_name=vdu_name,
7175 deploy_params=deploy_params,
7176 descriptor_config=descriptor_config,
7177 base_folder=base_folder,
7178 task_instantiation_info=tasks_dict_info,
7179 stage=stage,
7180 )
7181 vdu_id = vca_info["osm_vdu_id"]
7182 vdur = find_in_list(
7183 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007184 )
aktas5f75f102021-03-15 11:26:10 +03007185 descriptor_config = get_configuration(db_vnfd, vdu_id)
7186 if vdur.get("additionalParams"):
7187 deploy_params_vdu = parse_yaml_strings(
7188 vdur["additionalParams"]
7189 )
7190 else:
7191 deploy_params_vdu = deploy_params
7192 deploy_params_vdu["OSM"] = get_osm_params(
7193 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007194 )
aktas5f75f102021-03-15 11:26:10 +03007195 if descriptor_config:
7196 vdu_name = None
7197 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007198 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007199 stage[
7200 1
7201 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007202 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007203 )
7204 stage[2] = step = "Scaling out VCA"
7205 self._write_op_status(op_id=nslcmop_id, stage=stage)
7206 self._deploy_n2vc(
7207 logging_text=logging_text
7208 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7209 member_vnf_index, vdu_id, vdu_index
7210 ),
7211 db_nsr=db_nsr,
7212 db_vnfr=db_vnfr,
7213 nslcmop_id=nslcmop_id,
7214 nsr_id=nsr_id,
7215 nsi_id=nsi_id,
7216 vnfd_id=vnfd_id,
7217 vdu_id=vdu_id,
7218 kdu_name=kdu_name,
7219 member_vnf_index=member_vnf_index,
7220 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007221 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007222 vdu_name=vdu_name,
7223 deploy_params=deploy_params_vdu,
7224 descriptor_config=descriptor_config,
7225 base_folder=base_folder,
7226 task_instantiation_info=tasks_dict_info,
7227 stage=stage,
7228 )
aktas13251562021-02-12 22:19:10 +03007229 # SCALE-UP VCA - END
7230 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007231
kuuseac3a8882019-10-03 10:48:06 +02007232 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007233 # execute primitive service POST-SCALING
7234 step = "Executing post-scale vnf-config-primitive"
7235 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007236 for scaling_config_action in scaling_descriptor[
7237 "scaling-config-action"
7238 ]:
7239 if (
7240 scaling_config_action.get("trigger") == "post-scale-in"
7241 and scaling_type == "SCALE_IN"
7242 ) or (
7243 scaling_config_action.get("trigger") == "post-scale-out"
7244 and scaling_type == "SCALE_OUT"
7245 ):
7246 vnf_config_primitive = scaling_config_action[
7247 "vnf-config-primitive-name-ref"
7248 ]
7249 step = db_nslcmop_update[
7250 "detailed-status"
7251 ] = "executing post-scale scaling-config-action '{}'".format(
7252 vnf_config_primitive
7253 )
tiernoda964822019-01-14 15:53:47 +00007254
aktas5f75f102021-03-15 11:26:10 +03007255 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007256 if db_vnfr.get("additionalParamsForVnf"):
7257 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7258
tierno59d22d22018-09-25 18:10:19 +02007259 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007260 for config_primitive in (
7261 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7262 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007263 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007264 break
7265 else:
tiernoa278b842020-07-08 15:33:55 +00007266 raise LcmException(
7267 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7268 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007269 "config-primitive".format(
7270 scaling_group, vnf_config_primitive
7271 )
7272 )
tierno9ab95942018-10-10 16:44:22 +02007273 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007274 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007275 primitive_params = self._map_primitive_params(
7276 config_primitive, {}, vnfr_params
7277 )
tiernod6de1992018-10-11 13:05:52 +02007278
tierno7c4e24c2020-05-13 08:41:35 +00007279 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007280 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007281 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007282 vnf_index,
7283 vnf_config_primitive,
7284 primitive_params,
7285 "POST-SCALE",
7286 )
quilesj4cda56b2019-12-05 10:02:20 +00007287 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007288 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007289 result = "COMPLETED"
7290 result_detail = "Done"
7291 self.logger.debug(
7292 logging_text
7293 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7294 vnf_config_primitive, result, result_detail
7295 )
7296 )
kuuseac3a8882019-10-03 10:48:06 +02007297 else:
quilesj4cda56b2019-12-05 10:02:20 +00007298 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007299 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007300 op_index = (
7301 len(db_nslcmop.get("_admin", {}).get("operations"))
7302 - 1
7303 )
7304 self.logger.debug(
7305 logging_text
7306 + "vnf_config_primitive={} New sub-operation".format(
7307 vnf_config_primitive
7308 )
7309 )
kuuseac3a8882019-10-03 10:48:06 +02007310 else:
tierno7c4e24c2020-05-13 08:41:35 +00007311 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007312 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7313 op_index
7314 ]
7315 vnf_index = op.get("member_vnf_index")
7316 vnf_config_primitive = op.get("primitive")
7317 primitive_params = op.get("primitive_params")
7318 self.logger.debug(
7319 logging_text
7320 + "vnf_config_primitive={} Sub-operation retry".format(
7321 vnf_config_primitive
7322 )
7323 )
tierno588547c2020-07-01 15:30:20 +00007324 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007325 ee_descriptor_id = config_primitive.get(
7326 "execution-environment-ref"
7327 )
7328 primitive_name = config_primitive.get(
7329 "execution-environment-primitive", vnf_config_primitive
7330 )
7331 ee_id, vca_type = self._look_for_deployed_vca(
7332 nsr_deployed["VCA"],
7333 member_vnf_index=vnf_index,
7334 vdu_id=None,
7335 vdu_count_index=None,
7336 ee_descriptor_id=ee_descriptor_id,
7337 )
kuuseac3a8882019-10-03 10:48:06 +02007338 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007339 ee_id,
7340 primitive_name,
7341 primitive_params,
7342 vca_type=vca_type,
7343 vca_id=vca_id,
7344 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007345 self.logger.debug(
7346 logging_text
7347 + "vnf_config_primitive={} Done with result {} {}".format(
7348 vnf_config_primitive, result, result_detail
7349 )
7350 )
kuuseac3a8882019-10-03 10:48:06 +02007351 # Update operationState = COMPLETED | FAILED
7352 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007353 db_nslcmop, op_index, result, result_detail
7354 )
kuuseac3a8882019-10-03 10:48:06 +02007355
tierno59d22d22018-09-25 18:10:19 +02007356 if result == "FAILED":
7357 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007358 db_nsr_update["config-status"] = old_config_status
7359 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007360 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007361 # Check if each vnf has exporter for metric collection if so update prometheus job records
Rahul Kumar54671c52024-05-09 15:34:01 +05307362 if scaling_type == "SCALE_OUT" and bool(self.service_kpi.old_sa):
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007363 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7364 vnfr_id = db_vnfr["id"]
7365 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7366 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7367 self.logger.debug("exporter config :{}".format(exporter_config))
7368 artifact_path = "{}/{}/{}".format(
7369 base_folder["folder"],
7370 base_folder["pkg-dir"],
7371 "exporter-endpoint",
7372 )
7373 ee_id = None
7374 ee_config_descriptor = exporter_config
7375 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7376 logging_text,
7377 nsr_id,
7378 vnfr_id,
7379 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7380 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7381 user=None,
7382 pub_key=None,
7383 )
7384 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7385 self.logger.debug("Artifact_path:{}".format(artifact_path))
7386 vdu_id_for_prom = None
7387 vdu_index_for_prom = None
7388 for x in get_iterable(db_vnfr, "vdur"):
7389 vdu_id_for_prom = x.get("vdu-id-ref")
7390 vdu_index_for_prom = x.get("count-index")
7391 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7392 vnfr_id = vnfr_id.replace("_", "")
7393 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7394 ee_id=ee_id,
7395 artifact_path=artifact_path,
7396 ee_config_descriptor=ee_config_descriptor,
7397 vnfr_id=vnfr_id,
7398 nsr_id=nsr_id,
7399 target_ip=rw_mgmt_ip,
7400 element_type="VDU",
7401 vdu_id=vdu_id_for_prom,
7402 vdu_index=vdu_index_for_prom,
7403 )
tierno59d22d22018-09-25 18:10:19 +02007404
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007405 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7406 if prometheus_jobs:
7407 db_nsr_update[
7408 "_admin.deployed.prometheus_jobs"
7409 ] = prometheus_jobs
7410 self.update_db_2(
7411 "nsrs",
7412 nsr_id,
7413 db_nsr_update,
7414 )
7415
7416 for job in prometheus_jobs:
7417 self.db.set_one(
7418 "prometheus_jobs",
7419 {"job_name": ""},
7420 job,
7421 upsert=True,
7422 fail_on_empty=False,
7423 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007424 db_nsr_update[
7425 "detailed-status"
7426 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7427 db_nsr_update["operational-status"] = (
7428 "running"
7429 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007430 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007431 )
tiernod6de1992018-10-11 13:05:52 +02007432 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007433 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007434 except (
7435 ROclient.ROClientException,
7436 DbException,
7437 LcmException,
7438 NgRoException,
7439 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007440 self.logger.error(logging_text + "Exit Exception {}".format(e))
7441 exc = e
7442 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007443 self.logger.error(
7444 logging_text + "Cancelled Exception while '{}'".format(step)
7445 )
tierno59d22d22018-09-25 18:10:19 +02007446 exc = "Operation was cancelled"
7447 except Exception as e:
7448 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007449 self.logger.critical(
7450 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7451 exc_info=True,
7452 )
tierno59d22d22018-09-25 18:10:19 +02007453 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007454 error_list = list()
7455 if exc:
7456 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007457 self._write_ns_status(
7458 nsr_id=nsr_id,
7459 ns_state=None,
7460 current_operation="IDLE",
7461 current_operation_id=None,
7462 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007463 try:
7464 if tasks_dict_info:
7465 stage[1] = "Waiting for instantiate pending tasks."
7466 self.logger.debug(logging_text + stage[1])
7467 exc = await self._wait_for_tasks(
7468 logging_text,
7469 tasks_dict_info,
7470 self.timeout.ns_deploy,
7471 stage,
7472 nslcmop_id,
7473 nsr_id=nsr_id,
7474 )
7475 except asyncio.CancelledError:
7476 error_list.append("Cancelled")
7477 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7478 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007479 logging_text,
7480 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007481 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007482 stage,
7483 nslcmop_id,
7484 nsr_id=nsr_id,
7485 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007486 if error_list:
7487 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007488 db_nslcmop_update[
7489 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007490 ] = error_description_nslcmop = "FAILED {}: {}".format(
7491 step, error_detail
7492 )
tiernoa17d4f42020-04-28 09:59:23 +00007493 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007494 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007495 db_nsr_update["operational-status"] = old_operational_status
7496 db_nsr_update["config-status"] = old_config_status
7497 db_nsr_update["detailed-status"] = ""
7498 if scale_process:
7499 if "VCA" in scale_process:
7500 db_nsr_update["config-status"] = "failed"
7501 if "RO" in scale_process:
7502 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007503 db_nsr_update[
7504 "detailed-status"
7505 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007506 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007507 )
tiernoa17d4f42020-04-28 09:59:23 +00007508 else:
7509 error_description_nslcmop = None
7510 nslcmop_operation_state = "COMPLETED"
7511 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007512 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7513 self.db.del_one(
7514 "prometheus_jobs",
7515 {"job_name": prom_job_name},
7516 fail_on_empty=False,
7517 )
quilesj4cda56b2019-12-05 10:02:20 +00007518
garciadeblas5697b8b2021-03-24 09:17:02 +01007519 self._write_op_status(
7520 op_id=nslcmop_id,
7521 stage="",
7522 error_message=error_description_nslcmop,
7523 operation_state=nslcmop_operation_state,
7524 other_update=db_nslcmop_update,
7525 )
tiernoa17d4f42020-04-28 09:59:23 +00007526 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007527 self._write_ns_status(
7528 nsr_id=nsr_id,
7529 ns_state=None,
7530 current_operation="IDLE",
7531 current_operation_id=None,
7532 other_update=db_nsr_update,
7533 )
tiernoa17d4f42020-04-28 09:59:23 +00007534
tierno59d22d22018-09-25 18:10:19 +02007535 if nslcmop_operation_state:
7536 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007537 msg = {
7538 "nsr_id": nsr_id,
7539 "nslcmop_id": nslcmop_id,
7540 "operationState": nslcmop_operation_state,
7541 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007542 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007543 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007544 self.logger.error(
7545 logging_text + "kafka_write notification Exception {}".format(e)
7546 )
tierno59d22d22018-09-25 18:10:19 +02007547 self.logger.debug(logging_text + "Exit")
7548 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007549
aktas5f75f102021-03-15 11:26:10 +03007550 async def _scale_kdu(
7551 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7552 ):
7553 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7554 for kdu_name in _scaling_info:
7555 for kdu_scaling_info in _scaling_info[kdu_name]:
7556 deployed_kdu, index = get_deployed_kdu(
7557 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7558 )
7559 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7560 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007561 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007562 scale = int(kdu_scaling_info["scale"])
7563 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7564
7565 db_dict = {
7566 "collection": "nsrs",
7567 "filter": {"_id": nsr_id},
7568 "path": "_admin.deployed.K8s.{}".format(index),
7569 }
7570
7571 step = "scaling application {}".format(
7572 kdu_scaling_info["resource-name"]
7573 )
7574 self.logger.debug(logging_text + step)
7575
7576 if kdu_scaling_info["type"] == "delete":
7577 kdu_config = get_configuration(db_vnfd, kdu_name)
7578 if (
7579 kdu_config
7580 and kdu_config.get("terminate-config-primitive")
7581 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7582 ):
7583 terminate_config_primitive_list = kdu_config.get(
7584 "terminate-config-primitive"
7585 )
7586 terminate_config_primitive_list.sort(
7587 key=lambda val: int(val["seq"])
7588 )
7589
7590 for (
7591 terminate_config_primitive
7592 ) in terminate_config_primitive_list:
7593 primitive_params_ = self._map_primitive_params(
7594 terminate_config_primitive, {}, {}
7595 )
7596 step = "execute terminate config primitive"
7597 self.logger.debug(logging_text + step)
7598 await asyncio.wait_for(
7599 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7600 cluster_uuid=cluster_uuid,
7601 kdu_instance=kdu_instance,
7602 primitive_name=terminate_config_primitive["name"],
7603 params=primitive_params_,
7604 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007605 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007606 vca_id=vca_id,
7607 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007608 timeout=self.timeout.primitive
7609 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007610 )
7611
7612 await asyncio.wait_for(
7613 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007614 kdu_instance=kdu_instance,
7615 scale=scale,
7616 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007617 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007618 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007619 cluster_uuid=cluster_uuid,
7620 kdu_model=kdu_model,
7621 atomic=True,
7622 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007623 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007624 timeout=self.timeout.scale_on_error
7625 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007626 )
7627
7628 if kdu_scaling_info["type"] == "create":
7629 kdu_config = get_configuration(db_vnfd, kdu_name)
7630 if (
7631 kdu_config
7632 and kdu_config.get("initial-config-primitive")
7633 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7634 ):
7635 initial_config_primitive_list = kdu_config.get(
7636 "initial-config-primitive"
7637 )
7638 initial_config_primitive_list.sort(
7639 key=lambda val: int(val["seq"])
7640 )
7641
7642 for initial_config_primitive in initial_config_primitive_list:
7643 primitive_params_ = self._map_primitive_params(
7644 initial_config_primitive, {}, {}
7645 )
7646 step = "execute initial config primitive"
7647 self.logger.debug(logging_text + step)
7648 await asyncio.wait_for(
7649 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7650 cluster_uuid=cluster_uuid,
7651 kdu_instance=kdu_instance,
7652 primitive_name=initial_config_primitive["name"],
7653 params=primitive_params_,
7654 db_dict=db_dict,
7655 vca_id=vca_id,
7656 ),
7657 timeout=600,
7658 )
7659
garciadeblas5697b8b2021-03-24 09:17:02 +01007660 async def _scale_ng_ro(
7661 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7662 ):
tierno2357f4e2020-10-19 16:38:59 +00007663 nsr_id = db_nslcmop["nsInstanceId"]
7664 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7665 db_vnfrs = {}
7666
7667 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007668 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007669
7670 # for each vnf in ns, read vnfd
7671 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7672 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7673 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007674 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007675 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007676 # read from db
7677 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007678 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007679 n2vc_key = self.n2vc.get_public_key()
7680 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007681 self.scale_vnfr(
7682 db_vnfr,
7683 vdu_scaling_info.get("vdu-create"),
7684 vdu_scaling_info.get("vdu-delete"),
7685 mark_delete=True,
7686 )
tierno2357f4e2020-10-19 16:38:59 +00007687 # db_vnfr has been updated, update db_vnfrs to use it
7688 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007689 await self._instantiate_ng_ro(
7690 logging_text,
7691 nsr_id,
7692 db_nsd,
7693 db_nsr,
7694 db_nslcmop,
7695 db_vnfrs,
7696 db_vnfds,
7697 n2vc_key_list,
7698 stage=stage,
7699 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007700 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007701 )
tierno2357f4e2020-10-19 16:38:59 +00007702 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007703 self.scale_vnfr(
7704 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7705 )
tierno2357f4e2020-10-19 16:38:59 +00007706
bravof73bac502021-05-11 07:38:47 -04007707 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007708 self,
7709 ee_id: str,
7710 artifact_path: str,
7711 ee_config_descriptor: dict,
7712 vnfr_id: str,
7713 nsr_id: str,
7714 target_ip: str,
7715 element_type: str,
7716 vnf_member_index: str = "",
7717 vdu_id: str = "",
7718 vdu_index: int = None,
7719 kdu_name: str = "",
7720 kdu_index: int = None,
7721 ) -> dict:
7722 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7723 This method will wait until the corresponding VDU or KDU is fully instantiated
7724
7725 Args:
7726 ee_id (str): Execution Environment ID
7727 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7728 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7729 vnfr_id (str): VNFR ID where this EE applies
7730 nsr_id (str): NSR ID where this EE applies
7731 target_ip (str): VDU/KDU instance IP address
7732 element_type (str): NS or VNF or VDU or KDU
7733 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7734 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7735 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7736 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7737 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7738
7739 Raises:
7740 LcmException: When the VDU or KDU instance was not found in an hour
7741
7742 Returns:
7743 _type_: Prometheus jobs
7744 """
7745 # default the vdur and kdur names to an empty string, to avoid any later
7746 # problem with Prometheus when the element type is not VDU or KDU
7747 vdur_name = ""
7748 kdur_name = ""
7749
tiernob996d942020-07-03 14:52:28 +00007750 # look if exist a file called 'prometheus*.j2' and
7751 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007752 job_file = next(
7753 (
7754 f
7755 for f in artifact_content
7756 if f.startswith("prometheus") and f.endswith(".j2")
7757 ),
7758 None,
7759 )
tiernob996d942020-07-03 14:52:28 +00007760 if not job_file:
7761 return
k4.rahul74944982023-04-19 17:00:52 +05307762 self.logger.debug("Artifact path{}".format(artifact_path))
7763 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007764 with self.fs.file_open((artifact_path, job_file), "r") as f:
7765 job_data = f.read()
7766
Pedro Escaleira120695e2022-06-11 21:17:26 +01007767 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7768 if element_type in ("VDU", "KDU"):
7769 for _ in range(360):
7770 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7771 if vdu_id and vdu_index is not None:
7772 vdur = next(
7773 (
7774 x
7775 for x in get_iterable(db_vnfr, "vdur")
7776 if (
7777 x.get("vdu-id-ref") == vdu_id
7778 and x.get("count-index") == vdu_index
7779 )
7780 ),
7781 {},
7782 )
7783 if vdur.get("name"):
7784 vdur_name = vdur.get("name")
7785 break
7786 if kdu_name and kdu_index is not None:
7787 kdur = next(
7788 (
7789 x
7790 for x in get_iterable(db_vnfr, "kdur")
7791 if (
7792 x.get("kdu-name") == kdu_name
7793 and x.get("count-index") == kdu_index
7794 )
7795 ),
7796 {},
7797 )
7798 if kdur.get("name"):
7799 kdur_name = kdur.get("name")
7800 break
7801
Gabriel Cubae7898982023-05-11 01:57:21 -05007802 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007803 else:
7804 if vdu_id and vdu_index is not None:
7805 raise LcmException(
7806 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7807 )
7808 if kdu_name and kdu_index is not None:
7809 raise LcmException(
7810 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7811 )
7812
k4.rahul74944982023-04-19 17:00:52 +05307813 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007814 _, namespace, helm_id = get_ee_id_parts(
7815 ee_id
7816 ) # get namespace and EE gRPC service name
7817 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307818 host_port = "80"
7819 vnfr_id = vnfr_id.replace("-", "")
7820 variables = {
7821 "JOB_NAME": vnfr_id,
7822 "TARGET_IP": target_ip,
7823 "EXPORTER_POD_IP": host_name,
7824 "EXPORTER_POD_PORT": host_port,
7825 "NSR_ID": nsr_id,
7826 "VNF_MEMBER_INDEX": vnf_member_index,
7827 "VDUR_NAME": vdur_name,
7828 "KDUR_NAME": kdur_name,
7829 "ELEMENT_TYPE": element_type,
7830 }
7831 else:
7832 metric_path = ee_config_descriptor["metric-path"]
7833 target_port = ee_config_descriptor["metric-port"]
7834 vnfr_id = vnfr_id.replace("-", "")
7835 variables = {
7836 "JOB_NAME": vnfr_id,
7837 "TARGET_IP": target_ip,
7838 "TARGET_PORT": target_port,
7839 "METRIC_PATH": metric_path,
7840 }
7841
bravof73bac502021-05-11 07:38:47 -04007842 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007843 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7844 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007845 if (
7846 not isinstance(job.get("job_name"), str)
7847 or vnfr_id not in job["job_name"]
7848 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307849 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007850 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007851 job["vnfr_id"] = vnfr_id
7852 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007853
preethika.p28b0bf82022-09-23 07:36:28 +00007854 async def rebuild_start_stop(
7855 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7856 ):
k4.rahulb827de92022-05-02 16:35:02 +00007857 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7858 self.logger.info(logging_text + "Enter")
7859 stage = ["Preparing the environment", ""]
7860 # database nsrs record
7861 db_nsr_update = {}
7862 vdu_vim_name = None
7863 vim_vm_id = None
7864 # in case of error, indicates what part of scale was failed to put nsr at error status
7865 start_deploy = time()
7866 try:
7867 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7868 vim_account_id = db_vnfr.get("vim-account-id")
7869 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007870 vdu_id = additional_param["vdu_id"]
7871 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007872 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007873 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007874 )
k4.rahulb827de92022-05-02 16:35:02 +00007875 if vdur:
7876 vdu_vim_name = vdur["name"]
7877 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7878 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007879 else:
7880 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007881 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7882 # wait for any previous tasks in process
7883 stage[1] = "Waiting for previous operations to terminate"
7884 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007885 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007886
7887 stage[1] = "Reading from database."
7888 self.logger.info(stage[1])
7889 self._write_ns_status(
7890 nsr_id=nsr_id,
7891 ns_state=None,
7892 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007893 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007894 )
7895 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7896
7897 # read from db: ns
7898 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7899 db_nsr_update["operational-status"] = operation_type
7900 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7901 # Payload for RO
7902 desc = {
7903 operation_type: {
7904 "vim_vm_id": vim_vm_id,
7905 "vnf_id": vnf_id,
7906 "vdu_index": additional_param["count-index"],
7907 "vdu_id": vdur["id"],
7908 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007909 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007910 }
7911 }
7912 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7913 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7914 self.logger.info("ro nsr id: {}".format(nsr_id))
7915 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7916 self.logger.info("response from RO: {}".format(result_dict))
7917 action_id = result_dict["action_id"]
7918 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007919 nsr_id,
7920 action_id,
7921 nslcmop_id,
7922 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007923 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007924 None,
7925 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007926 )
7927 return "COMPLETED", "Done"
7928 except (ROclient.ROClientException, DbException, LcmException) as e:
7929 self.logger.error("Exit Exception {}".format(e))
7930 exc = e
7931 except asyncio.CancelledError:
7932 self.logger.error("Cancelled Exception while '{}'".format(stage))
7933 exc = "Operation was cancelled"
7934 except Exception as e:
7935 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007936 self.logger.critical(
7937 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7938 )
k4.rahulb827de92022-05-02 16:35:02 +00007939 return "FAILED", "Error in operate VNF {}".format(exc)
7940
elumalai80bcf1c2022-04-28 18:05:01 +05307941 async def migrate(self, nsr_id, nslcmop_id):
7942 """
7943 Migrate VNFs and VDUs instances in a NS
7944
7945 :param: nsr_id: NS Instance ID
7946 :param: nslcmop_id: nslcmop ID of migrate
7947
7948 """
7949 # Try to lock HA task here
7950 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7951 if not task_is_locked_by_me:
7952 return
7953 logging_text = "Task ns={} migrate ".format(nsr_id)
7954 self.logger.debug(logging_text + "Enter")
7955 # get all needed from database
7956 db_nslcmop = None
7957 db_nslcmop_update = {}
7958 nslcmop_operation_state = None
7959 db_nsr_update = {}
7960 target = {}
7961 exc = None
7962 # in case of error, indicates what part of scale was failed to put nsr at error status
7963 start_deploy = time()
7964
7965 try:
7966 # wait for any previous tasks in process
7967 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007968 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307969
7970 self._write_ns_status(
7971 nsr_id=nsr_id,
7972 ns_state=None,
7973 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007974 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307975 )
7976 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007977 self.logger.debug(
7978 step + " after having waited for previous tasks to be completed"
7979 )
elumalai80bcf1c2022-04-28 18:05:01 +05307980 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7981 migrate_params = db_nslcmop.get("operationParams")
7982
7983 target = {}
7984 target.update(migrate_params)
Pedro Pereirab6cccb22024-08-23 10:23:02 +01007985
7986 if "migrateToHost" in target:
7987 desc = await self.RO.migrate(nsr_id, target)
7988 self.logger.debug("RO return > {}".format(desc))
7989 action_id = desc["action_id"]
7990 await self._wait_ng_ro(
7991 nsr_id,
7992 action_id,
7993 nslcmop_id,
7994 start_deploy,
7995 self.timeout.migrate,
7996 operation="migrate",
7997 )
7998
7999 elif "targetHostK8sLabels" in target:
8000 await self.k8sclusterhelm3.migrate(nsr_id, target)
8001
elumalai80bcf1c2022-04-28 18:05:01 +05308002 except (ROclient.ROClientException, DbException, LcmException) as e:
8003 self.logger.error("Exit Exception {}".format(e))
8004 exc = e
8005 except asyncio.CancelledError:
8006 self.logger.error("Cancelled Exception while '{}'".format(step))
8007 exc = "Operation was cancelled"
8008 except Exception as e:
8009 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03008010 self.logger.critical(
8011 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8012 )
elumalai80bcf1c2022-04-28 18:05:01 +05308013 finally:
8014 self._write_ns_status(
8015 nsr_id=nsr_id,
8016 ns_state=None,
8017 current_operation="IDLE",
8018 current_operation_id=None,
8019 )
8020 if exc:
aticig349aa462022-05-19 12:29:35 +03008021 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308022 nslcmop_operation_state = "FAILED"
8023 else:
8024 nslcmop_operation_state = "COMPLETED"
8025 db_nslcmop_update["detailed-status"] = "Done"
8026 db_nsr_update["detailed-status"] = "Done"
8027
8028 self._write_op_status(
8029 op_id=nslcmop_id,
8030 stage="",
8031 error_message="",
8032 operation_state=nslcmop_operation_state,
8033 other_update=db_nslcmop_update,
8034 )
8035 if nslcmop_operation_state:
8036 try:
8037 msg = {
8038 "nsr_id": nsr_id,
8039 "nslcmop_id": nslcmop_id,
8040 "operationState": nslcmop_operation_state,
8041 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008042 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308043 except Exception as e:
8044 self.logger.error(
8045 logging_text + "kafka_write notification Exception {}".format(e)
8046 )
8047 self.logger.debug(logging_text + "Exit")
8048 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008049
garciadeblas07f4e4c2022-06-09 09:42:58 +02008050 async def heal(self, nsr_id, nslcmop_id):
8051 """
8052 Heal NS
8053
8054 :param nsr_id: ns instance to heal
8055 :param nslcmop_id: operation to run
8056 :return:
8057 """
8058
8059 # Try to lock HA task here
8060 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8061 if not task_is_locked_by_me:
8062 return
8063
8064 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8065 stage = ["", "", ""]
8066 tasks_dict_info = {}
8067 # ^ stage, step, VIM progress
8068 self.logger.debug(logging_text + "Enter")
8069 # get all needed from database
8070 db_nsr = None
8071 db_nslcmop_update = {}
8072 db_nsr_update = {}
8073 db_vnfrs = {} # vnf's info indexed by _id
8074 exc = None
8075 old_operational_status = ""
8076 old_config_status = ""
8077 nsi_id = None
8078 try:
8079 # wait for any previous tasks in process
8080 step = "Waiting for previous operations to terminate"
8081 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8082 self._write_ns_status(
8083 nsr_id=nsr_id,
8084 ns_state=None,
8085 current_operation="HEALING",
8086 current_operation_id=nslcmop_id,
8087 )
8088
8089 step = "Getting nslcmop from database"
8090 self.logger.debug(
8091 step + " after having waited for previous tasks to be completed"
8092 )
8093 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8094
8095 step = "Getting nsr from database"
8096 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8097 old_operational_status = db_nsr["operational-status"]
8098 old_config_status = db_nsr["config-status"]
8099
8100 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008101 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008102 "_admin.deployed.RO.operational-status": "healing",
8103 }
8104 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8105
8106 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008107 await self.heal_RO(
8108 logging_text=logging_text,
8109 nsr_id=nsr_id,
8110 db_nslcmop=db_nslcmop,
8111 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008112 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008113 # VCA tasks
8114 # read from db: nsd
8115 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8116 self.logger.debug(logging_text + stage[1])
8117 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8118 self.fs.sync(db_nsr["nsd-id"])
8119 db_nsr["nsd"] = nsd
8120 # read from db: vnfr's of this ns
8121 step = "Getting vnfrs from db"
8122 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8123 for vnfr in db_vnfrs_list:
8124 db_vnfrs[vnfr["_id"]] = vnfr
8125 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8126
8127 # Check for each target VNF
8128 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8129 for target_vnf in target_list:
8130 # Find this VNF in the list from DB
8131 vnfr_id = target_vnf.get("vnfInstanceId", None)
8132 if vnfr_id:
8133 db_vnfr = db_vnfrs[vnfr_id]
8134 vnfd_id = db_vnfr.get("vnfd-id")
8135 vnfd_ref = db_vnfr.get("vnfd-ref")
8136 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8137 base_folder = vnfd["_admin"]["storage"]
8138 vdu_id = None
8139 vdu_index = 0
8140 vdu_name = None
8141 kdu_name = None
8142 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8143 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8144
8145 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008146 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8147 "vdu", []
8148 )
garciadeblas50639832022-09-01 13:09:47 +02008149 if not target_vdu_list:
8150 # Codigo nuevo para crear diccionario
8151 target_vdu_list = []
8152 for existing_vdu in db_vnfr.get("vdur"):
8153 vdu_name = existing_vdu.get("vdu-name", None)
8154 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008155 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8156 "run-day1", False
8157 )
8158 vdu_to_be_healed = {
8159 "vdu-id": vdu_name,
8160 "count-index": vdu_index,
8161 "run-day1": vdu_run_day1,
8162 }
garciadeblas50639832022-09-01 13:09:47 +02008163 target_vdu_list.append(vdu_to_be_healed)
8164 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008165 deploy_params_vdu = target_vdu
8166 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008167 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8168 "additionalParams", {}
8169 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008170 deploy_params_vdu["run-day1"] = target_vnf[
8171 "additionalParams"
8172 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008173 vdu_name = target_vdu.get("vdu-id", None)
8174 # TODO: Get vdu_id from vdud.
8175 vdu_id = vdu_name
8176 # For multi instance VDU count-index is mandatory
8177 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008178 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008179
8180 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8181 stage[1] = "Deploying Execution Environments."
8182 self.logger.debug(logging_text + stage[1])
8183
8184 # VNF Level charm. Normal case when proxy charms.
8185 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8186 descriptor_config = get_configuration(vnfd, vnfd_ref)
8187 if descriptor_config:
8188 # Continue if healed machine is management machine
8189 vnf_ip_address = db_vnfr.get("ip-address")
8190 target_instance = None
8191 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008192 if (
8193 instance["vdu-name"] == vdu_name
8194 and instance["count-index"] == vdu_index
8195 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008196 target_instance = instance
8197 break
8198 if vnf_ip_address == target_instance.get("ip-address"):
8199 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008200 logging_text=logging_text
8201 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8202 member_vnf_index, vdu_name, vdu_index
8203 ),
8204 db_nsr=db_nsr,
8205 db_vnfr=db_vnfr,
8206 nslcmop_id=nslcmop_id,
8207 nsr_id=nsr_id,
8208 nsi_id=nsi_id,
8209 vnfd_id=vnfd_ref,
8210 vdu_id=None,
8211 kdu_name=None,
8212 member_vnf_index=member_vnf_index,
8213 vdu_index=0,
8214 vdu_name=None,
8215 deploy_params=deploy_params_vdu,
8216 descriptor_config=descriptor_config,
8217 base_folder=base_folder,
8218 task_instantiation_info=tasks_dict_info,
8219 stage=stage,
8220 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008221
8222 # VDU Level charm. Normal case with native charms.
8223 descriptor_config = get_configuration(vnfd, vdu_name)
8224 if descriptor_config:
8225 self._heal_n2vc(
8226 logging_text=logging_text
8227 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8228 member_vnf_index, vdu_name, vdu_index
8229 ),
8230 db_nsr=db_nsr,
8231 db_vnfr=db_vnfr,
8232 nslcmop_id=nslcmop_id,
8233 nsr_id=nsr_id,
8234 nsi_id=nsi_id,
8235 vnfd_id=vnfd_ref,
8236 vdu_id=vdu_id,
8237 kdu_name=kdu_name,
8238 member_vnf_index=member_vnf_index,
8239 vdu_index=vdu_index,
8240 vdu_name=vdu_name,
8241 deploy_params=deploy_params_vdu,
8242 descriptor_config=descriptor_config,
8243 base_folder=base_folder,
8244 task_instantiation_info=tasks_dict_info,
8245 stage=stage,
8246 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008247 except (
8248 ROclient.ROClientException,
8249 DbException,
8250 LcmException,
8251 NgRoException,
8252 ) as e:
8253 self.logger.error(logging_text + "Exit Exception {}".format(e))
8254 exc = e
8255 except asyncio.CancelledError:
8256 self.logger.error(
8257 logging_text + "Cancelled Exception while '{}'".format(step)
8258 )
8259 exc = "Operation was cancelled"
8260 except Exception as e:
8261 exc = traceback.format_exc()
8262 self.logger.critical(
8263 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8264 exc_info=True,
8265 )
8266 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008267 error_list = list()
36970544ef442024-04-01 10:58:42 +00008268 if db_vnfrs_list and target_list:
8269 for vnfrs in db_vnfrs_list:
8270 for vnf_instance in target_list:
8271 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8272 self.db.set_list(
8273 "vnfrs",
8274 {"_id": vnfrs["_id"]},
8275 {"_admin.modified": time()},
8276 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008277 if exc:
8278 error_list.append(str(exc))
8279 try:
8280 if tasks_dict_info:
8281 stage[1] = "Waiting for healing pending tasks."
8282 self.logger.debug(logging_text + stage[1])
8283 exc = await self._wait_for_tasks(
8284 logging_text,
8285 tasks_dict_info,
8286 self.timeout.ns_deploy,
8287 stage,
8288 nslcmop_id,
8289 nsr_id=nsr_id,
8290 )
8291 except asyncio.CancelledError:
8292 error_list.append("Cancelled")
8293 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8294 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008295 logging_text,
8296 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008297 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008298 stage,
8299 nslcmop_id,
8300 nsr_id=nsr_id,
8301 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008302 if error_list:
8303 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008304 db_nslcmop_update[
8305 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008306 ] = error_description_nslcmop = "FAILED {}: {}".format(
8307 step, error_detail
8308 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008309 nslcmop_operation_state = "FAILED"
8310 if db_nsr:
8311 db_nsr_update["operational-status"] = old_operational_status
8312 db_nsr_update["config-status"] = old_config_status
8313 db_nsr_update[
8314 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008315 ] = "FAILED healing nslcmop={} {}: {}".format(
8316 nslcmop_id, step, error_detail
8317 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008318 for task, task_name in tasks_dict_info.items():
8319 if not task.done() or task.cancelled() or task.exception():
8320 if task_name.startswith(self.task_name_deploy_vca):
8321 # A N2VC task is pending
8322 db_nsr_update["config-status"] = "failed"
8323 else:
8324 # RO task is pending
8325 db_nsr_update["operational-status"] = "failed"
8326 else:
8327 error_description_nslcmop = None
8328 nslcmop_operation_state = "COMPLETED"
8329 db_nslcmop_update["detailed-status"] = "Done"
8330 db_nsr_update["detailed-status"] = "Done"
8331 db_nsr_update["operational-status"] = "running"
8332 db_nsr_update["config-status"] = "configured"
8333
8334 self._write_op_status(
8335 op_id=nslcmop_id,
8336 stage="",
8337 error_message=error_description_nslcmop,
8338 operation_state=nslcmop_operation_state,
8339 other_update=db_nslcmop_update,
8340 )
8341 if db_nsr:
8342 self._write_ns_status(
8343 nsr_id=nsr_id,
8344 ns_state=None,
8345 current_operation="IDLE",
8346 current_operation_id=None,
8347 other_update=db_nsr_update,
8348 )
8349
8350 if nslcmop_operation_state:
8351 try:
8352 msg = {
8353 "nsr_id": nsr_id,
8354 "nslcmop_id": nslcmop_id,
8355 "operationState": nslcmop_operation_state,
8356 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008357 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008358 except Exception as e:
8359 self.logger.error(
8360 logging_text + "kafka_write notification Exception {}".format(e)
8361 )
8362 self.logger.debug(logging_text + "Exit")
8363 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8364
8365 async def heal_RO(
8366 self,
8367 logging_text,
8368 nsr_id,
8369 db_nslcmop,
8370 stage,
8371 ):
8372 """
8373 Heal at RO
8374 :param logging_text: preffix text to use at logging
8375 :param nsr_id: nsr identity
8376 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8377 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8378 :return: None or exception
8379 """
preethika.p28b0bf82022-09-23 07:36:28 +00008380
garciadeblas07f4e4c2022-06-09 09:42:58 +02008381 def get_vim_account(vim_account_id):
8382 nonlocal db_vims
8383 if vim_account_id in db_vims:
8384 return db_vims[vim_account_id]
8385 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8386 db_vims[vim_account_id] = db_vim
8387 return db_vim
8388
8389 try:
8390 start_heal = time()
8391 ns_params = db_nslcmop.get("operationParams")
8392 if ns_params and ns_params.get("timeout_ns_heal"):
8393 timeout_ns_heal = ns_params["timeout_ns_heal"]
8394 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008395 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008396
8397 db_vims = {}
8398
8399 nslcmop_id = db_nslcmop["_id"]
8400 target = {
8401 "action_id": nslcmop_id,
8402 }
preethika.p28b0bf82022-09-23 07:36:28 +00008403 self.logger.warning(
8404 "db_nslcmop={} and timeout_ns_heal={}".format(
8405 db_nslcmop, timeout_ns_heal
8406 )
8407 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008408 target.update(db_nslcmop.get("operationParams", {}))
8409
8410 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8411 desc = await self.RO.recreate(nsr_id, target)
8412 self.logger.debug("RO return > {}".format(desc))
8413 action_id = desc["action_id"]
8414 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8415 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008416 nsr_id,
8417 action_id,
8418 nslcmop_id,
8419 start_heal,
8420 timeout_ns_heal,
8421 stage,
8422 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008423 )
8424
8425 # Updating NSR
8426 db_nsr_update = {
8427 "_admin.deployed.RO.operational-status": "running",
8428 "detailed-status": " ".join(stage),
8429 }
8430 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8431 self._write_op_status(nslcmop_id, stage)
8432 self.logger.debug(
8433 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8434 )
8435
8436 except Exception as e:
8437 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008438 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008439 self.logger.error(
8440 "Error healing at VIM {}".format(e),
8441 exc_info=not isinstance(
8442 e,
8443 (
8444 ROclient.ROClientException,
8445 LcmException,
8446 DbException,
8447 NgRoException,
8448 ),
8449 ),
8450 )
8451 raise
8452
8453 def _heal_n2vc(
8454 self,
8455 logging_text,
8456 db_nsr,
8457 db_vnfr,
8458 nslcmop_id,
8459 nsr_id,
8460 nsi_id,
8461 vnfd_id,
8462 vdu_id,
8463 kdu_name,
8464 member_vnf_index,
8465 vdu_index,
8466 vdu_name,
8467 deploy_params,
8468 descriptor_config,
8469 base_folder,
8470 task_instantiation_info,
8471 stage,
8472 ):
8473 # launch instantiate_N2VC in a asyncio task and register task object
8474 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8475 # if not found, create one entry and update database
8476 # fill db_nsr._admin.deployed.VCA.<index>
8477
8478 self.logger.debug(
8479 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8480 )
aticig9bc63ac2022-07-27 09:32:06 +03008481
8482 charm_name = ""
8483 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008484 if "execution-environment-list" in descriptor_config:
8485 ee_list = descriptor_config.get("execution-environment-list", [])
8486 elif "juju" in descriptor_config:
8487 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008488 if "execution-environment-list" not in descriptor_config:
8489 # charm name is only required for ns charms
8490 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008491 else: # other types as script are not supported
8492 ee_list = []
8493
8494 for ee_item in ee_list:
8495 self.logger.debug(
8496 logging_text
8497 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8498 ee_item.get("juju"), ee_item.get("helm-chart")
8499 )
8500 )
8501 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008502 vca_name, charm_name, vca_type = self.get_vca_info(
8503 ee_item, db_nsr, get_charm_name
8504 )
8505 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008506 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008507 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008508 )
8509 continue
8510
8511 vca_index = -1
8512 for vca_index, vca_deployed in enumerate(
8513 db_nsr["_admin"]["deployed"]["VCA"]
8514 ):
8515 if not vca_deployed:
8516 continue
8517 if (
8518 vca_deployed.get("member-vnf-index") == member_vnf_index
8519 and vca_deployed.get("vdu_id") == vdu_id
8520 and vca_deployed.get("kdu_name") == kdu_name
8521 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8522 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8523 ):
8524 break
8525 else:
8526 # not found, create one.
8527 target = (
8528 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8529 )
8530 if vdu_id:
8531 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8532 elif kdu_name:
8533 target += "/kdu/{}".format(kdu_name)
8534 vca_deployed = {
8535 "target_element": target,
8536 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8537 "member-vnf-index": member_vnf_index,
8538 "vdu_id": vdu_id,
8539 "kdu_name": kdu_name,
8540 "vdu_count_index": vdu_index,
8541 "operational-status": "init", # TODO revise
8542 "detailed-status": "", # TODO revise
8543 "step": "initial-deploy", # TODO revise
8544 "vnfd_id": vnfd_id,
8545 "vdu_name": vdu_name,
8546 "type": vca_type,
8547 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008548 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008549 }
8550 vca_index += 1
8551
8552 # create VCA and configurationStatus in db
8553 db_dict = {
8554 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8555 "configurationStatus.{}".format(vca_index): dict(),
8556 }
8557 self.update_db_2("nsrs", nsr_id, db_dict)
8558
8559 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8560
8561 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8562 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8563 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8564
8565 # Launch task
8566 task_n2vc = asyncio.ensure_future(
8567 self.heal_N2VC(
8568 logging_text=logging_text,
8569 vca_index=vca_index,
8570 nsi_id=nsi_id,
8571 db_nsr=db_nsr,
8572 db_vnfr=db_vnfr,
8573 vdu_id=vdu_id,
8574 kdu_name=kdu_name,
8575 vdu_index=vdu_index,
8576 deploy_params=deploy_params,
8577 config_descriptor=descriptor_config,
8578 base_folder=base_folder,
8579 nslcmop_id=nslcmop_id,
8580 stage=stage,
8581 vca_type=vca_type,
8582 vca_name=vca_name,
8583 ee_config_descriptor=ee_item,
8584 )
8585 )
8586 self.lcm_tasks.register(
8587 "ns",
8588 nsr_id,
8589 nslcmop_id,
8590 "instantiate_N2VC-{}".format(vca_index),
8591 task_n2vc,
8592 )
8593 task_instantiation_info[
8594 task_n2vc
8595 ] = self.task_name_deploy_vca + " {}.{}".format(
8596 member_vnf_index or "", vdu_id or ""
8597 )
8598
8599 async def heal_N2VC(
8600 self,
8601 logging_text,
8602 vca_index,
8603 nsi_id,
8604 db_nsr,
8605 db_vnfr,
8606 vdu_id,
8607 kdu_name,
8608 vdu_index,
8609 config_descriptor,
8610 deploy_params,
8611 base_folder,
8612 nslcmop_id,
8613 stage,
8614 vca_type,
8615 vca_name,
8616 ee_config_descriptor,
8617 ):
8618 nsr_id = db_nsr["_id"]
8619 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8620 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8621 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8622 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8623 db_dict = {
8624 "collection": "nsrs",
8625 "filter": {"_id": nsr_id},
8626 "path": db_update_entry,
8627 }
8628 step = ""
8629 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008630 element_type = "NS"
8631 element_under_configuration = nsr_id
8632
8633 vnfr_id = None
8634 if db_vnfr:
8635 vnfr_id = db_vnfr["_id"]
8636 osm_config["osm"]["vnf_id"] = vnfr_id
8637
8638 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8639
8640 if vca_type == "native_charm":
8641 index_number = 0
8642 else:
8643 index_number = vdu_index or 0
8644
8645 if vnfr_id:
8646 element_type = "VNF"
8647 element_under_configuration = vnfr_id
8648 namespace += ".{}-{}".format(vnfr_id, index_number)
8649 if vdu_id:
8650 namespace += ".{}-{}".format(vdu_id, index_number)
8651 element_type = "VDU"
8652 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8653 osm_config["osm"]["vdu_id"] = vdu_id
8654 elif kdu_name:
8655 namespace += ".{}".format(kdu_name)
8656 element_type = "KDU"
8657 element_under_configuration = kdu_name
8658 osm_config["osm"]["kdu_name"] = kdu_name
8659
8660 # Get artifact path
8661 if base_folder["pkg-dir"]:
8662 artifact_path = "{}/{}/{}/{}".format(
8663 base_folder["folder"],
8664 base_folder["pkg-dir"],
8665 "charms"
8666 if vca_type
8667 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8668 else "helm-charts",
8669 vca_name,
8670 )
8671 else:
8672 artifact_path = "{}/Scripts/{}/{}/".format(
8673 base_folder["folder"],
8674 "charms"
8675 if vca_type
8676 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8677 else "helm-charts",
8678 vca_name,
8679 )
8680
8681 self.logger.debug("Artifact path > {}".format(artifact_path))
8682
8683 # get initial_config_primitive_list that applies to this element
8684 initial_config_primitive_list = config_descriptor.get(
8685 "initial-config-primitive"
8686 )
8687
8688 self.logger.debug(
8689 "Initial config primitive list > {}".format(
8690 initial_config_primitive_list
8691 )
8692 )
8693
8694 # add config if not present for NS charm
8695 ee_descriptor_id = ee_config_descriptor.get("id")
8696 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8697 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8698 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8699 )
8700
8701 self.logger.debug(
8702 "Initial config primitive list #2 > {}".format(
8703 initial_config_primitive_list
8704 )
8705 )
8706 # n2vc_redesign STEP 3.1
8707 # find old ee_id if exists
8708 ee_id = vca_deployed.get("ee_id")
8709
8710 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8711 # create or register execution environment in VCA. Only for native charms when healing
8712 if vca_type == "native_charm":
8713 step = "Waiting to VM being up and getting IP address"
8714 self.logger.debug(logging_text + step)
8715 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8716 logging_text,
8717 nsr_id,
8718 vnfr_id,
8719 vdu_id,
8720 vdu_index,
8721 user=None,
8722 pub_key=None,
8723 )
8724 credentials = {"hostname": rw_mgmt_ip}
8725 # get username
8726 username = deep_get(
8727 config_descriptor, ("config-access", "ssh-access", "default-user")
8728 )
8729 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8730 # merged. Meanwhile let's get username from initial-config-primitive
8731 if not username and initial_config_primitive_list:
8732 for config_primitive in initial_config_primitive_list:
8733 for param in config_primitive.get("parameter", ()):
8734 if param["name"] == "ssh-username":
8735 username = param["value"]
8736 break
8737 if not username:
8738 raise LcmException(
8739 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8740 "'config-access.ssh-access.default-user'"
8741 )
8742 credentials["username"] = username
8743
8744 # n2vc_redesign STEP 3.2
8745 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8746 self._write_configuration_status(
8747 nsr_id=nsr_id,
8748 vca_index=vca_index,
8749 status="REGISTERING",
8750 element_under_configuration=element_under_configuration,
8751 element_type=element_type,
8752 )
8753
8754 step = "register execution environment {}".format(credentials)
8755 self.logger.debug(logging_text + step)
8756 ee_id = await self.vca_map[vca_type].register_execution_environment(
8757 credentials=credentials,
8758 namespace=namespace,
8759 db_dict=db_dict,
8760 vca_id=vca_id,
8761 )
8762
8763 # update ee_id en db
8764 db_dict_ee_id = {
8765 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8766 }
8767 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8768
8769 # for compatibility with MON/POL modules, the need model and application name at database
8770 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8771 # Not sure if this need to be done when healing
8772 """
8773 ee_id_parts = ee_id.split(".")
8774 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8775 if len(ee_id_parts) >= 2:
8776 model_name = ee_id_parts[0]
8777 application_name = ee_id_parts[1]
8778 db_nsr_update[db_update_entry + "model"] = model_name
8779 db_nsr_update[db_update_entry + "application"] = application_name
8780 """
8781
8782 # n2vc_redesign STEP 3.3
8783 # Install configuration software. Only for native charms.
8784 step = "Install configuration Software"
8785
8786 self._write_configuration_status(
8787 nsr_id=nsr_id,
8788 vca_index=vca_index,
8789 status="INSTALLING SW",
8790 element_under_configuration=element_under_configuration,
8791 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008792 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008793 other_update=None,
8794 )
8795
8796 # TODO check if already done
8797 self.logger.debug(logging_text + step)
8798 config = None
8799 if vca_type == "native_charm":
8800 config_primitive = next(
8801 (p for p in initial_config_primitive_list if p["name"] == "config"),
8802 None,
8803 )
8804 if config_primitive:
8805 config = self._map_primitive_params(
8806 config_primitive, {}, deploy_params
8807 )
8808 await self.vca_map[vca_type].install_configuration_sw(
8809 ee_id=ee_id,
8810 artifact_path=artifact_path,
8811 db_dict=db_dict,
8812 config=config,
8813 num_units=1,
8814 vca_id=vca_id,
8815 vca_type=vca_type,
8816 )
8817
8818 # write in db flag of configuration_sw already installed
8819 self.update_db_2(
8820 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8821 )
8822
8823 # Not sure if this need to be done when healing
8824 """
8825 # add relations for this VCA (wait for other peers related with this VCA)
8826 await self._add_vca_relations(
8827 logging_text=logging_text,
8828 nsr_id=nsr_id,
8829 vca_type=vca_type,
8830 vca_index=vca_index,
8831 )
8832 """
8833
8834 # if SSH access is required, then get execution environment SSH public
8835 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00008836 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008837 pub_key = None
8838 user = None
8839 # self.logger.debug("get ssh key block")
8840 if deep_get(
8841 config_descriptor, ("config-access", "ssh-access", "required")
8842 ):
8843 # self.logger.debug("ssh key needed")
8844 # Needed to inject a ssh key
8845 user = deep_get(
8846 config_descriptor,
8847 ("config-access", "ssh-access", "default-user"),
8848 )
8849 step = "Install configuration Software, getting public ssh key"
8850 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8851 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8852 )
8853
8854 step = "Insert public key into VM user={} ssh_key={}".format(
8855 user, pub_key
8856 )
8857 else:
8858 # self.logger.debug("no need to get ssh key")
8859 step = "Waiting to VM being up and getting IP address"
8860 self.logger.debug(logging_text + step)
8861
8862 # n2vc_redesign STEP 5.1
8863 # wait for RO (ip-address) Insert pub_key into VM
8864 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008865 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008866 if vnfr_id:
8867 if kdu_name:
8868 rw_mgmt_ip = await self.wait_kdu_up(
8869 logging_text, nsr_id, vnfr_id, kdu_name
8870 )
8871 else:
8872 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8873 logging_text,
8874 nsr_id,
8875 vnfr_id,
8876 vdu_id,
8877 vdu_index,
8878 user=user,
8879 pub_key=pub_key,
8880 )
8881 else:
8882 rw_mgmt_ip = None # This is for a NS configuration
8883
8884 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8885
8886 # store rw_mgmt_ip in deploy params for later replacement
8887 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8888
8889 # Day1 operations.
8890 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008891 runDay1 = deploy_params.get("run-day1", False)
8892 self.logger.debug(
8893 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8894 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008895 if runDay1:
8896 # n2vc_redesign STEP 6 Execute initial config primitive
8897 step = "execute initial config primitive"
8898
8899 # wait for dependent primitives execution (NS -> VNF -> VDU)
8900 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008901 await self._wait_dependent_n2vc(
8902 nsr_id, vca_deployed_list, vca_index
8903 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008904
8905 # stage, in function of element type: vdu, kdu, vnf or ns
8906 my_vca = vca_deployed_list[vca_index]
8907 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8908 # VDU or KDU
8909 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8910 elif my_vca.get("member-vnf-index"):
8911 # VNF
8912 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8913 else:
8914 # NS
8915 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8916
8917 self._write_configuration_status(
8918 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8919 )
8920
8921 self._write_op_status(op_id=nslcmop_id, stage=stage)
8922
8923 check_if_terminated_needed = True
8924 for initial_config_primitive in initial_config_primitive_list:
8925 # adding information on the vca_deployed if it is a NS execution environment
8926 if not vca_deployed["member-vnf-index"]:
8927 deploy_params["ns_config_info"] = json.dumps(
8928 self._get_ns_config_info(nsr_id)
8929 )
8930 # TODO check if already done
8931 primitive_params_ = self._map_primitive_params(
8932 initial_config_primitive, {}, deploy_params
8933 )
8934
8935 step = "execute primitive '{}' params '{}'".format(
8936 initial_config_primitive["name"], primitive_params_
8937 )
8938 self.logger.debug(logging_text + step)
8939 await self.vca_map[vca_type].exec_primitive(
8940 ee_id=ee_id,
8941 primitive_name=initial_config_primitive["name"],
8942 params_dict=primitive_params_,
8943 db_dict=db_dict,
8944 vca_id=vca_id,
8945 vca_type=vca_type,
8946 )
8947 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8948 if check_if_terminated_needed:
8949 if config_descriptor.get("terminate-config-primitive"):
8950 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008951 "nsrs",
8952 nsr_id,
8953 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008954 )
8955 check_if_terminated_needed = False
8956
8957 # TODO register in database that primitive is done
8958
8959 # STEP 7 Configure metrics
8960 # Not sure if this need to be done when healing
8961 """
8962 if vca_type == "helm" or vca_type == "helm-v3":
8963 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8964 ee_id=ee_id,
8965 artifact_path=artifact_path,
8966 ee_config_descriptor=ee_config_descriptor,
8967 vnfr_id=vnfr_id,
8968 nsr_id=nsr_id,
8969 target_ip=rw_mgmt_ip,
8970 )
8971 if prometheus_jobs:
8972 self.update_db_2(
8973 "nsrs",
8974 nsr_id,
8975 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8976 )
8977
8978 for job in prometheus_jobs:
8979 self.db.set_one(
8980 "prometheus_jobs",
8981 {"job_name": job["job_name"]},
8982 job,
8983 upsert=True,
8984 fail_on_empty=False,
8985 )
8986
8987 """
8988 step = "instantiated at VCA"
8989 self.logger.debug(logging_text + step)
8990
8991 self._write_configuration_status(
8992 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8993 )
8994
8995 except Exception as e: # TODO not use Exception but N2VC exception
8996 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8997 if not isinstance(
8998 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8999 ):
9000 self.logger.error(
9001 "Exception while {} : {}".format(step, e), exc_info=True
9002 )
9003 self._write_configuration_status(
9004 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
9005 )
9006 raise LcmException("{} {}".format(step, e)) from e
9007
9008 async def _wait_heal_ro(
9009 self,
9010 nsr_id,
9011 timeout=600,
9012 ):
9013 start_time = time()
9014 while time() <= start_time + timeout:
9015 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009016 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9017 "operational-status"
9018 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009019 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9020 if operational_status_ro != "healing":
9021 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009022 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009023 else: # timeout_ns_deploy
9024 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309025
9026 async def vertical_scale(self, nsr_id, nslcmop_id):
9027 """
9028 Vertical Scale the VDUs in a NS
9029
9030 :param: nsr_id: NS Instance ID
9031 :param: nslcmop_id: nslcmop ID of migrate
9032
9033 """
govindarajul4ff4b512022-05-02 20:02:41 +05309034 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05309035 self.logger.info(logging_text + "Enter")
9036 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05309037 # get all needed from database
9038 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05309039 db_nsr_update = {}
9040 target = {}
9041 exc = None
9042 # in case of error, indicates what part of scale was failed to put nsr at error status
9043 start_deploy = time()
9044
9045 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05309046 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9047 operationParams = db_nslcmop.get("operationParams")
9048 vertical_scale_data = operationParams["verticalScaleVnf"]
9049 vnfd_id = vertical_scale_data["vnfdId"]
9050 count_index = vertical_scale_data["countIndex"]
9051 vdu_id_ref = vertical_scale_data["vduId"]
9052 vnfr_id = vertical_scale_data["vnfInstanceId"]
9053 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9054 db_flavor = db_nsr.get("flavor")
9055 db_flavor_index = str(len(db_flavor))
9056
9057 def set_flavor_refrence_to_vdur(diff=0):
9058 """
9059 Utility function to add and remove the
9060 ref to new ns-flavor-id to vdurs
9061 :param: diff: default 0
9062 """
9063 q_filter = {}
9064 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9065 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9066 if (
9067 vdur.get("count-index") == count_index
9068 and vdur.get("vdu-id-ref") == vdu_id_ref
9069 ):
9070 filter_text = {
9071 "_id": vnfr_id,
9072 "vdur.count-index": count_index,
9073 "vdur.vdu-id-ref": vdu_id_ref,
9074 }
9075 q_filter.update(filter_text)
9076 db_update = {}
9077 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9078 int(db_flavor_index) - diff
9079 )
9080 self.db.set_one(
9081 "vnfrs",
9082 q_filter=q_filter,
9083 update_dict=db_update,
9084 fail_on_empty=True,
9085 )
9086
govindarajul4ff4b512022-05-02 20:02:41 +05309087 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309088 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009089 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309090
9091 self._write_ns_status(
9092 nsr_id=nsr_id,
9093 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309094 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009095 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309096 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309097 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009098 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309099 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009100 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309101 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9102 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9103 virtual_compute = vnfd["virtual-compute-desc"][0]
9104 virtual_memory = round(
9105 float(virtual_compute["virtual-memory"]["size"]) * 1024
9106 )
9107 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9108 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009109 flavor_dict_update = {
9110 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309111 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009112 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309113 "storage-gb": str(virtual_storage),
9114 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009115 }
9116 db_flavor.append(flavor_dict_update)
9117 db_update = {}
9118 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309119 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009120 "_id": nsr_id,
9121 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309122 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009123 self.db.set_one(
9124 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309125 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009126 update_dict=db_update,
9127 fail_on_empty=True,
9128 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309129 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309130 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309131 new_operationParams = {
9132 "lcmOperationType": "verticalscale",
9133 "verticalScale": "CHANGE_VNFFLAVOR",
9134 "nsInstanceId": nsr_id,
9135 "changeVnfFlavorData": {
9136 "vnfInstanceId": vnfr_id,
9137 "additionalParams": {
9138 "vduid": vdu_id_ref,
9139 "vduCountIndex": count_index,
9140 "virtualMemory": virtual_memory,
9141 "numVirtualCpu": int(virtual_cpu),
9142 "sizeOfStorage": int(virtual_storage),
9143 },
9144 },
9145 }
9146 target.update(new_operationParams)
9147
9148 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9149 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9150 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309151 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309152 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309153 action_id = desc["action_id"]
9154 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009155 nsr_id,
9156 action_id,
9157 nslcmop_id,
9158 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009159 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009160 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309161 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009162 except (
9163 NgRoException,
9164 ROclient.ROClientException,
9165 DbException,
9166 LcmException,
9167 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309168 self.logger.error("Exit Exception {}".format(e))
9169 exc = e
9170 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309171 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309172 exc = "Operation was cancelled"
9173 except Exception as e:
9174 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009175 self.logger.critical(
9176 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9177 )
govindarajul4ff4b512022-05-02 20:02:41 +05309178 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309179 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009180 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309181 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009182 )
9183 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309184 "nsrs",
9185 {"_id": nsr_id},
9186 None,
9187 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009188 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309189 set_flavor_refrence_to_vdur(diff=1)
9190 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9191 else:
9192 return "COMPLETED", "Done"