blob: 5d3c91166695b299625c69015f0f9096874abd85 [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"][
1140 "instance_name"
1141 ] = vdu_instantiation_params.get("instance_name")
tierno2357f4e2020-10-19 16:38:59 +00001142 vdur_list.append(vdur)
1143 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001144 target["vnf"].append(target_vnf)
1145
garciadeblas07f4e4c2022-06-09 09:42:58 +02001146 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001147 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001148 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001149 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001150 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001151 nsr_id,
1152 action_id,
1153 nslcmop_id,
1154 start_deploy,
1155 timeout_ns_deploy,
1156 stage,
1157 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001158 )
tierno69f0d382020-05-07 13:08:09 +00001159
1160 # Updating NSR
1161 db_nsr_update = {
1162 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001163 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001164 }
1165 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1166 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1167 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001168 self.logger.debug(
1169 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1170 )
tierno69f0d382020-05-07 13:08:09 +00001171 return
1172
garciadeblas5697b8b2021-03-24 09:17:02 +01001173 async def _wait_ng_ro(
1174 self,
1175 nsr_id,
1176 action_id,
1177 nslcmop_id=None,
1178 start_time=None,
1179 timeout=600,
1180 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001181 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001182 ):
tierno69f0d382020-05-07 13:08:09 +00001183 detailed_status_old = None
1184 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001185 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001186 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001187 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001188 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001189 if desc_status["status"] == "FAILED":
1190 raise NgRoException(desc_status["details"])
1191 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001192 if stage:
1193 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001194 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001195 if stage:
1196 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001197 break
1198 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001199 assert False, "ROclient.check_ns_status returns unknown {}".format(
1200 desc_status["status"]
1201 )
tierno2357f4e2020-10-19 16:38:59 +00001202 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001203 detailed_status_old = stage[2]
1204 db_nsr_update["detailed-status"] = " ".join(stage)
1205 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1206 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001207 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001208 else: # timeout_ns_deploy
1209 raise NgRoException("Timeout waiting ns to deploy")
1210
garciadeblas5697b8b2021-03-24 09:17:02 +01001211 async def _terminate_ng_ro(
1212 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1213 ):
tierno69f0d382020-05-07 13:08:09 +00001214 db_nsr_update = {}
1215 failed_detail = []
1216 action_id = None
1217 start_deploy = time()
1218 try:
1219 target = {
1220 "ns": {"vld": []},
1221 "vnf": [],
1222 "image": [],
1223 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001224 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001225 }
1226 desc = await self.RO.deploy(nsr_id, target)
1227 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001228 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001229 self.logger.debug(
1230 logging_text
1231 + "ns terminate action at RO. action_id={}".format(action_id)
1232 )
tierno69f0d382020-05-07 13:08:09 +00001233
1234 # wait until done
1235 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001236 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001237 nsr_id,
1238 action_id,
1239 nslcmop_id,
1240 start_deploy,
1241 delete_timeout,
1242 stage,
1243 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001244 )
tierno69f0d382020-05-07 13:08:09 +00001245 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1246 # delete all nsr
1247 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001248 except NgRoException as e:
1249 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001250 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1251 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001252 self.logger.debug(
1253 logging_text + "RO_action_id={} already deleted".format(action_id)
1254 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001255 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001256 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001257 self.logger.debug(
1258 logging_text
1259 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1260 )
tierno69f0d382020-05-07 13:08:09 +00001261 else:
1262 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001263 self.logger.error(
1264 logging_text
1265 + "RO_action_id={} delete error: {}".format(action_id, e)
1266 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001267 except Exception as e:
1268 failed_detail.append("delete error: {}".format(e))
1269 self.logger.error(
1270 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1271 )
tierno69f0d382020-05-07 13:08:09 +00001272
1273 if failed_detail:
1274 stage[2] = "Error deleting from VIM"
1275 else:
1276 stage[2] = "Deleted from VIM"
1277 db_nsr_update["detailed-status"] = " ".join(stage)
1278 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1279 self._write_op_status(nslcmop_id, stage)
1280
1281 if failed_detail:
1282 raise LcmException("; ".join(failed_detail))
1283 return
1284
garciadeblas5697b8b2021-03-24 09:17:02 +01001285 async def instantiate_RO(
1286 self,
1287 logging_text,
1288 nsr_id,
1289 nsd,
1290 db_nsr,
1291 db_nslcmop,
1292 db_vnfrs,
1293 db_vnfds,
1294 n2vc_key_list,
1295 stage,
1296 ):
tiernoe95ed362020-04-23 08:24:57 +00001297 """
1298 Instantiate at RO
1299 :param logging_text: preffix text to use at logging
1300 :param nsr_id: nsr identity
1301 :param nsd: database content of ns descriptor
1302 :param db_nsr: database content of ns record
1303 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1304 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001305 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001306 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1307 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1308 :return: None or exception
1309 """
tiernoe876f672020-02-13 14:34:48 +00001310 try:
tiernoe876f672020-02-13 14:34:48 +00001311 start_deploy = time()
1312 ns_params = db_nslcmop.get("operationParams")
1313 if ns_params and ns_params.get("timeout_ns_deploy"):
1314 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1315 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001316 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001317
tiernoe876f672020-02-13 14:34:48 +00001318 # Check for and optionally request placement optimization. Database will be updated if placement activated
1319 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001320 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1321 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1322 for vnfr in db_vnfrs.values():
1323 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1324 break
1325 else:
1326 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001327
garciadeblas5697b8b2021-03-24 09:17:02 +01001328 return await self._instantiate_ng_ro(
1329 logging_text,
1330 nsr_id,
1331 nsd,
1332 db_nsr,
1333 db_nslcmop,
1334 db_vnfrs,
1335 db_vnfds,
1336 n2vc_key_list,
1337 stage,
1338 start_deploy,
1339 timeout_ns_deploy,
1340 )
tierno2357f4e2020-10-19 16:38:59 +00001341 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001342 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001343 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001344 self.logger.error(
1345 "Error deploying at VIM {}".format(e),
1346 exc_info=not isinstance(
1347 e,
1348 (
1349 ROclient.ROClientException,
1350 LcmException,
1351 DbException,
1352 NgRoException,
1353 ),
1354 ),
1355 )
tiernoe876f672020-02-13 14:34:48 +00001356 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001357
tierno7ecbc342020-09-21 14:05:39 +00001358 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1359 """
1360 Wait for kdu to be up, get ip address
1361 :param logging_text: prefix use for logging
1362 :param nsr_id:
1363 :param vnfr_id:
1364 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001365 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001366 """
1367
1368 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1369 nb_tries = 0
1370
1371 while nb_tries < 360:
1372 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001373 kdur = next(
1374 (
1375 x
1376 for x in get_iterable(db_vnfr, "kdur")
1377 if x.get("kdu-name") == kdu_name
1378 ),
1379 None,
1380 )
tierno7ecbc342020-09-21 14:05:39 +00001381 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001382 raise LcmException(
1383 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1384 )
tierno7ecbc342020-09-21 14:05:39 +00001385 if kdur.get("status"):
1386 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001387 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001388 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001389 raise LcmException(
1390 "target KDU={} is in error state".format(kdu_name)
1391 )
tierno7ecbc342020-09-21 14:05:39 +00001392
Gabriel Cubae7898982023-05-11 01:57:21 -05001393 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001394 nb_tries += 1
1395 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1396
garciadeblas5697b8b2021-03-24 09:17:02 +01001397 async def wait_vm_up_insert_key_ro(
1398 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1399 ):
tiernoa5088192019-11-26 16:12:53 +00001400 """
1401 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1402 :param logging_text: prefix use for logging
1403 :param nsr_id:
1404 :param vnfr_id:
1405 :param vdu_id:
1406 :param vdu_index:
1407 :param pub_key: public ssh key to inject, None to skip
1408 :param user: user to apply the public ssh key
1409 :return: IP address
1410 """
quilesj7e13aeb2019-10-08 13:34:55 +02001411
tierno2357f4e2020-10-19 16:38:59 +00001412 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001413 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001414 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001415 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001416
tiernod8323042019-08-09 11:32:23 +00001417 while True:
quilesj3149f262019-12-03 10:58:10 +00001418 ro_retries += 1
1419 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001420 raise LcmException(
1421 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1422 )
quilesj3149f262019-12-03 10:58:10 +00001423
Gabriel Cubae7898982023-05-11 01:57:21 -05001424 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001425
1426 # get ip address
tiernod8323042019-08-09 11:32:23 +00001427 if not target_vdu_id:
1428 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001429
1430 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001431 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001432 raise LcmException(
1433 "Cannot inject ssh-key because target VNF is in error state"
1434 )
tiernod8323042019-08-09 11:32:23 +00001435 ip_address = db_vnfr.get("ip-address")
1436 if not ip_address:
1437 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001438 vdur = next(
1439 (
1440 x
1441 for x in get_iterable(db_vnfr, "vdur")
1442 if x.get("ip-address") == ip_address
1443 ),
1444 None,
1445 )
quilesj3149f262019-12-03 10:58:10 +00001446 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001447 vdur = next(
1448 (
1449 x
1450 for x in get_iterable(db_vnfr, "vdur")
1451 if x.get("vdu-id-ref") == vdu_id
1452 and x.get("count-index") == vdu_index
1453 ),
1454 None,
1455 )
quilesj3149f262019-12-03 10:58:10 +00001456
garciadeblas5697b8b2021-03-24 09:17:02 +01001457 if (
1458 not vdur and len(db_vnfr.get("vdur", ())) == 1
1459 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001460 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001461 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001462 raise LcmException(
1463 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1464 vnfr_id, vdu_id, vdu_index
1465 )
1466 )
tierno2357f4e2020-10-19 16:38:59 +00001467 # New generation RO stores information at "vim_info"
1468 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001469 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001470 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001471 target_vim = next(
1472 t for t in vdur["vim_info"]
1473 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001474 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001475 if (
1476 vdur.get("pdu-type")
1477 or vdur.get("status") == "ACTIVE"
1478 or ng_ro_status == "ACTIVE"
1479 ):
quilesj3149f262019-12-03 10:58:10 +00001480 ip_address = vdur.get("ip-address")
1481 if not ip_address:
1482 continue
1483 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001484 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001485 raise LcmException(
1486 "Cannot inject ssh-key because target VM is in error state"
1487 )
quilesj3149f262019-12-03 10:58:10 +00001488
tiernod8323042019-08-09 11:32:23 +00001489 if not target_vdu_id:
1490 continue
tiernod8323042019-08-09 11:32:23 +00001491
quilesj7e13aeb2019-10-08 13:34:55 +02001492 # inject public key into machine
1493 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001494 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001495 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001496 if vdur.get("pdu-type"):
1497 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1498 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001499 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001500 target = {
1501 "action": {
1502 "action": "inject_ssh_key",
1503 "key": pub_key,
1504 "user": user,
1505 },
1506 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1507 }
1508 desc = await self.RO.deploy(nsr_id, target)
1509 action_id = desc["action_id"]
1510 await self._wait_ng_ro(
1511 nsr_id, action_id, timeout=600, operation="instantiation"
1512 )
1513 break
tierno69f0d382020-05-07 13:08:09 +00001514 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001515 raise LcmException(
1516 "Reaching max tries injecting key. Error: {}".format(e)
1517 )
quilesj7e13aeb2019-10-08 13:34:55 +02001518 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001519 break
1520
1521 return ip_address
1522
tierno5ee02052019-12-05 19:55:02 +00001523 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1524 """
1525 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1526 """
1527 my_vca = vca_deployed_list[vca_index]
1528 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001529 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001530 return
1531 timeout = 300
1532 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001533 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1534 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1535 configuration_status_list = db_nsr["configurationStatus"]
1536 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001537 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001538 # myself
tierno5ee02052019-12-05 19:55:02 +00001539 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001540 if not my_vca.get("member-vnf-index") or (
1541 vca_deployed.get("member-vnf-index")
1542 == my_vca.get("member-vnf-index")
1543 ):
quilesj3655ae02019-12-12 16:08:35 +00001544 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001545 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001546 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001547 elif internal_status == "BROKEN":
1548 raise LcmException(
1549 "Configuration aborted because dependent charm/s has failed"
1550 )
quilesj3655ae02019-12-12 16:08:35 +00001551 else:
1552 break
tierno5ee02052019-12-05 19:55:02 +00001553 else:
quilesj3655ae02019-12-12 16:08:35 +00001554 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001555 return
1556 await asyncio.sleep(10)
1557 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001558
1559 raise LcmException("Configuration aborted because dependent charm/s timeout")
1560
David Garciac1fe90a2021-03-31 19:12:02 +02001561 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001562 vca_id = None
1563 if db_vnfr:
1564 vca_id = deep_get(db_vnfr, ("vca-id",))
1565 elif db_nsr:
1566 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1567 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1568 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001569
garciadeblas5697b8b2021-03-24 09:17:02 +01001570 async def instantiate_N2VC(
1571 self,
1572 logging_text,
1573 vca_index,
1574 nsi_id,
1575 db_nsr,
1576 db_vnfr,
1577 vdu_id,
1578 kdu_name,
1579 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001580 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001581 config_descriptor,
1582 deploy_params,
1583 base_folder,
1584 nslcmop_id,
1585 stage,
1586 vca_type,
1587 vca_name,
1588 ee_config_descriptor,
1589 ):
tiernod8323042019-08-09 11:32:23 +00001590 nsr_id = db_nsr["_id"]
1591 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001592 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001593 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001594 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001595 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001596 "collection": "nsrs",
1597 "filter": {"_id": nsr_id},
1598 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001599 }
tiernod8323042019-08-09 11:32:23 +00001600 step = ""
1601 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001602 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001603 element_under_configuration = nsr_id
1604
tiernod8323042019-08-09 11:32:23 +00001605 vnfr_id = None
1606 if db_vnfr:
1607 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001608 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001609
garciadeblas5697b8b2021-03-24 09:17:02 +01001610 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001611
aktas98488ed2021-07-29 17:42:49 +03001612 if vca_type == "native_charm":
1613 index_number = 0
1614 else:
1615 index_number = vdu_index or 0
1616
tiernod8323042019-08-09 11:32:23 +00001617 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001618 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001619 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001620 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001621 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001622 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001623 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001624 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001625 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001626 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001627 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001628 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001629 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001630 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001631
1632 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001633 if base_folder["pkg-dir"]:
1634 artifact_path = "{}/{}/{}/{}".format(
1635 base_folder["folder"],
1636 base_folder["pkg-dir"],
1637 "charms"
aticig15db6142022-01-24 12:51:26 +03001638 if vca_type
1639 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001640 else "helm-charts",
1641 vca_name,
1642 )
1643 else:
1644 artifact_path = "{}/Scripts/{}/{}/".format(
1645 base_folder["folder"],
1646 "charms"
aticig15db6142022-01-24 12:51:26 +03001647 if vca_type
1648 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001649 else "helm-charts",
1650 vca_name,
1651 )
bravof922c4172020-11-24 21:21:43 -03001652
1653 self.logger.debug("Artifact path > {}".format(artifact_path))
1654
tiernoa278b842020-07-08 15:33:55 +00001655 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001656 initial_config_primitive_list = config_descriptor.get(
1657 "initial-config-primitive"
1658 )
tiernoa278b842020-07-08 15:33:55 +00001659
garciadeblas5697b8b2021-03-24 09:17:02 +01001660 self.logger.debug(
1661 "Initial config primitive list > {}".format(
1662 initial_config_primitive_list
1663 )
1664 )
bravof922c4172020-11-24 21:21:43 -03001665
tiernoa278b842020-07-08 15:33:55 +00001666 # add config if not present for NS charm
1667 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001668 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001669 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1670 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1671 )
tiernod8323042019-08-09 11:32:23 +00001672
garciadeblas5697b8b2021-03-24 09:17:02 +01001673 self.logger.debug(
1674 "Initial config primitive list #2 > {}".format(
1675 initial_config_primitive_list
1676 )
1677 )
tierno588547c2020-07-01 15:30:20 +00001678 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001679 # find old ee_id if exists
1680 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001681
David Garciac1fe90a2021-03-31 19:12:02 +02001682 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001683 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001684 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001685 self._write_configuration_status(
1686 nsr_id=nsr_id,
1687 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001688 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001689 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001690 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001691 )
tiernod8323042019-08-09 11:32:23 +00001692
tierno588547c2020-07-01 15:30:20 +00001693 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001694 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001695
1696 ee_id = None
1697 credentials = None
1698 if vca_type == "k8s_proxy_charm":
1699 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001700 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001701 namespace=namespace,
1702 artifact_path=artifact_path,
1703 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001704 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001705 )
Luis Vegae11384e2023-10-10 22:36:33 +00001706 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001707 ee_id, credentials = await self.vca_map[
1708 vca_type
1709 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001710 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001711 reuse_ee_id=ee_id,
1712 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001713 config=osm_config,
1714 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001715 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001716 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001717 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001718 else:
1719 ee_id, credentials = await self.vca_map[
1720 vca_type
1721 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001722 namespace=namespace,
1723 reuse_ee_id=ee_id,
1724 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001725 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001726 )
quilesj3655ae02019-12-12 16:08:35 +00001727
tierno588547c2020-07-01 15:30:20 +00001728 elif vca_type == "native_charm":
1729 step = "Waiting to VM being up and getting IP address"
1730 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001731 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1732 logging_text,
1733 nsr_id,
1734 vnfr_id,
1735 vdu_id,
1736 vdu_index,
1737 user=None,
1738 pub_key=None,
1739 )
tierno588547c2020-07-01 15:30:20 +00001740 credentials = {"hostname": rw_mgmt_ip}
1741 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001742 username = deep_get(
1743 config_descriptor, ("config-access", "ssh-access", "default-user")
1744 )
tierno588547c2020-07-01 15:30:20 +00001745 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1746 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001747 if not username and initial_config_primitive_list:
1748 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001749 for param in config_primitive.get("parameter", ()):
1750 if param["name"] == "ssh-username":
1751 username = param["value"]
1752 break
1753 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001754 raise LcmException(
1755 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1756 "'config-access.ssh-access.default-user'"
1757 )
tierno588547c2020-07-01 15:30:20 +00001758 credentials["username"] = username
1759 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001760
tierno588547c2020-07-01 15:30:20 +00001761 self._write_configuration_status(
1762 nsr_id=nsr_id,
1763 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001764 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001765 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001766 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001767 )
quilesj3655ae02019-12-12 16:08:35 +00001768
tierno588547c2020-07-01 15:30:20 +00001769 step = "register execution environment {}".format(credentials)
1770 self.logger.debug(logging_text + step)
1771 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001772 credentials=credentials,
1773 namespace=namespace,
1774 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001775 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001776 )
tierno3bedc9b2019-11-27 15:46:57 +00001777
tierno588547c2020-07-01 15:30:20 +00001778 # for compatibility with MON/POL modules, the need model and application name at database
1779 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001780 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001781 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1782 if len(ee_id_parts) >= 2:
1783 model_name = ee_id_parts[0]
1784 application_name = ee_id_parts[1]
1785 db_nsr_update[db_update_entry + "model"] = model_name
1786 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001787
1788 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001789 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001790
tiernoc231a872020-01-21 08:49:05 +00001791 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001792 nsr_id=nsr_id,
1793 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001794 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001795 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001796 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001797 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001798 )
1799
tierno3bedc9b2019-11-27 15:46:57 +00001800 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001801 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001802 config = None
tierno588547c2020-07-01 15:30:20 +00001803 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001804 config_primitive = next(
1805 (p for p in initial_config_primitive_list if p["name"] == "config"),
1806 None,
1807 )
tiernoa278b842020-07-08 15:33:55 +00001808 if config_primitive:
1809 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001810 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001811 )
tierno588547c2020-07-01 15:30:20 +00001812 num_units = 1
1813 if vca_type == "lxc_proxy_charm":
1814 if element_type == "NS":
1815 num_units = db_nsr.get("config-units") or 1
1816 elif element_type == "VNF":
1817 num_units = db_vnfr.get("config-units") or 1
1818 elif element_type == "VDU":
1819 for v in db_vnfr["vdur"]:
1820 if vdu_id == v["vdu-id-ref"]:
1821 num_units = v.get("config-units") or 1
1822 break
David Garciaaae391f2020-11-09 11:12:54 +01001823 if vca_type != "k8s_proxy_charm":
1824 await self.vca_map[vca_type].install_configuration_sw(
1825 ee_id=ee_id,
1826 artifact_path=artifact_path,
1827 db_dict=db_dict,
1828 config=config,
1829 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001830 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001831 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001832 )
quilesj7e13aeb2019-10-08 13:34:55 +02001833
quilesj63f90042020-01-17 09:53:55 +00001834 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001835 self.update_db_2(
1836 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1837 )
quilesj63f90042020-01-17 09:53:55 +00001838
1839 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001840 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001841 logging_text=logging_text,
1842 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001843 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001844 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001845 )
quilesj63f90042020-01-17 09:53:55 +00001846
Patricia Reinosob4312c02023-01-06 22:28:44 +00001847 if not is_relation_added:
1848 raise LcmException("Relations could not be added to VCA.")
1849
quilesj7e13aeb2019-10-08 13:34:55 +02001850 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001851 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001852 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001853 pub_key = None
1854 user = None
tierno588547c2020-07-01 15:30:20 +00001855 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001856 if deep_get(
1857 config_descriptor, ("config-access", "ssh-access", "required")
1858 ):
tierno588547c2020-07-01 15:30:20 +00001859 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001860 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001861 user = deep_get(
1862 config_descriptor,
1863 ("config-access", "ssh-access", "default-user"),
1864 )
tierno3bedc9b2019-11-27 15:46:57 +00001865 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001866 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001867 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001868 )
quilesj7e13aeb2019-10-08 13:34:55 +02001869
garciadeblas5697b8b2021-03-24 09:17:02 +01001870 step = "Insert public key into VM user={} ssh_key={}".format(
1871 user, pub_key
1872 )
tierno3bedc9b2019-11-27 15:46:57 +00001873 else:
tierno588547c2020-07-01 15:30:20 +00001874 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001875 step = "Waiting to VM being up and getting IP address"
1876 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001877
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001878 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1879 rw_mgmt_ip = None
1880
tierno3bedc9b2019-11-27 15:46:57 +00001881 # n2vc_redesign STEP 5.1
1882 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001883 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001884 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001885 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001886 logging_text, nsr_id, vnfr_id, kdu_name
1887 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001888 vnfd = self.db.get_one(
1889 "vnfds_revisions",
1890 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1891 )
1892 kdu = get_kdu(vnfd, kdu_name)
1893 kdu_services = [
1894 service["name"] for service in get_kdu_services(kdu)
1895 ]
1896 exposed_services = []
1897 for service in services:
1898 if any(s in service["name"] for s in kdu_services):
1899 exposed_services.append(service)
1900 await self.vca_map[vca_type].exec_primitive(
1901 ee_id=ee_id,
1902 primitive_name="config",
1903 params_dict={
1904 "osm-config": json.dumps(
1905 OsmConfigBuilder(
1906 k8s={"services": exposed_services}
1907 ).build()
1908 )
1909 },
1910 vca_id=vca_id,
1911 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001912
1913 # This verification is needed in order to avoid trying to add a public key
1914 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1915 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1916 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1917 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001918 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001919 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1920 logging_text,
1921 nsr_id,
1922 vnfr_id,
1923 vdu_id,
1924 vdu_index,
1925 user=user,
1926 pub_key=pub_key,
1927 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001928
garciadeblas5697b8b2021-03-24 09:17:02 +01001929 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001930
tiernoa5088192019-11-26 16:12:53 +00001931 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001932 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001933
1934 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001935 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001936
1937 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001938 if initial_config_primitive_list:
1939 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001940
1941 # stage, in function of element type: vdu, kdu, vnf or ns
1942 my_vca = vca_deployed_list[vca_index]
1943 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1944 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001945 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001946 elif my_vca.get("member-vnf-index"):
1947 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001948 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001949 else:
1950 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001951 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00001952
tiernoc231a872020-01-21 08:49:05 +00001953 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01001954 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00001955 )
1956
garciadeblas5697b8b2021-03-24 09:17:02 +01001957 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00001958
tiernoe876f672020-02-13 14:34:48 +00001959 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001960 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001961 # adding information on the vca_deployed if it is a NS execution environment
1962 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001963 deploy_params["ns_config_info"] = json.dumps(
1964 self._get_ns_config_info(nsr_id)
1965 )
tiernod8323042019-08-09 11:32:23 +00001966 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01001967 primitive_params_ = self._map_primitive_params(
1968 initial_config_primitive, {}, deploy_params
1969 )
tierno3bedc9b2019-11-27 15:46:57 +00001970
garciadeblas5697b8b2021-03-24 09:17:02 +01001971 step = "execute primitive '{}' params '{}'".format(
1972 initial_config_primitive["name"], primitive_params_
1973 )
tiernod8323042019-08-09 11:32:23 +00001974 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001975 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001976 ee_id=ee_id,
1977 primitive_name=initial_config_primitive["name"],
1978 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02001979 db_dict=db_dict,
1980 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001981 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02001982 )
tiernoe876f672020-02-13 14:34:48 +00001983 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1984 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01001985 if config_descriptor.get("terminate-config-primitive"):
1986 self.update_db_2(
1987 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
1988 )
tiernoe876f672020-02-13 14:34:48 +00001989 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001990
tiernod8323042019-08-09 11:32:23 +00001991 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001992
tiernob996d942020-07-03 14:52:28 +00001993 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00001994 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02001995 # TODO: review for those cases where the helm chart is a reference and
1996 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04001997 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00001998 ee_id=ee_id,
1999 artifact_path=artifact_path,
2000 ee_config_descriptor=ee_config_descriptor,
2001 vnfr_id=vnfr_id,
2002 nsr_id=nsr_id,
2003 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002004 element_type=element_type,
2005 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2006 vdu_id=vdu_id,
2007 vdu_index=vdu_index,
2008 kdu_name=kdu_name,
2009 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002010 )
2011 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002012 self.update_db_2(
2013 "nsrs",
2014 nsr_id,
2015 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2016 )
tiernob996d942020-07-03 14:52:28 +00002017
bravof73bac502021-05-11 07:38:47 -04002018 for job in prometheus_jobs:
2019 self.db.set_one(
2020 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002021 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002022 job,
2023 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002024 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002025 )
2026
quilesj7e13aeb2019-10-08 13:34:55 +02002027 step = "instantiated at VCA"
2028 self.logger.debug(logging_text + step)
2029
tiernoc231a872020-01-21 08:49:05 +00002030 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002031 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002032 )
2033
tiernod8323042019-08-09 11:32:23 +00002034 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002035 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002036 if not isinstance(
2037 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2038 ):
2039 self.logger.error(
2040 "Exception while {} : {}".format(step, e), exc_info=True
2041 )
tiernoc231a872020-01-21 08:49:05 +00002042 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002043 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002044 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002045 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002046
garciadeblas5697b8b2021-03-24 09:17:02 +01002047 def _write_ns_status(
2048 self,
2049 nsr_id: str,
2050 ns_state: str,
2051 current_operation: str,
2052 current_operation_id: str,
2053 error_description: str = None,
2054 error_detail: str = None,
2055 other_update: dict = None,
2056 ):
tiernoe876f672020-02-13 14:34:48 +00002057 """
2058 Update db_nsr fields.
2059 :param nsr_id:
2060 :param ns_state:
2061 :param current_operation:
2062 :param current_operation_id:
2063 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002064 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002065 :param other_update: Other required changes at database if provided, will be cleared
2066 :return:
2067 """
quilesj4cda56b2019-12-05 10:02:20 +00002068 try:
tiernoe876f672020-02-13 14:34:48 +00002069 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002070 db_dict[
2071 "_admin.nslcmop"
2072 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002073 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002074 db_dict["_admin.operation-type"] = (
2075 current_operation if current_operation != "IDLE" else None
2076 )
quilesj4cda56b2019-12-05 10:02:20 +00002077 db_dict["currentOperation"] = current_operation
2078 db_dict["currentOperationID"] = current_operation_id
2079 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002080 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002081
2082 if ns_state:
2083 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002084 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002085 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002086 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002087
garciadeblas5697b8b2021-03-24 09:17:02 +01002088 def _write_op_status(
2089 self,
2090 op_id: str,
2091 stage: list = None,
2092 error_message: str = None,
2093 queuePosition: int = 0,
2094 operation_state: str = None,
2095 other_update: dict = None,
2096 ):
quilesj3655ae02019-12-12 16:08:35 +00002097 try:
tiernoe876f672020-02-13 14:34:48 +00002098 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002099 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002100 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002101 db_dict["stage"] = stage[0]
2102 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002103 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002104 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002105
2106 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002107 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002108 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002109 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002110 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002111 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002112 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002113 self.logger.warn(
2114 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2115 )
quilesj3655ae02019-12-12 16:08:35 +00002116
tierno51183952020-04-03 15:48:18 +00002117 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002118 try:
tierno51183952020-04-03 15:48:18 +00002119 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002120 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002121 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002122 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002123 db_nsr_update = {
2124 "configurationStatus.{}.status".format(index): status
2125 for index, v in enumerate(config_status)
2126 if v
2127 }
quilesj3655ae02019-12-12 16:08:35 +00002128 # update status
tierno51183952020-04-03 15:48:18 +00002129 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002130
tiernoe876f672020-02-13 14:34:48 +00002131 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002132 self.logger.warn(
2133 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2134 )
quilesj3655ae02019-12-12 16:08:35 +00002135
garciadeblas5697b8b2021-03-24 09:17:02 +01002136 def _write_configuration_status(
2137 self,
2138 nsr_id: str,
2139 vca_index: int,
2140 status: str = None,
2141 element_under_configuration: str = None,
2142 element_type: str = None,
2143 other_update: dict = None,
2144 ):
quilesj3655ae02019-12-12 16:08:35 +00002145 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2146 # .format(vca_index, status))
2147
2148 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002149 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002150 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002151 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002152 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002153 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002154 db_dict[
2155 db_path + "elementUnderConfiguration"
2156 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002157 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002158 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002159 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002160 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002161 self.logger.warn(
2162 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2163 status, nsr_id, vca_index, e
2164 )
2165 )
quilesj4cda56b2019-12-05 10:02:20 +00002166
tierno38089af2020-04-16 07:56:58 +00002167 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2168 """
2169 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2170 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2171 Database is used because the result can be obtained from a different LCM worker in case of HA.
2172 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2173 :param db_nslcmop: database content of nslcmop
2174 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002175 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2176 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002177 """
tierno8790a3d2020-04-23 22:49:52 +00002178 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002179 nslcmop_id = db_nslcmop["_id"]
2180 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002181 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002182 self.logger.debug(
2183 logging_text + "Invoke and wait for placement optimization"
2184 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002185 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002186 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002187 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002188 pla_result = None
2189 while not pla_result and wait >= 0:
2190 await asyncio.sleep(db_poll_interval)
2191 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002192 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002193 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002194
2195 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002196 raise LcmException(
2197 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2198 )
magnussonle9198bb2020-01-21 13:00:51 +01002199
garciadeblas5697b8b2021-03-24 09:17:02 +01002200 for pla_vnf in pla_result["vnf"]:
2201 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2202 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002203 continue
tierno8790a3d2020-04-23 22:49:52 +00002204 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002205 self.db.set_one(
2206 "vnfrs",
2207 {"_id": vnfr["_id"]},
2208 {"vim-account-id": pla_vnf["vimAccountId"]},
2209 )
tierno38089af2020-04-16 07:56:58 +00002210 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002211 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002212 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002213
aguilard1ae3c562023-02-16 17:24:35 +00002214 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2215 alerts = []
2216 nsr_id = vnfr["nsr-id-ref"]
2217 df = vnfd.get("df", [{}])[0]
2218 # Checking for auto-healing configuration
2219 if "healing-aspect" in df:
2220 healing_aspects = df["healing-aspect"]
2221 for healing in healing_aspects:
2222 for healing_policy in healing.get("healing-policy", ()):
2223 vdu_id = healing_policy["vdu-id"]
2224 vdur = next(
2225 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2226 {},
2227 )
2228 if not vdur:
2229 continue
2230 metric_name = "vm_status"
2231 vdu_name = vdur.get("name")
2232 vnf_member_index = vnfr["member-vnf-index-ref"]
2233 uuid = str(uuid4())
2234 name = f"healing_{uuid}"
2235 action = healing_policy
2236 # action_on_recovery = healing.get("action-on-recovery")
2237 # cooldown_time = healing.get("cooldown-time")
2238 # day1 = healing.get("day1")
2239 alert = {
2240 "uuid": uuid,
2241 "name": name,
2242 "metric": metric_name,
2243 "tags": {
2244 "ns_id": nsr_id,
2245 "vnf_member_index": vnf_member_index,
2246 "vdu_name": vdu_name,
2247 },
2248 "alarm_status": "ok",
2249 "action_type": "healing",
2250 "action": action,
2251 }
2252 alerts.append(alert)
2253 return alerts
2254
2255 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2256 alerts = []
2257 nsr_id = vnfr["nsr-id-ref"]
2258 df = vnfd.get("df", [{}])[0]
2259 # Checking for auto-scaling configuration
2260 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002261 scaling_aspects = df["scaling-aspect"]
2262 all_vnfd_monitoring_params = {}
2263 for ivld in vnfd.get("int-virtual-link-desc", ()):
2264 for mp in ivld.get("monitoring-parameters", ()):
2265 all_vnfd_monitoring_params[mp.get("id")] = mp
2266 for vdu in vnfd.get("vdu", ()):
2267 for mp in vdu.get("monitoring-parameter", ()):
2268 all_vnfd_monitoring_params[mp.get("id")] = mp
2269 for df in vnfd.get("df", ()):
2270 for mp in df.get("monitoring-parameter", ()):
2271 all_vnfd_monitoring_params[mp.get("id")] = mp
2272 for scaling_aspect in scaling_aspects:
2273 scaling_group_name = scaling_aspect.get("name", "")
2274 # Get monitored VDUs
2275 all_monitored_vdus = set()
2276 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2277 "deltas", ()
2278 ):
2279 for vdu_delta in delta.get("vdu-delta", ()):
2280 all_monitored_vdus.add(vdu_delta.get("id"))
2281 monitored_vdurs = list(
2282 filter(
2283 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2284 vnfr["vdur"],
2285 )
2286 )
2287 if not monitored_vdurs:
2288 self.logger.error(
2289 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2290 )
2291 continue
2292 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2293 if scaling_policy["scaling-type"] != "automatic":
2294 continue
2295 threshold_time = scaling_policy.get("threshold-time", "1")
2296 cooldown_time = scaling_policy.get("cooldown-time", "0")
2297 for scaling_criteria in scaling_policy["scaling-criteria"]:
2298 monitoring_param_ref = scaling_criteria.get(
2299 "vnf-monitoring-param-ref"
2300 )
2301 vnf_monitoring_param = all_vnfd_monitoring_params[
2302 monitoring_param_ref
2303 ]
2304 for vdur in monitored_vdurs:
2305 vdu_id = vdur["vdu-id-ref"]
2306 metric_name = vnf_monitoring_param.get("performance-metric")
Rahul Kumar54671c52024-05-09 15:34:01 +05302307 if "exporters-endpoints" not in df:
2308 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002309 vnf_member_index = vnfr["member-vnf-index-ref"]
2310 scalein_threshold = scaling_criteria.get(
2311 "scale-in-threshold"
2312 )
2313 scaleout_threshold = scaling_criteria.get(
2314 "scale-out-threshold"
2315 )
2316 # Looking for min/max-number-of-instances
2317 instances_min_number = 1
2318 instances_max_number = 1
2319 vdu_profile = df["vdu-profile"]
2320 if vdu_profile:
2321 profile = next(
2322 item for item in vdu_profile if item["id"] == vdu_id
2323 )
2324 instances_min_number = profile.get(
2325 "min-number-of-instances", 1
2326 )
2327 instances_max_number = profile.get(
2328 "max-number-of-instances", 1
2329 )
2330
2331 if scalein_threshold:
2332 uuid = str(uuid4())
2333 name = f"scalein_{uuid}"
2334 operation = scaling_criteria[
2335 "scale-in-relational-operation"
2336 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002337 rel_operator = self.rel_operation_types.get(
2338 operation, "<="
2339 )
aguilard1ae3c562023-02-16 17:24:35 +00002340 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2341 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302342 if (
2343 "exporters-endpoints" in df
2344 and metric_name.startswith("kpi_")
2345 ):
2346 new_metric_name = (
2347 f'osm_{metric_name.replace("kpi_", "").strip()}'
2348 )
2349 metric_port = df["exporters-endpoints"].get(
2350 "metric-port", 9100
2351 )
2352 vdu_ip = vdur["ip-address"]
2353 ip_port = str(vdu_ip) + ":" + str(metric_port)
2354 metric_selector = (
2355 f'{new_metric_name}{{instance="{ip_port}"}}'
2356 )
2357 expression = f"({metric_selector} {rel_operator} {scalein_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002358 labels = {
2359 "ns_id": nsr_id,
2360 "vnf_member_index": vnf_member_index,
2361 "vdu_id": vdu_id,
2362 }
2363 prom_cfg = {
2364 "alert": name,
2365 "expr": expression,
2366 "for": str(threshold_time) + "m",
2367 "labels": labels,
2368 }
2369 action = scaling_policy
2370 action = {
2371 "scaling-group": scaling_group_name,
2372 "cooldown-time": cooldown_time,
2373 }
2374 alert = {
2375 "uuid": uuid,
2376 "name": name,
2377 "metric": metric_name,
2378 "tags": {
2379 "ns_id": nsr_id,
2380 "vnf_member_index": vnf_member_index,
2381 "vdu_id": vdu_id,
2382 },
2383 "alarm_status": "ok",
2384 "action_type": "scale_in",
2385 "action": action,
2386 "prometheus_config": prom_cfg,
2387 }
2388 alerts.append(alert)
2389
2390 if scaleout_threshold:
2391 uuid = str(uuid4())
2392 name = f"scaleout_{uuid}"
2393 operation = scaling_criteria[
2394 "scale-out-relational-operation"
2395 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002396 rel_operator = self.rel_operation_types.get(
2397 operation, "<="
2398 )
aguilard1ae3c562023-02-16 17:24:35 +00002399 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2400 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302401 if (
2402 "exporters-endpoints" in df
2403 and metric_name.startswith("kpi_")
2404 ):
2405 new_metric_name = (
2406 f'osm_{metric_name.replace("kpi_", "").strip()}'
2407 )
2408 metric_port = df["exporters-endpoints"].get(
2409 "metric-port", 9100
2410 )
2411 vdu_ip = vdur["ip-address"]
2412 ip_port = str(vdu_ip) + ":" + str(metric_port)
2413 metric_selector = (
2414 f'{new_metric_name}{{instance="{ip_port}"}}'
2415 )
2416 expression = f"({metric_selector} {rel_operator} {scaleout_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002417 labels = {
2418 "ns_id": nsr_id,
2419 "vnf_member_index": vnf_member_index,
2420 "vdu_id": vdu_id,
2421 }
2422 prom_cfg = {
2423 "alert": name,
2424 "expr": expression,
2425 "for": str(threshold_time) + "m",
2426 "labels": labels,
2427 }
2428 action = scaling_policy
2429 action = {
2430 "scaling-group": scaling_group_name,
2431 "cooldown-time": cooldown_time,
2432 }
2433 alert = {
2434 "uuid": uuid,
2435 "name": name,
2436 "metric": metric_name,
2437 "tags": {
2438 "ns_id": nsr_id,
2439 "vnf_member_index": vnf_member_index,
2440 "vdu_id": vdu_id,
2441 },
2442 "alarm_status": "ok",
2443 "action_type": "scale_out",
2444 "action": action,
2445 "prometheus_config": prom_cfg,
2446 }
2447 alerts.append(alert)
2448 return alerts
2449
garciadeblas9148fa82023-05-30 12:51:14 +02002450 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2451 alerts = []
2452 nsr_id = vnfr["nsr-id-ref"]
2453 vnf_member_index = vnfr["member-vnf-index-ref"]
2454
2455 # Checking for VNF alarm configuration
2456 for vdur in vnfr["vdur"]:
2457 vdu_id = vdur["vdu-id-ref"]
2458 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2459 if "alarm" in vdu:
2460 # Get VDU monitoring params, since alerts are based on them
2461 vdu_monitoring_params = {}
2462 for mp in vdu.get("monitoring-parameter", []):
2463 vdu_monitoring_params[mp.get("id")] = mp
2464 if not vdu_monitoring_params:
2465 self.logger.error(
2466 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2467 )
2468 continue
2469 # Get alarms in the VDU
2470 alarm_descriptors = vdu["alarm"]
2471 # Create VDU alarms for each alarm in the VDU
2472 for alarm_descriptor in alarm_descriptors:
2473 # Check that the VDU alarm refers to a proper monitoring param
2474 alarm_monitoring_param = alarm_descriptor.get(
2475 "vnf-monitoring-param-ref", ""
2476 )
2477 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2478 alarm_monitoring_param, {}
2479 )
2480 if not vdu_specific_monitoring_param:
2481 self.logger.error(
2482 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2483 )
2484 continue
2485 metric_name = vdu_specific_monitoring_param.get(
2486 "performance-metric"
2487 )
2488 if not metric_name:
2489 self.logger.error(
2490 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2491 )
2492 continue
2493 # Set params of the alarm to be created in Prometheus
2494 metric_name = f"osm_{metric_name}"
2495 metric_threshold = alarm_descriptor.get("value")
2496 uuid = str(uuid4())
2497 alert_name = f"vdu_alarm_{uuid}"
2498 operation = alarm_descriptor["operation"]
2499 rel_operator = self.rel_operation_types.get(operation, "<=")
2500 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 +00002501 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002502 labels = {
2503 "ns_id": nsr_id,
2504 "vnf_member_index": vnf_member_index,
2505 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002506 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002507 }
2508 prom_cfg = {
2509 "alert": alert_name,
2510 "expr": expression,
2511 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2512 "labels": labels,
2513 }
2514 alarm_action = dict()
2515 for action_type in ["ok", "insufficient-data", "alarm"]:
2516 if (
2517 "actions" in alarm_descriptor
2518 and action_type in alarm_descriptor["actions"]
2519 ):
aguilardeb076722023-05-31 09:45:00 +00002520 alarm_action[action_type] = alarm_descriptor["actions"][
2521 action_type
2522 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002523 alert = {
2524 "uuid": uuid,
2525 "name": alert_name,
2526 "metric": metric_name,
2527 "tags": {
2528 "ns_id": nsr_id,
2529 "vnf_member_index": vnf_member_index,
2530 "vdu_id": vdu_id,
2531 },
2532 "alarm_status": "ok",
2533 "action_type": "vdu_alarm",
2534 "action": alarm_action,
2535 "prometheus_config": prom_cfg,
2536 }
2537 alerts.append(alert)
2538 return alerts
2539
magnussonle9198bb2020-01-21 13:00:51 +01002540 def update_nsrs_with_pla_result(self, params):
2541 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002542 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2543 self.update_db_2(
2544 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2545 )
magnussonle9198bb2020-01-21 13:00:51 +01002546 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002547 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002548
tierno59d22d22018-09-25 18:10:19 +02002549 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002550 """
2551
2552 :param nsr_id: ns instance to deploy
2553 :param nslcmop_id: operation to run
2554 :return:
2555 """
kuused124bfe2019-06-18 12:09:24 +02002556
2557 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002558 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002559 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002560 self.logger.debug(
2561 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2562 )
kuused124bfe2019-06-18 12:09:24 +02002563 return
2564
tierno59d22d22018-09-25 18:10:19 +02002565 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2566 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002567
tierno59d22d22018-09-25 18:10:19 +02002568 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002569
2570 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002571 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002572
2573 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002574 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002575
2576 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002577 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002578 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002579 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002580
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002581 timeout_ns_deploy = self.timeout.ns_deploy
2582
tierno59d22d22018-09-25 18:10:19 +02002583 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002584 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002585 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002586 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002587 exc = None
tiernoe876f672020-02-13 14:34:48 +00002588 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002589 stage = [
2590 "Stage 1/5: preparation of the environment.",
2591 "Waiting for previous operations to terminate.",
2592 "",
2593 ]
tiernoe876f672020-02-13 14:34:48 +00002594 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002595 try:
kuused124bfe2019-06-18 12:09:24 +02002596 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002597 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002598
quilesj7e13aeb2019-10-08 13:34:55 +02002599 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002600 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002601 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002602 db_nsr_update["detailed-status"] = "creating"
2603 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002604 self._write_ns_status(
2605 nsr_id=nsr_id,
2606 ns_state="BUILDING",
2607 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002608 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002609 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002610 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002611 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002612
quilesj7e13aeb2019-10-08 13:34:55 +02002613 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002614 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002615 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002616 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2617 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2618 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2619 )
tierno744303e2020-01-13 16:46:31 +00002620 ns_params = db_nslcmop.get("operationParams")
2621 if ns_params and ns_params.get("timeout_ns_deploy"):
2622 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002623
2624 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002625 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002626 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002627 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002628 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002629 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002630 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002631 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002632 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002633 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002634
quilesj7e13aeb2019-10-08 13:34:55 +02002635 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002636 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002637 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002638 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002639
quilesj7e13aeb2019-10-08 13:34:55 +02002640 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002641 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002642
2643 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002644 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002645 if vnfr.get("kdur"):
2646 kdur_list = []
2647 for kdur in vnfr["kdur"]:
2648 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002649 kdur["additionalParams"] = json.loads(
2650 kdur["additionalParams"]
2651 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002652 kdur_list.append(kdur)
2653 vnfr["kdur"] = kdur_list
2654
bravof922c4172020-11-24 21:21:43 -03002655 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2656 vnfd_id = vnfr["vnfd-id"]
2657 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002658 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002659
quilesj7e13aeb2019-10-08 13:34:55 +02002660 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002661 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002662 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002663 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2664 vnfd_id, vnfd_ref
2665 )
tiernoe876f672020-02-13 14:34:48 +00002666 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002667 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002668
quilesj7e13aeb2019-10-08 13:34:55 +02002669 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002670 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002671
2672 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002673 vca_deployed_list = None
2674 if db_nsr["_admin"].get("deployed"):
2675 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2676 if vca_deployed_list is None:
2677 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002678 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002679 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002680 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002681 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002682 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002683 elif isinstance(vca_deployed_list, dict):
2684 # maintain backward compatibility. Change a dict to list at database
2685 vca_deployed_list = list(vca_deployed_list.values())
2686 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002687 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002688
garciadeblas5697b8b2021-03-24 09:17:02 +01002689 if not isinstance(
2690 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2691 ):
tiernoa009e552019-01-30 16:45:44 +00002692 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2693 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002694
tiernobaa51102018-12-14 13:16:18 +00002695 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2696 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2697 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002698 self.db.set_list(
2699 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2700 )
quilesj3655ae02019-12-12 16:08:35 +00002701
2702 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002703 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2704 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002705
tiernob5203912020-08-11 11:20:13 +00002706 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002707 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002708 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002709 await self.deploy_kdus(
2710 logging_text=logging_text,
2711 nsr_id=nsr_id,
2712 nslcmop_id=nslcmop_id,
2713 db_vnfrs=db_vnfrs,
2714 db_vnfds=db_vnfds,
2715 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002716 )
tiernoe876f672020-02-13 14:34:48 +00002717
2718 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002719 # n2vc_redesign STEP 1 Get VCA public ssh-key
2720 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002721 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002722 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002723 if self.vca_config.public_key:
2724 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002725
tiernoe876f672020-02-13 14:34:48 +00002726 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002727 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002728 self.instantiate_RO(
2729 logging_text=logging_text,
2730 nsr_id=nsr_id,
2731 nsd=nsd,
2732 db_nsr=db_nsr,
2733 db_nslcmop=db_nslcmop,
2734 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002735 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002736 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002737 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002738 )
tiernod8323042019-08-09 11:32:23 +00002739 )
2740 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002741 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002742
tiernod8323042019-08-09 11:32:23 +00002743 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002744 stage[1] = "Deploying Execution Environments."
2745 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002746
Gabriel Cuba1411a002022-10-07 11:38:23 -05002747 # create namespace and certificate if any helm based EE is present in the NS
2748 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002749 await self.vca_map["helm-v3"].setup_ns_namespace(
2750 name=nsr_id,
2751 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002752 # create TLS certificates
2753 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002754 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002755 dns_prefix="*",
2756 nsr_id=nsr_id,
2757 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002758 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002759 )
2760
tiernod8323042019-08-09 11:32:23 +00002761 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002762 for vnf_profile in get_vnf_profiles(nsd):
2763 vnfd_id = vnf_profile["vnfd-id"]
2764 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2765 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002766 db_vnfr = db_vnfrs[member_vnf_index]
2767 base_folder = vnfd["_admin"]["storage"]
2768 vdu_id = None
2769 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002770 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002771 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002772 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002773
tierno8a518872018-12-21 13:42:14 +00002774 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002775 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002776 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002777 deploy_params.update(
2778 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2779 )
tierno8a518872018-12-21 13:42:14 +00002780
bravofe5a31bc2021-02-17 19:09:12 -03002781 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002782 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002783 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002784 logging_text=logging_text
2785 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002786 db_nsr=db_nsr,
2787 db_vnfr=db_vnfr,
2788 nslcmop_id=nslcmop_id,
2789 nsr_id=nsr_id,
2790 nsi_id=nsi_id,
2791 vnfd_id=vnfd_id,
2792 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002793 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002794 member_vnf_index=member_vnf_index,
2795 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002796 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002797 vdu_name=vdu_name,
2798 deploy_params=deploy_params,
2799 descriptor_config=descriptor_config,
2800 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002801 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002802 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002803 )
tierno59d22d22018-09-25 18:10:19 +02002804
2805 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002806 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002807 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002808 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002809 vdur = find_in_list(
2810 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2811 )
bravof922c4172020-11-24 21:21:43 -03002812
tierno626e0152019-11-29 14:16:16 +00002813 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002814 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002815 else:
2816 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002817 deploy_params_vdu["OSM"] = get_osm_params(
2818 db_vnfr, vdu_id, vdu_count_index=0
2819 )
endika76ba9232021-06-21 18:55:07 +02002820 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002821
2822 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002823 self.logger.debug(
2824 "Descriptor config > {}".format(descriptor_config)
2825 )
tierno588547c2020-07-01 15:30:20 +00002826 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002827 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002828 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002829 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002830 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002831 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002832 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002833 logging_text=logging_text
2834 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2835 member_vnf_index, vdu_id, vdu_index
2836 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002837 db_nsr=db_nsr,
2838 db_vnfr=db_vnfr,
2839 nslcmop_id=nslcmop_id,
2840 nsr_id=nsr_id,
2841 nsi_id=nsi_id,
2842 vnfd_id=vnfd_id,
2843 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002844 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002845 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002846 member_vnf_index=member_vnf_index,
2847 vdu_index=vdu_index,
2848 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002849 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002850 descriptor_config=descriptor_config,
2851 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002852 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002853 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002854 )
bravof922c4172020-11-24 21:21:43 -03002855 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002856 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002857 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002858 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002859 vdu_id = None
2860 vdu_index = 0
2861 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002862 kdu_index, kdur = next(
2863 x
2864 for x in enumerate(db_vnfr["kdur"])
2865 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002866 )
bravof922c4172020-11-24 21:21:43 -03002867 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002868 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002869 deploy_params_kdu.update(
2870 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002871 )
tierno59d22d22018-09-25 18:10:19 +02002872
calvinosanch9f9c6f22019-11-04 13:37:39 +01002873 self._deploy_n2vc(
2874 logging_text=logging_text,
2875 db_nsr=db_nsr,
2876 db_vnfr=db_vnfr,
2877 nslcmop_id=nslcmop_id,
2878 nsr_id=nsr_id,
2879 nsi_id=nsi_id,
2880 vnfd_id=vnfd_id,
2881 vdu_id=vdu_id,
2882 kdu_name=kdu_name,
2883 member_vnf_index=member_vnf_index,
2884 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002885 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002886 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002887 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002888 descriptor_config=descriptor_config,
2889 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002890 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002891 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002892 )
tierno59d22d22018-09-25 18:10:19 +02002893
k4.rahul74944982023-04-19 17:00:52 +05302894 # Check if each vnf has exporter for metric collection if so update prometheus job records
2895 if "exporters-endpoints" in vnfd.get("df")[0]:
2896 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2897 self.logger.debug("exporter config :{}".format(exporter_config))
2898 artifact_path = "{}/{}/{}".format(
2899 base_folder["folder"],
2900 base_folder["pkg-dir"],
2901 "exporter-endpoint",
2902 )
2903 ee_id = None
2904 ee_config_descriptor = exporter_config
2905 vnfr_id = db_vnfr["id"]
2906 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2907 logging_text,
2908 nsr_id,
2909 vnfr_id,
2910 vdu_id=None,
2911 vdu_index=None,
2912 user=None,
2913 pub_key=None,
2914 )
2915 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2916 self.logger.debug("Artifact_path:{}".format(artifact_path))
2917 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2918 vdu_id_for_prom = None
2919 vdu_index_for_prom = None
2920 for x in get_iterable(db_vnfr, "vdur"):
2921 vdu_id_for_prom = x.get("vdu-id-ref")
2922 vdu_index_for_prom = x.get("count-index")
2923 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2924 ee_id=ee_id,
2925 artifact_path=artifact_path,
2926 ee_config_descriptor=ee_config_descriptor,
2927 vnfr_id=vnfr_id,
2928 nsr_id=nsr_id,
2929 target_ip=rw_mgmt_ip,
2930 element_type="VDU",
2931 vdu_id=vdu_id_for_prom,
2932 vdu_index=vdu_index_for_prom,
2933 )
2934
2935 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2936 if prometheus_jobs:
2937 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2938 self.update_db_2(
2939 "nsrs",
2940 nsr_id,
2941 db_nsr_update,
2942 )
2943
2944 for job in prometheus_jobs:
2945 self.db.set_one(
2946 "prometheus_jobs",
2947 {"job_name": job["job_name"]},
2948 job,
2949 upsert=True,
2950 fail_on_empty=False,
2951 )
2952
tierno1b633412019-02-25 16:48:23 +00002953 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002954 descriptor_config = nsd.get("ns-configuration")
2955 if descriptor_config and descriptor_config.get("juju"):
2956 vnfd_id = None
2957 db_vnfr = None
2958 member_vnf_index = None
2959 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002960 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002961 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00002962 vdu_index = 0
2963 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002964
tiernod8323042019-08-09 11:32:23 +00002965 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002966 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002967 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002968 deploy_params.update(
2969 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2970 )
tiernod8323042019-08-09 11:32:23 +00002971 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002972 self._deploy_n2vc(
2973 logging_text=logging_text,
2974 db_nsr=db_nsr,
2975 db_vnfr=db_vnfr,
2976 nslcmop_id=nslcmop_id,
2977 nsr_id=nsr_id,
2978 nsi_id=nsi_id,
2979 vnfd_id=vnfd_id,
2980 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002981 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002982 member_vnf_index=member_vnf_index,
2983 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002984 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002985 vdu_name=vdu_name,
2986 deploy_params=deploy_params,
2987 descriptor_config=descriptor_config,
2988 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002989 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002990 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002991 )
tierno1b633412019-02-25 16:48:23 +00002992
tiernoe876f672020-02-13 14:34:48 +00002993 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002994
garciadeblas5697b8b2021-03-24 09:17:02 +01002995 except (
2996 ROclient.ROClientException,
2997 DbException,
2998 LcmException,
2999 N2VCException,
3000 ) as e:
3001 self.logger.error(
3002 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3003 )
tierno59d22d22018-09-25 18:10:19 +02003004 exc = e
3005 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003006 self.logger.error(
3007 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3008 )
tierno59d22d22018-09-25 18:10:19 +02003009 exc = "Operation was cancelled"
3010 except Exception as e:
3011 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003012 self.logger.critical(
3013 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3014 exc_info=True,
3015 )
tierno59d22d22018-09-25 18:10:19 +02003016 finally:
3017 if exc:
tiernoe876f672020-02-13 14:34:48 +00003018 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003019 try:
tiernoe876f672020-02-13 14:34:48 +00003020 # wait for pending tasks
3021 if tasks_dict_info:
3022 stage[1] = "Waiting for instantiate pending tasks."
3023 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003024 error_list += await self._wait_for_tasks(
3025 logging_text,
3026 tasks_dict_info,
3027 timeout_ns_deploy,
3028 stage,
3029 nslcmop_id,
3030 nsr_id=nsr_id,
3031 )
tiernoe876f672020-02-13 14:34:48 +00003032 stage[1] = stage[2] = ""
3033 except asyncio.CancelledError:
3034 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003035 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3036 await self._wait_for_tasks(
3037 logging_text,
3038 tasks_dict_info,
3039 timeout_ns_deploy,
3040 stage,
3041 nslcmop_id,
3042 nsr_id=nsr_id,
3043 )
tiernoe876f672020-02-13 14:34:48 +00003044 except Exception as exc:
3045 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003046
tiernoe876f672020-02-13 14:34:48 +00003047 # update operation-status
3048 db_nsr_update["operational-status"] = "running"
3049 # let's begin with VCA 'configured' status (later we can change it)
3050 db_nsr_update["config-status"] = "configured"
3051 for task, task_name in tasks_dict_info.items():
3052 if not task.done() or task.cancelled() or task.exception():
3053 if task_name.startswith(self.task_name_deploy_vca):
3054 # A N2VC task is pending
3055 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003056 else:
tiernoe876f672020-02-13 14:34:48 +00003057 # RO or KDU task is pending
3058 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003059
tiernoe876f672020-02-13 14:34:48 +00003060 # update status at database
3061 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003062 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003063 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003064 error_description_nslcmop = "{} Detail: {}".format(
3065 stage[0], error_detail
3066 )
3067 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3068 nslcmop_id, stage[0]
3069 )
quilesj3655ae02019-12-12 16:08:35 +00003070
garciadeblas5697b8b2021-03-24 09:17:02 +01003071 db_nsr_update["detailed-status"] = (
3072 error_description_nsr + " Detail: " + error_detail
3073 )
tiernoe876f672020-02-13 14:34:48 +00003074 db_nslcmop_update["detailed-status"] = error_detail
3075 nslcmop_operation_state = "FAILED"
3076 ns_state = "BROKEN"
3077 else:
tiernoa2143262020-03-27 16:20:40 +00003078 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003079 error_description_nsr = error_description_nslcmop = None
3080 ns_state = "READY"
3081 db_nsr_update["detailed-status"] = "Done"
3082 db_nslcmop_update["detailed-status"] = "Done"
3083 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003084 # Gather auto-healing and auto-scaling alerts for each vnfr
3085 healing_alerts = []
3086 scaling_alerts = []
3087 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3088 vnfd = next(
3089 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3090 )
3091 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3092 for alert in healing_alerts:
3093 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3094 self.db.create("alerts", alert)
3095
3096 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3097 for alert in scaling_alerts:
3098 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3099 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003100
garciadeblas9148fa82023-05-30 12:51:14 +02003101 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3102 for alert in alarm_alerts:
3103 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3104 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003105 if db_nsr:
3106 self._write_ns_status(
3107 nsr_id=nsr_id,
3108 ns_state=ns_state,
3109 current_operation="IDLE",
3110 current_operation_id=None,
3111 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003112 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003113 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003114 )
tiernoa17d4f42020-04-28 09:59:23 +00003115 self._write_op_status(
3116 op_id=nslcmop_id,
3117 stage="",
3118 error_message=error_description_nslcmop,
3119 operation_state=nslcmop_operation_state,
3120 other_update=db_nslcmop_update,
3121 )
quilesj3655ae02019-12-12 16:08:35 +00003122
tierno59d22d22018-09-25 18:10:19 +02003123 if nslcmop_operation_state:
3124 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003125 await self.msg.aiowrite(
3126 "ns",
3127 "instantiated",
3128 {
3129 "nsr_id": nsr_id,
3130 "nslcmop_id": nslcmop_id,
3131 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003132 "startTime": db_nslcmop["startTime"],
3133 "links": db_nslcmop["links"],
3134 "operationParams": {
3135 "nsInstanceId": nsr_id,
3136 "nsdId": db_nsr["nsd-id"],
3137 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003138 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003139 )
tierno59d22d22018-09-25 18:10:19 +02003140 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003141 self.logger.error(
3142 logging_text + "kafka_write notification Exception {}".format(e)
3143 )
tierno59d22d22018-09-25 18:10:19 +02003144
3145 self.logger.debug(logging_text + "Exit")
3146 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3147
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003148 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003149 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003150 cached_vnfds[vnfd_id] = self.db.get_one(
3151 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3152 )
David Garciab4ebcd02021-10-28 02:00:43 +02003153 return cached_vnfds[vnfd_id]
3154
3155 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3156 if vnf_profile_id not in cached_vnfrs:
3157 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3158 "vnfrs",
3159 {
3160 "member-vnf-index-ref": vnf_profile_id,
3161 "nsr-id-ref": nsr_id,
3162 },
3163 )
3164 return cached_vnfrs[vnf_profile_id]
3165
3166 def _is_deployed_vca_in_relation(
3167 self, vca: DeployedVCA, relation: Relation
3168 ) -> bool:
3169 found = False
3170 for endpoint in (relation.provider, relation.requirer):
3171 if endpoint["kdu-resource-profile-id"]:
3172 continue
3173 found = (
3174 vca.vnf_profile_id == endpoint.vnf_profile_id
3175 and vca.vdu_profile_id == endpoint.vdu_profile_id
3176 and vca.execution_environment_ref == endpoint.execution_environment_ref
3177 )
3178 if found:
3179 break
3180 return found
3181
3182 def _update_ee_relation_data_with_implicit_data(
3183 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3184 ):
3185 ee_relation_data = safe_get_ee_relation(
3186 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3187 )
3188 ee_relation_level = EELevel.get_level(ee_relation_data)
3189 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3190 "execution-environment-ref"
3191 ]:
3192 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3193 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003194 project = nsd["_admin"]["projects_read"][0]
3195 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003196 entity_id = (
3197 vnfd_id
3198 if ee_relation_level == EELevel.VNF
3199 else ee_relation_data["vdu-profile-id"]
3200 )
3201 ee = get_juju_ee_ref(db_vnfd, entity_id)
3202 if not ee:
3203 raise Exception(
3204 f"not execution environments found for ee_relation {ee_relation_data}"
3205 )
3206 ee_relation_data["execution-environment-ref"] = ee["id"]
3207 return ee_relation_data
3208
3209 def _get_ns_relations(
3210 self,
3211 nsr_id: str,
3212 nsd: Dict[str, Any],
3213 vca: DeployedVCA,
3214 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003215 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003216 relations = []
3217 db_ns_relations = get_ns_configuration_relation_list(nsd)
3218 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003219 provider_dict = None
3220 requirer_dict = None
3221 if all(key in r for key in ("provider", "requirer")):
3222 provider_dict = r["provider"]
3223 requirer_dict = r["requirer"]
3224 elif "entities" in r:
3225 provider_id = r["entities"][0]["id"]
3226 provider_dict = {
3227 "nsr-id": nsr_id,
3228 "endpoint": r["entities"][0]["endpoint"],
3229 }
3230 if provider_id != nsd["id"]:
3231 provider_dict["vnf-profile-id"] = provider_id
3232 requirer_id = r["entities"][1]["id"]
3233 requirer_dict = {
3234 "nsr-id": nsr_id,
3235 "endpoint": r["entities"][1]["endpoint"],
3236 }
3237 if requirer_id != nsd["id"]:
3238 requirer_dict["vnf-profile-id"] = requirer_id
3239 else:
aticig15db6142022-01-24 12:51:26 +03003240 raise Exception(
3241 "provider/requirer or entities must be included in the relation."
3242 )
David Garciab4ebcd02021-10-28 02:00:43 +02003243 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003244 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003245 )
3246 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003247 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003248 )
3249 provider = EERelation(relation_provider)
3250 requirer = EERelation(relation_requirer)
3251 relation = Relation(r["name"], provider, requirer)
3252 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3253 if vca_in_relation:
3254 relations.append(relation)
3255 return relations
3256
3257 def _get_vnf_relations(
3258 self,
3259 nsr_id: str,
3260 nsd: Dict[str, Any],
3261 vca: DeployedVCA,
3262 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003263 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003264 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003265 if vca.target_element == "ns":
3266 self.logger.debug("VCA is a NS charm, not a VNF.")
3267 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003268 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3269 vnf_profile_id = vnf_profile["id"]
3270 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003271 project = nsd["_admin"]["projects_read"][0]
3272 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003273 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3274 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003275 provider_dict = None
3276 requirer_dict = None
3277 if all(key in r for key in ("provider", "requirer")):
3278 provider_dict = r["provider"]
3279 requirer_dict = r["requirer"]
3280 elif "entities" in r:
3281 provider_id = r["entities"][0]["id"]
3282 provider_dict = {
3283 "nsr-id": nsr_id,
3284 "vnf-profile-id": vnf_profile_id,
3285 "endpoint": r["entities"][0]["endpoint"],
3286 }
3287 if provider_id != vnfd_id:
3288 provider_dict["vdu-profile-id"] = provider_id
3289 requirer_id = r["entities"][1]["id"]
3290 requirer_dict = {
3291 "nsr-id": nsr_id,
3292 "vnf-profile-id": vnf_profile_id,
3293 "endpoint": r["entities"][1]["endpoint"],
3294 }
3295 if requirer_id != vnfd_id:
3296 requirer_dict["vdu-profile-id"] = requirer_id
3297 else:
aticig15db6142022-01-24 12:51:26 +03003298 raise Exception(
3299 "provider/requirer or entities must be included in the relation."
3300 )
David Garciab4ebcd02021-10-28 02:00:43 +02003301 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003302 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003303 )
3304 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003305 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003306 )
3307 provider = EERelation(relation_provider)
3308 requirer = EERelation(relation_requirer)
3309 relation = Relation(r["name"], provider, requirer)
3310 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3311 if vca_in_relation:
3312 relations.append(relation)
3313 return relations
3314
3315 def _get_kdu_resource_data(
3316 self,
3317 ee_relation: EERelation,
3318 db_nsr: Dict[str, Any],
3319 cached_vnfds: Dict[str, Any],
3320 ) -> DeployedK8sResource:
3321 nsd = get_nsd(db_nsr)
3322 vnf_profiles = get_vnf_profiles(nsd)
3323 vnfd_id = find_in_list(
3324 vnf_profiles,
3325 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3326 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003327 project = nsd["_admin"]["projects_read"][0]
3328 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003329 kdu_resource_profile = get_kdu_resource_profile(
3330 db_vnfd, ee_relation.kdu_resource_profile_id
3331 )
3332 kdu_name = kdu_resource_profile["kdu-name"]
3333 deployed_kdu, _ = get_deployed_kdu(
3334 db_nsr.get("_admin", ()).get("deployed", ()),
3335 kdu_name,
3336 ee_relation.vnf_profile_id,
3337 )
3338 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3339 return deployed_kdu
3340
3341 def _get_deployed_component(
3342 self,
3343 ee_relation: EERelation,
3344 db_nsr: Dict[str, Any],
3345 cached_vnfds: Dict[str, Any],
3346 ) -> DeployedComponent:
3347 nsr_id = db_nsr["_id"]
3348 deployed_component = None
3349 ee_level = EELevel.get_level(ee_relation)
3350 if ee_level == EELevel.NS:
3351 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3352 if vca:
3353 deployed_component = DeployedVCA(nsr_id, vca)
3354 elif ee_level == EELevel.VNF:
3355 vca = get_deployed_vca(
3356 db_nsr,
3357 {
3358 "vdu_id": None,
3359 "member-vnf-index": ee_relation.vnf_profile_id,
3360 "ee_descriptor_id": ee_relation.execution_environment_ref,
3361 },
3362 )
3363 if vca:
3364 deployed_component = DeployedVCA(nsr_id, vca)
3365 elif ee_level == EELevel.VDU:
3366 vca = get_deployed_vca(
3367 db_nsr,
3368 {
3369 "vdu_id": ee_relation.vdu_profile_id,
3370 "member-vnf-index": ee_relation.vnf_profile_id,
3371 "ee_descriptor_id": ee_relation.execution_environment_ref,
3372 },
3373 )
3374 if vca:
3375 deployed_component = DeployedVCA(nsr_id, vca)
3376 elif ee_level == EELevel.KDU:
3377 kdu_resource_data = self._get_kdu_resource_data(
3378 ee_relation, db_nsr, cached_vnfds
3379 )
3380 if kdu_resource_data:
3381 deployed_component = DeployedK8sResource(kdu_resource_data)
3382 return deployed_component
3383
3384 async def _add_relation(
3385 self,
3386 relation: Relation,
3387 vca_type: str,
3388 db_nsr: Dict[str, Any],
3389 cached_vnfds: Dict[str, Any],
3390 cached_vnfrs: Dict[str, Any],
3391 ) -> bool:
3392 deployed_provider = self._get_deployed_component(
3393 relation.provider, db_nsr, cached_vnfds
3394 )
3395 deployed_requirer = self._get_deployed_component(
3396 relation.requirer, db_nsr, cached_vnfds
3397 )
3398 if (
3399 deployed_provider
3400 and deployed_requirer
3401 and deployed_provider.config_sw_installed
3402 and deployed_requirer.config_sw_installed
3403 ):
3404 provider_db_vnfr = (
3405 self._get_vnfr(
3406 relation.provider.nsr_id,
3407 relation.provider.vnf_profile_id,
3408 cached_vnfrs,
3409 )
3410 if relation.provider.vnf_profile_id
3411 else None
3412 )
3413 requirer_db_vnfr = (
3414 self._get_vnfr(
3415 relation.requirer.nsr_id,
3416 relation.requirer.vnf_profile_id,
3417 cached_vnfrs,
3418 )
3419 if relation.requirer.vnf_profile_id
3420 else None
3421 )
3422 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3423 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3424 provider_relation_endpoint = RelationEndpoint(
3425 deployed_provider.ee_id,
3426 provider_vca_id,
3427 relation.provider.endpoint,
3428 )
3429 requirer_relation_endpoint = RelationEndpoint(
3430 deployed_requirer.ee_id,
3431 requirer_vca_id,
3432 relation.requirer.endpoint,
3433 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003434 try:
3435 await self.vca_map[vca_type].add_relation(
3436 provider=provider_relation_endpoint,
3437 requirer=requirer_relation_endpoint,
3438 )
3439 except N2VCException as exception:
3440 self.logger.error(exception)
3441 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003442 return True
3443 return False
3444
David Garciac1fe90a2021-03-31 19:12:02 +02003445 async def _add_vca_relations(
3446 self,
3447 logging_text,
3448 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003449 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003450 vca_index: int,
3451 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003452 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003453 # steps:
3454 # 1. find all relations for this VCA
3455 # 2. wait for other peers related
3456 # 3. add relations
3457
3458 try:
quilesj63f90042020-01-17 09:53:55 +00003459 # STEP 1: find all relations for this VCA
3460
3461 # read nsr record
3462 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003463 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003464
3465 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003466 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3467 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003468
David Garciab4ebcd02021-10-28 02:00:43 +02003469 cached_vnfds = {}
3470 cached_vnfrs = {}
3471 relations = []
3472 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3473 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003474
3475 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003476 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003477 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003478 return True
3479
David Garciab4ebcd02021-10-28 02:00:43 +02003480 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003481
3482 # add all relations
3483 start = time()
3484 while True:
3485 # check timeout
3486 now = time()
3487 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003488 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003489 return False
3490
David Garciab4ebcd02021-10-28 02:00:43 +02003491 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003492 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3493
David Garciab4ebcd02021-10-28 02:00:43 +02003494 # for each relation, find the VCA's related
3495 for relation in relations.copy():
3496 added = await self._add_relation(
3497 relation,
3498 vca_type,
3499 db_nsr,
3500 cached_vnfds,
3501 cached_vnfrs,
3502 )
3503 if added:
3504 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003505
David Garciab4ebcd02021-10-28 02:00:43 +02003506 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003507 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003508 break
David Garciab4ebcd02021-10-28 02:00:43 +02003509 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003510
3511 return True
3512
3513 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003514 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003515 return False
3516
garciadeblas5697b8b2021-03-24 09:17:02 +01003517 async def _install_kdu(
3518 self,
3519 nsr_id: str,
3520 nsr_db_path: str,
3521 vnfr_data: dict,
3522 kdu_index: int,
3523 kdud: dict,
3524 vnfd: dict,
3525 k8s_instance_info: dict,
3526 k8params: dict = None,
3527 timeout: int = 600,
3528 vca_id: str = None,
3529 ):
tiernob9018152020-04-16 14:18:24 +00003530 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003531 k8sclustertype = k8s_instance_info["k8scluster-type"]
3532 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003533 db_dict_install = {
3534 "collection": "nsrs",
3535 "filter": {"_id": nsr_id},
3536 "path": nsr_db_path,
3537 }
lloretgalleg7c121132020-07-08 07:53:22 +00003538
romeromonser4554a702021-05-28 12:00:08 +02003539 if k8s_instance_info.get("kdu-deployment-name"):
3540 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3541 else:
3542 kdu_instance = self.k8scluster_map[
3543 k8sclustertype
3544 ].generate_kdu_instance_name(
3545 db_dict=db_dict_install,
3546 kdu_model=k8s_instance_info["kdu-model"],
3547 kdu_name=k8s_instance_info["kdu-name"],
3548 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003549
3550 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003551 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003552 item="nsrs",
3553 _id=nsr_id,
3554 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003555 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003556
3557 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3558 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3559 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3560 # namespace, this first verification could be removed, and the next step would be done for any kind
3561 # of KNF.
3562 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3563 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3564 if k8sclustertype in ("juju", "juju-bundle"):
3565 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3566 # that the user passed a namespace which he wants its KDU to be deployed in)
3567 if (
3568 self.db.count(
3569 table="nsrs",
3570 q_filter={
3571 "_id": nsr_id,
3572 "_admin.projects_write": k8s_instance_info["namespace"],
3573 "_admin.projects_read": k8s_instance_info["namespace"],
3574 },
3575 )
3576 > 0
3577 ):
3578 self.logger.debug(
3579 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3580 )
3581 self.update_db_2(
3582 item="nsrs",
3583 _id=nsr_id,
3584 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3585 )
3586 k8s_instance_info["namespace"] = kdu_instance
3587
David Garciad64e2742021-02-25 20:19:18 +01003588 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003589 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3590 kdu_model=k8s_instance_info["kdu-model"],
3591 atomic=True,
3592 params=k8params,
3593 db_dict=db_dict_install,
3594 timeout=timeout,
3595 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003596 namespace=k8s_instance_info["namespace"],
3597 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003598 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003599 )
lloretgalleg7c121132020-07-08 07:53:22 +00003600
3601 # Obtain services to obtain management service ip
3602 services = await self.k8scluster_map[k8sclustertype].get_services(
3603 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3604 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003605 namespace=k8s_instance_info["namespace"],
3606 )
lloretgalleg7c121132020-07-08 07:53:22 +00003607
3608 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003609 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003610 kdu_config = get_configuration(vnfd, kdud["name"])
3611 if kdu_config:
3612 target_ee_list = kdu_config.get("execution-environment-list", [])
3613 else:
3614 target_ee_list = []
3615
lloretgalleg7c121132020-07-08 07:53:22 +00003616 if services:
tierno7ecbc342020-09-21 14:05:39 +00003617 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003618 mgmt_services = [
3619 service
3620 for service in kdud.get("service", [])
3621 if service.get("mgmt-service")
3622 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003623 for mgmt_service in mgmt_services:
3624 for service in services:
3625 if service["name"].startswith(mgmt_service["name"]):
3626 # Mgmt service found, Obtain service ip
3627 ip = service.get("external_ip", service.get("cluster_ip"))
3628 if isinstance(ip, list) and len(ip) == 1:
3629 ip = ip[0]
3630
garciadeblas5697b8b2021-03-24 09:17:02 +01003631 vnfr_update_dict[
3632 "kdur.{}.ip-address".format(kdu_index)
3633 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003634
3635 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003636 service_external_cp = mgmt_service.get(
3637 "external-connection-point-ref"
3638 )
lloretgalleg7c121132020-07-08 07:53:22 +00003639 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003640 if (
3641 deep_get(vnfd, ("mgmt-interface", "cp"))
3642 == service_external_cp
3643 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003644 vnfr_update_dict["ip-address"] = ip
3645
bravof6ec62b72021-02-25 17:20:35 -03003646 if find_in_list(
3647 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003648 lambda ee: ee.get(
3649 "external-connection-point-ref", ""
3650 )
3651 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003652 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003653 vnfr_update_dict[
3654 "kdur.{}.ip-address".format(kdu_index)
3655 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003656 break
3657 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003658 self.logger.warn(
3659 "Mgmt service name: {} not found".format(
3660 mgmt_service["name"]
3661 )
3662 )
lloretgalleg7c121132020-07-08 07:53:22 +00003663
tierno7ecbc342020-09-21 14:05:39 +00003664 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3665 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003666
bravof9a256db2021-02-22 18:02:07 -03003667 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003668 if (
3669 kdu_config
3670 and kdu_config.get("initial-config-primitive")
3671 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
jegan99448902024-12-06 07:19:34 +00003672 and get_helm_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
garciadeblas5697b8b2021-03-24 09:17:02 +01003673 ):
3674 initial_config_primitive_list = kdu_config.get(
3675 "initial-config-primitive"
3676 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003677 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3678
3679 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003680 primitive_params_ = self._map_primitive_params(
3681 initial_config_primitive, {}, {}
3682 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003683
3684 await asyncio.wait_for(
3685 self.k8scluster_map[k8sclustertype].exec_primitive(
3686 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3687 kdu_instance=kdu_instance,
3688 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003689 params=primitive_params_,
3690 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003691 vca_id=vca_id,
3692 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003693 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003694 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003695
tiernob9018152020-04-16 14:18:24 +00003696 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003697 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003698 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003699 self.update_db_2(
3700 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3701 )
3702 self.update_db_2(
3703 "vnfrs",
3704 vnfr_data.get("_id"),
3705 {"kdur.{}.status".format(kdu_index): "ERROR"},
3706 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003707 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003708 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003709 self.logger.warning(
3710 f"An exception occurred while updating DB: {str(error)}"
3711 )
lloretgalleg7c121132020-07-08 07:53:22 +00003712 # reraise original error
3713 raise
3714
3715 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003716
garciadeblas5697b8b2021-03-24 09:17:02 +01003717 async def deploy_kdus(
3718 self,
3719 logging_text,
3720 nsr_id,
3721 nslcmop_id,
3722 db_vnfrs,
3723 db_vnfds,
3724 task_instantiation_info,
3725 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003726 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003727
garciadeblas5697b8b2021-03-24 09:17:02 +01003728 k8scluster_id_2_uuic = {
3729 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003730 "juju-bundle": {},
3731 }
tierno626e0152019-11-29 14:16:16 +00003732
tierno16f4a4e2020-07-20 09:05:51 +00003733 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003734 nonlocal k8scluster_id_2_uuic
3735 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3736 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3737
tierno16f4a4e2020-07-20 09:05:51 +00003738 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003739 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3740 "k8scluster", cluster_id
3741 )
tierno16f4a4e2020-07-20 09:05:51 +00003742 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003743 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3744 task_name, cluster_id
3745 )
tierno16f4a4e2020-07-20 09:05:51 +00003746 self.logger.debug(logging_text + text)
3747 await asyncio.wait(task_dependency, timeout=3600)
3748
garciadeblas5697b8b2021-03-24 09:17:02 +01003749 db_k8scluster = self.db.get_one(
3750 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3751 )
tierno626e0152019-11-29 14:16:16 +00003752 if not db_k8scluster:
3753 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003754
tierno626e0152019-11-29 14:16:16 +00003755 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3756 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003757 if cluster_type == "helm-chart-v3":
3758 try:
3759 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003760 k8s_credentials = yaml.safe_dump(
3761 db_k8scluster.get("credentials")
3762 )
3763 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3764 k8s_credentials, reuse_cluster_uuid=cluster_id
3765 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003766 db_k8scluster_update = {}
3767 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3768 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003769 db_k8scluster_update[
3770 "_admin.helm-chart-v3.created"
3771 ] = uninstall_sw
3772 db_k8scluster_update[
3773 "_admin.helm-chart-v3.operationalState"
3774 ] = "ENABLED"
3775 self.update_db_2(
3776 "k8sclusters", cluster_id, db_k8scluster_update
3777 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003778 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003779 self.logger.error(
3780 logging_text
3781 + "error initializing helm-v3 cluster: {}".format(str(e))
3782 )
3783 raise LcmException(
3784 "K8s cluster '{}' has not been initialized for '{}'".format(
3785 cluster_id, cluster_type
3786 )
3787 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003788 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003789 raise LcmException(
3790 "K8s cluster '{}' has not been initialized for '{}'".format(
3791 cluster_id, cluster_type
3792 )
3793 )
tierno626e0152019-11-29 14:16:16 +00003794 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3795 return k8s_id
3796
3797 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003798 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003799 try:
tierno626e0152019-11-29 14:16:16 +00003800 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003801 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003802
tierno626e0152019-11-29 14:16:16 +00003803 index = 0
tiernoe876f672020-02-13 14:34:48 +00003804 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003805 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003806
tierno626e0152019-11-29 14:16:16 +00003807 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003808 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003809 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3810 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003811 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003812 vnfd_id = vnfr_data.get("vnfd-id")
3813 vnfd_with_id = find_in_list(
3814 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3815 )
3816 kdud = next(
3817 kdud
3818 for kdud in vnfd_with_id["kdu"]
3819 if kdud["name"] == kdur["kdu-name"]
3820 )
tiernode1584f2020-04-07 09:07:33 +00003821 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003822 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003823 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003824 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003825 # Default version: helm3, if helm-version is v2 assign v2
3826 k8sclustertype = "helm-chart-v3"
3827 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003828 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003829 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003830 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003831 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003832 raise LcmException(
3833 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3834 "juju-bundle. Maybe an old NBI version is running".format(
3835 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3836 )
3837 )
quilesjacde94f2020-01-23 10:07:08 +00003838 # check if kdumodel is a file and exists
3839 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003840 vnfd_with_id = find_in_list(
3841 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3842 )
3843 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003844 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003845 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003846 if storage["pkg-dir"]:
3847 filename = "{}/{}/{}s/{}".format(
3848 storage["folder"],
3849 storage["pkg-dir"],
3850 k8sclustertype,
3851 kdumodel,
3852 )
3853 else:
3854 filename = "{}/Scripts/{}s/{}".format(
3855 storage["folder"],
3856 k8sclustertype,
3857 kdumodel,
3858 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003859 if self.fs.file_exists(
3860 filename, mode="file"
3861 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003862 kdumodel = self.fs.path + filename
3863 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003864 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003865 except Exception as e: # it is not a file
3866 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003867
tiernoe876f672020-02-13 14:34:48 +00003868 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003869 step = "Synchronize repos for k8s cluster '{}'".format(
3870 k8s_cluster_id
3871 )
tierno16f4a4e2020-07-20 09:05:51 +00003872 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003873
lloretgalleg7c121132020-07-08 07:53:22 +00003874 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003875 if (
3876 k8sclustertype == "helm-chart"
3877 and cluster_uuid not in updated_cluster_list
3878 ) or (
3879 k8sclustertype == "helm-chart-v3"
3880 and cluster_uuid not in updated_v3_cluster_list
3881 ):
tiernoe876f672020-02-13 14:34:48 +00003882 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003883 self.k8scluster_map[k8sclustertype].synchronize_repos(
3884 cluster_uuid=cluster_uuid
3885 )
3886 )
tiernoe876f672020-02-13 14:34:48 +00003887 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003888 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003889 unset = {
3890 "_admin.helm_charts_added." + item: None
3891 for item in del_repo_list
3892 }
3893 updated = {
3894 "_admin.helm_charts_added." + item: name
3895 for item, name in added_repo_dict.items()
3896 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003897 updated_cluster_list.append(cluster_uuid)
3898 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003899 unset = {
3900 "_admin.helm_charts_v3_added." + item: None
3901 for item in del_repo_list
3902 }
3903 updated = {
3904 "_admin.helm_charts_v3_added." + item: name
3905 for item, name in added_repo_dict.items()
3906 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003907 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003908 self.logger.debug(
3909 logging_text + "repos synchronized on k8s cluster "
3910 "'{}' to_delete: {}, to_add: {}".format(
3911 k8s_cluster_id, del_repo_list, added_repo_dict
3912 )
3913 )
3914 self.db.set_one(
3915 "k8sclusters",
3916 {"_id": k8s_cluster_id},
3917 updated,
3918 unset=unset,
3919 )
lloretgallegedc5f332020-02-20 11:50:50 +01003920
lloretgalleg7c121132020-07-08 07:53:22 +00003921 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003922 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3923 vnfr_data["member-vnf-index-ref"],
3924 kdur["kdu-name"],
3925 k8s_cluster_id,
3926 )
3927 k8s_instance_info = {
3928 "kdu-instance": None,
3929 "k8scluster-uuid": cluster_uuid,
3930 "k8scluster-type": k8sclustertype,
3931 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3932 "kdu-name": kdur["kdu-name"],
3933 "kdu-model": kdumodel,
3934 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003935 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003936 }
tiernob9018152020-04-16 14:18:24 +00003937 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003938 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003939 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003940 vnfd_with_id = find_in_list(
3941 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3942 )
tiernoa2143262020-03-27 16:20:40 +00003943 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003944 self._install_kdu(
3945 nsr_id,
3946 db_path,
3947 vnfr_data,
3948 kdu_index,
3949 kdud,
3950 vnfd_with_id,
3951 k8s_instance_info,
3952 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003953 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003954 vca_id=vca_id,
3955 )
3956 )
3957 self.lcm_tasks.register(
3958 "ns",
3959 nsr_id,
3960 nslcmop_id,
3961 "instantiate_KDU-{}".format(index),
3962 task,
3963 )
3964 task_instantiation_info[task] = "Deploying KDU {}".format(
3965 kdur["kdu-name"]
3966 )
tiernoe876f672020-02-13 14:34:48 +00003967
tierno626e0152019-11-29 14:16:16 +00003968 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003969
tiernoe876f672020-02-13 14:34:48 +00003970 except (LcmException, asyncio.CancelledError):
3971 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003972 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003973 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3974 if isinstance(e, (N2VCException, DbException)):
3975 self.logger.error(logging_text + msg)
3976 else:
3977 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003978 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003979 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003980 if db_nsr_update:
3981 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003982
garciadeblas5697b8b2021-03-24 09:17:02 +01003983 def _deploy_n2vc(
3984 self,
3985 logging_text,
3986 db_nsr,
3987 db_vnfr,
3988 nslcmop_id,
3989 nsr_id,
3990 nsi_id,
3991 vnfd_id,
3992 vdu_id,
3993 kdu_name,
3994 member_vnf_index,
3995 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003996 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01003997 vdu_name,
3998 deploy_params,
3999 descriptor_config,
4000 base_folder,
4001 task_instantiation_info,
4002 stage,
4003 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004004 # launch instantiate_N2VC in a asyncio task and register task object
4005 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4006 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004007 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004008
garciadeblas5697b8b2021-03-24 09:17:02 +01004009 self.logger.debug(
4010 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4011 )
aticig9bc63ac2022-07-27 09:32:06 +03004012
4013 charm_name = ""
4014 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004015 if "execution-environment-list" in descriptor_config:
4016 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004017 elif "juju" in descriptor_config:
4018 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004019 if "execution-environment-list" not in descriptor_config:
4020 # charm name is only required for ns charms
4021 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004022 else: # other types as script are not supported
4023 ee_list = []
4024
4025 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004026 self.logger.debug(
4027 logging_text
4028 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4029 ee_item.get("juju"), ee_item.get("helm-chart")
4030 )
4031 )
tiernoa278b842020-07-08 15:33:55 +00004032 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05004033 vca_name, charm_name, vca_type = self.get_vca_info(
4034 ee_item, db_nsr, get_charm_name
4035 )
4036 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004037 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004038 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004039 )
quilesj7e13aeb2019-10-08 13:34:55 +02004040 continue
quilesj3655ae02019-12-12 16:08:35 +00004041
tierno588547c2020-07-01 15:30:20 +00004042 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004043 for vca_index, vca_deployed in enumerate(
4044 db_nsr["_admin"]["deployed"]["VCA"]
4045 ):
tierno588547c2020-07-01 15:30:20 +00004046 if not vca_deployed:
4047 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004048 if (
4049 vca_deployed.get("member-vnf-index") == member_vnf_index
4050 and vca_deployed.get("vdu_id") == vdu_id
4051 and vca_deployed.get("kdu_name") == kdu_name
4052 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4053 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4054 ):
tierno588547c2020-07-01 15:30:20 +00004055 break
4056 else:
4057 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004058 target = (
4059 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4060 )
tiernoa278b842020-07-08 15:33:55 +00004061 if vdu_id:
4062 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4063 elif kdu_name:
4064 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004065 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004066 "target_element": target,
4067 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004068 "member-vnf-index": member_vnf_index,
4069 "vdu_id": vdu_id,
4070 "kdu_name": kdu_name,
4071 "vdu_count_index": vdu_index,
4072 "operational-status": "init", # TODO revise
4073 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004074 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004075 "vnfd_id": vnfd_id,
4076 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004077 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004078 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004079 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004080 }
4081 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004082
tierno588547c2020-07-01 15:30:20 +00004083 # create VCA and configurationStatus in db
4084 db_dict = {
4085 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004086 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004087 }
4088 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004089
tierno588547c2020-07-01 15:30:20 +00004090 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4091
bravof922c4172020-11-24 21:21:43 -03004092 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4093 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4094 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4095
tierno588547c2020-07-01 15:30:20 +00004096 # Launch task
4097 task_n2vc = asyncio.ensure_future(
4098 self.instantiate_N2VC(
4099 logging_text=logging_text,
4100 vca_index=vca_index,
4101 nsi_id=nsi_id,
4102 db_nsr=db_nsr,
4103 db_vnfr=db_vnfr,
4104 vdu_id=vdu_id,
4105 kdu_name=kdu_name,
4106 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004107 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004108 deploy_params=deploy_params,
4109 config_descriptor=descriptor_config,
4110 base_folder=base_folder,
4111 nslcmop_id=nslcmop_id,
4112 stage=stage,
4113 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004114 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004115 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004116 )
quilesj7e13aeb2019-10-08 13:34:55 +02004117 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004118 self.lcm_tasks.register(
4119 "ns",
4120 nsr_id,
4121 nslcmop_id,
4122 "instantiate_N2VC-{}".format(vca_index),
4123 task_n2vc,
4124 )
4125 task_instantiation_info[
4126 task_n2vc
4127 ] = self.task_name_deploy_vca + " {}.{}".format(
4128 member_vnf_index or "", vdu_id or ""
4129 )
tiernobaa51102018-12-14 13:16:18 +00004130
calvinosanch9f9c6f22019-11-04 13:37:39 +01004131 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004132 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004133 for key, value in params.items():
4134 if str(value).startswith("!!yaml "):
4135 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004136 return params
4137
kuuse8b998e42019-07-30 15:22:16 +02004138 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004139 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004140 primitive_params = {}
4141 params = {
4142 "member_vnf_index": vnf_index,
4143 "primitive": primitive,
4144 "primitive_params": primitive_params,
4145 }
4146 desc_params = {}
4147 return self._map_primitive_params(seq, params, desc_params)
4148
kuuseac3a8882019-10-03 10:48:06 +02004149 # sub-operations
4150
tierno51183952020-04-03 15:48:18 +00004151 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004152 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4153 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004154 # b. Skip sub-operation
4155 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4156 return self.SUBOPERATION_STATUS_SKIP
4157 else:
tierno7c4e24c2020-05-13 08:41:35 +00004158 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004159 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004160 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004161 operationState = "PROCESSING"
4162 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004163 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004164 db_nslcmop, op_index, operationState, detailed_status
4165 )
kuuseac3a8882019-10-03 10:48:06 +02004166 # Return the sub-operation index
4167 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4168 # with arguments extracted from the sub-operation
4169 return op_index
4170
4171 # Find a sub-operation where all keys in a matching dictionary must match
4172 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4173 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004174 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004175 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004176 for i, op in enumerate(op_list):
4177 if all(op.get(k) == match[k] for k in match):
4178 return i
4179 return self.SUBOPERATION_STATUS_NOT_FOUND
4180
4181 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004182 def _update_suboperation_status(
4183 self, db_nslcmop, op_index, operationState, detailed_status
4184 ):
kuuseac3a8882019-10-03 10:48:06 +02004185 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004186 q_filter = {"_id": db_nslcmop["_id"]}
4187 update_dict = {
4188 "_admin.operations.{}.operationState".format(op_index): operationState,
4189 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4190 }
4191 self.db.set_one(
4192 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4193 )
kuuseac3a8882019-10-03 10:48:06 +02004194
4195 # Add sub-operation, return the index of the added sub-operation
4196 # Optionally, set operationState, detailed-status, and operationType
4197 # Status and type are currently set for 'scale' sub-operations:
4198 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4199 # 'detailed-status' : status message
4200 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4201 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004202 def _add_suboperation(
4203 self,
4204 db_nslcmop,
4205 vnf_index,
4206 vdu_id,
4207 vdu_count_index,
4208 vdu_name,
4209 primitive,
4210 mapped_primitive_params,
4211 operationState=None,
4212 detailed_status=None,
4213 operationType=None,
4214 RO_nsr_id=None,
4215 RO_scaling_info=None,
4216 ):
tiernoe876f672020-02-13 14:34:48 +00004217 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004218 return self.SUBOPERATION_STATUS_NOT_FOUND
4219 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004220 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4221 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004222 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004223 new_op = {
4224 "member_vnf_index": vnf_index,
4225 "vdu_id": vdu_id,
4226 "vdu_count_index": vdu_count_index,
4227 "primitive": primitive,
4228 "primitive_params": mapped_primitive_params,
4229 }
kuuseac3a8882019-10-03 10:48:06 +02004230 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004231 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004232 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004233 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004234 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004235 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004236 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004237 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004238 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004239 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004240 if not op_list:
4241 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004242 db_nslcmop_admin.update({"operations": [new_op]})
4243 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004244 else:
4245 # Existing operations, append operation to list
4246 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004247
garciadeblas5697b8b2021-03-24 09:17:02 +01004248 db_nslcmop_update = {"_admin.operations": op_list}
4249 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004250 op_index = len(op_list) - 1
4251 return op_index
4252
4253 # Helper methods for scale() sub-operations
4254
4255 # pre-scale/post-scale:
4256 # Check for 3 different cases:
4257 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4258 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004259 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004260 def _check_or_add_scale_suboperation(
4261 self,
4262 db_nslcmop,
4263 vnf_index,
4264 vnf_config_primitive,
4265 primitive_params,
4266 operationType,
4267 RO_nsr_id=None,
4268 RO_scaling_info=None,
4269 ):
kuuseac3a8882019-10-03 10:48:06 +02004270 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004271 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004272 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004273 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004274 "member_vnf_index": vnf_index,
4275 "RO_nsr_id": RO_nsr_id,
4276 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004277 }
4278 else:
4279 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004280 "member_vnf_index": vnf_index,
4281 "primitive": vnf_config_primitive,
4282 "primitive_params": primitive_params,
4283 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004284 }
4285 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004286 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004287 # a. New sub-operation
4288 # The sub-operation does not exist, add it.
4289 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4290 # The following parameters are set to None for all kind of scaling:
4291 vdu_id = None
4292 vdu_count_index = None
4293 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004294 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004295 vnf_config_primitive = None
4296 primitive_params = None
4297 else:
4298 RO_nsr_id = None
4299 RO_scaling_info = None
4300 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004301 operationState = "PROCESSING"
4302 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004303 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004304 self._add_suboperation(
4305 db_nslcmop,
4306 vnf_index,
4307 vdu_id,
4308 vdu_count_index,
4309 vdu_name,
4310 vnf_config_primitive,
4311 primitive_params,
4312 operationState,
4313 detailed_status,
4314 operationType,
4315 RO_nsr_id,
4316 RO_scaling_info,
4317 )
kuuseac3a8882019-10-03 10:48:06 +02004318 return self.SUBOPERATION_STATUS_NEW
4319 else:
4320 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4321 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004322 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004323
preethika.pdf7d8e02019-12-10 13:10:48 +00004324 # Function to return execution_environment id
4325
David Garciac1fe90a2021-03-31 19:12:02 +02004326 async def destroy_N2VC(
4327 self,
4328 logging_text,
4329 db_nslcmop,
4330 vca_deployed,
4331 config_descriptor,
4332 vca_index,
4333 destroy_ee=True,
4334 exec_primitives=True,
4335 scaling_in=False,
4336 vca_id: str = None,
4337 ):
tiernoe876f672020-02-13 14:34:48 +00004338 """
4339 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4340 :param logging_text:
4341 :param db_nslcmop:
4342 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4343 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4344 :param vca_index: index in the database _admin.deployed.VCA
4345 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004346 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4347 not executed properly
aktas13251562021-02-12 22:19:10 +03004348 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004349 :return: None or exception
4350 """
tiernoe876f672020-02-13 14:34:48 +00004351
tierno588547c2020-07-01 15:30:20 +00004352 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004353 logging_text
4354 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004355 vca_index, vca_deployed, config_descriptor, destroy_ee
4356 )
4357 )
4358
4359 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4360
4361 # execute terminate_primitives
4362 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004363 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004364 config_descriptor.get("terminate-config-primitive"),
4365 vca_deployed.get("ee_descriptor_id"),
4366 )
tierno588547c2020-07-01 15:30:20 +00004367 vdu_id = vca_deployed.get("vdu_id")
4368 vdu_count_index = vca_deployed.get("vdu_count_index")
4369 vdu_name = vca_deployed.get("vdu_name")
4370 vnf_index = vca_deployed.get("member-vnf-index")
4371 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004372 for seq in terminate_primitives:
4373 # For each sequence in list, get primitive and call _ns_execute_primitive()
4374 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004375 vnf_index, seq.get("name")
4376 )
tierno588547c2020-07-01 15:30:20 +00004377 self.logger.debug(logging_text + step)
4378 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004379 primitive = seq.get("name")
4380 mapped_primitive_params = self._get_terminate_primitive_params(
4381 seq, vnf_index
4382 )
tierno588547c2020-07-01 15:30:20 +00004383
4384 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004385 self._add_suboperation(
4386 db_nslcmop,
4387 vnf_index,
4388 vdu_id,
4389 vdu_count_index,
4390 vdu_name,
4391 primitive,
4392 mapped_primitive_params,
4393 )
tierno588547c2020-07-01 15:30:20 +00004394 # Sub-operations: Call _ns_execute_primitive() instead of action()
4395 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004396 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004397 vca_deployed["ee_id"],
4398 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004399 mapped_primitive_params,
4400 vca_type=vca_type,
4401 vca_id=vca_id,
4402 )
tierno588547c2020-07-01 15:30:20 +00004403 except LcmException:
4404 # this happens when VCA is not deployed. In this case it is not needed to terminate
4405 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004406 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004407 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004408 raise LcmException(
4409 "terminate_primitive {} for vnf_member_index={} fails with "
4410 "error {}".format(seq.get("name"), vnf_index, result_detail)
4411 )
tierno588547c2020-07-01 15:30:20 +00004412 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004413 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4414 vca_index
4415 )
4416 self.update_db_2(
4417 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4418 )
tiernoe876f672020-02-13 14:34:48 +00004419
bravof73bac502021-05-11 07:38:47 -04004420 # Delete Prometheus Jobs if any
4421 # This uses NSR_ID, so it will destroy any jobs under this index
4422 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004423
tiernoe876f672020-02-13 14:34:48 +00004424 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004425 await self.vca_map[vca_type].delete_execution_environment(
4426 vca_deployed["ee_id"],
4427 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004428 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004429 vca_id=vca_id,
4430 )
kuuse0ca67472019-05-13 15:59:27 +02004431
David Garciac1fe90a2021-03-31 19:12:02 +02004432 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004433 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004434 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004435 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004436 await self.n2vc.delete_namespace(
4437 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004438 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004439 vca_id=vca_id,
4440 )
tiernof59ad6c2020-04-08 12:50:52 +00004441 except N2VCNotFound: # already deleted. Skip
4442 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004443 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004444
tiernoe876f672020-02-13 14:34:48 +00004445 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004446 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004447 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004448 if not task_is_locked_by_me:
4449 return
4450
tierno59d22d22018-09-25 18:10:19 +02004451 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4452 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004453 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004454 db_nsr = None
4455 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004456 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004457 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004458 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004459 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004460 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004461 tasks_dict_info = {}
4462 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004463 stage = [
4464 "Stage 1/3: Preparing task.",
4465 "Waiting for previous operations to terminate.",
4466 "",
4467 ]
tiernoe876f672020-02-13 14:34:48 +00004468 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004469 try:
kuused124bfe2019-06-18 12:09:24 +02004470 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004471 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004472
tiernoe876f672020-02-13 14:34:48 +00004473 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4474 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4475 operation_params = db_nslcmop.get("operationParams") or {}
4476 if operation_params.get("timeout_ns_terminate"):
4477 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4478 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4479 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4480
4481 db_nsr_update["operational-status"] = "terminating"
4482 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004483 self._write_ns_status(
4484 nsr_id=nsr_id,
4485 ns_state="TERMINATING",
4486 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004487 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004488 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004489 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004490 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004491 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004492 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4493 return
tierno59d22d22018-09-25 18:10:19 +02004494
tiernoe876f672020-02-13 14:34:48 +00004495 stage[1] = "Getting vnf descriptors from db."
4496 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004497 db_vnfrs_dict = {
4498 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4499 }
tiernoe876f672020-02-13 14:34:48 +00004500 db_vnfds_from_id = {}
4501 db_vnfds_from_member_index = {}
4502 # Loop over VNFRs
4503 for vnfr in db_vnfrs_list:
4504 vnfd_id = vnfr["vnfd-id"]
4505 if vnfd_id not in db_vnfds_from_id:
4506 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4507 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004508 db_vnfds_from_member_index[
4509 vnfr["member-vnf-index-ref"]
4510 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004511
tiernoe876f672020-02-13 14:34:48 +00004512 # Destroy individual execution environments when there are terminating primitives.
4513 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004514 # TODO - check before calling _destroy_N2VC
4515 # if not operation_params.get("skip_terminate_primitives"):#
4516 # or not vca.get("needed_terminate"):
4517 stage[0] = "Stage 2/3 execute terminating primitives."
4518 self.logger.debug(logging_text + stage[0])
4519 stage[1] = "Looking execution environment that needs terminate."
4520 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004521
tierno588547c2020-07-01 15:30:20 +00004522 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004523 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004524 vca_member_vnf_index = vca.get("member-vnf-index")
4525 vca_id = self.get_vca_id(
4526 db_vnfrs_dict.get(vca_member_vnf_index)
4527 if vca_member_vnf_index
4528 else None,
4529 db_nsr,
4530 )
tierno588547c2020-07-01 15:30:20 +00004531 if not vca or not vca.get("ee_id"):
4532 continue
4533 if not vca.get("member-vnf-index"):
4534 # ns
4535 config_descriptor = db_nsr.get("ns-configuration")
4536 elif vca.get("vdu_id"):
4537 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004538 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004539 elif vca.get("kdu_name"):
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("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004542 else:
bravofe5a31bc2021-02-17 19:09:12 -03004543 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004544 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004545 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004546 exec_terminate_primitives = not operation_params.get(
4547 "skip_terminate_primitives"
4548 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004549 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4550 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004551 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004552 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4553 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004554 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004555 self.destroy_N2VC(
4556 logging_text,
4557 db_nslcmop,
4558 vca,
4559 config_descriptor,
4560 vca_index,
4561 destroy_ee,
4562 exec_terminate_primitives,
4563 vca_id=vca_id,
4564 )
4565 )
tierno588547c2020-07-01 15:30:20 +00004566 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004567
tierno588547c2020-07-01 15:30:20 +00004568 # wait for pending tasks of terminate primitives
4569 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004570 self.logger.debug(
4571 logging_text
4572 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4573 )
4574 error_list = await self._wait_for_tasks(
4575 logging_text,
4576 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004577 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004578 stage,
4579 nslcmop_id,
4580 )
tierno86e33612020-09-16 14:13:06 +00004581 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004582 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004583 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004584
tiernoe876f672020-02-13 14:34:48 +00004585 # remove All execution environments at once
4586 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004587
tierno49676be2020-04-07 16:34:35 +00004588 if nsr_deployed.get("VCA"):
4589 stage[1] = "Deleting all execution environments."
4590 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004591 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4592 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004593 # Delete Namespace and Certificates
4594 await self.vca_map["helm-v3"].delete_tls_certificate(
4595 namespace=db_nslcmop["nsInstanceId"],
4596 certificate_name=self.EE_TLS_NAME,
4597 )
4598 await self.vca_map["helm-v3"].delete_namespace(
4599 namespace=db_nslcmop["nsInstanceId"],
4600 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004601 else:
4602 vca_id = self.get_vca_id({}, db_nsr)
4603 task_delete_ee = asyncio.ensure_future(
4604 asyncio.wait_for(
4605 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4606 timeout=self.timeout.charm_delete,
4607 )
4608 )
4609 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004610
tiernoe876f672020-02-13 14:34:48 +00004611 # Delete from k8scluster
4612 stage[1] = "Deleting KDUs."
4613 self.logger.debug(logging_text + stage[1])
4614 # print(nsr_deployed)
4615 for kdu in get_iterable(nsr_deployed, "K8s"):
4616 if not kdu or not kdu.get("kdu-instance"):
4617 continue
4618 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004619 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004620 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4621 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004622 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004623 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4624 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004625 kdu_instance=kdu_instance,
4626 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004627 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004628 )
4629 )
tiernoe876f672020-02-13 14:34:48 +00004630 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004631 self.logger.error(
4632 logging_text
4633 + "Unknown k8s deployment type {}".format(
4634 kdu.get("k8scluster-type")
4635 )
4636 )
tiernoe876f672020-02-13 14:34:48 +00004637 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004638 tasks_dict_info[
4639 task_delete_kdu_instance
4640 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004641
4642 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004643 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004644 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004645 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004646 self._terminate_ng_ro(
4647 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4648 )
4649 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004650 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004651
tiernoe876f672020-02-13 14:34:48 +00004652 # rest of staff will be done at finally
4653
garciadeblas5697b8b2021-03-24 09:17:02 +01004654 except (
4655 ROclient.ROClientException,
4656 DbException,
4657 LcmException,
4658 N2VCException,
4659 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004660 self.logger.error(logging_text + "Exit Exception {}".format(e))
4661 exc = e
4662 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004663 self.logger.error(
4664 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4665 )
tiernoe876f672020-02-13 14:34:48 +00004666 exc = "Operation was cancelled"
4667 except Exception as e:
4668 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004669 self.logger.critical(
4670 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4671 exc_info=True,
4672 )
tiernoe876f672020-02-13 14:34:48 +00004673 finally:
4674 if exc:
4675 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004676 try:
tiernoe876f672020-02-13 14:34:48 +00004677 # wait for pending tasks
4678 if tasks_dict_info:
4679 stage[1] = "Waiting for terminate pending tasks."
4680 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004681 error_list += await self._wait_for_tasks(
4682 logging_text,
4683 tasks_dict_info,
4684 timeout_ns_terminate,
4685 stage,
4686 nslcmop_id,
4687 )
tiernoe876f672020-02-13 14:34:48 +00004688 stage[1] = stage[2] = ""
4689 except asyncio.CancelledError:
4690 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004691 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4692 await self._wait_for_tasks(
4693 logging_text,
4694 tasks_dict_info,
4695 timeout_ns_terminate,
4696 stage,
4697 nslcmop_id,
4698 )
tiernoe876f672020-02-13 14:34:48 +00004699 except Exception as exc:
4700 error_list.append(str(exc))
4701 # update status at database
4702 if error_list:
4703 error_detail = "; ".join(error_list)
4704 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004705 error_description_nslcmop = "{} Detail: {}".format(
4706 stage[0], error_detail
4707 )
4708 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4709 nslcmop_id, stage[0]
4710 )
tierno59d22d22018-09-25 18:10:19 +02004711
tierno59d22d22018-09-25 18:10:19 +02004712 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004713 db_nsr_update["detailed-status"] = (
4714 error_description_nsr + " Detail: " + error_detail
4715 )
tiernoe876f672020-02-13 14:34:48 +00004716 db_nslcmop_update["detailed-status"] = error_detail
4717 nslcmop_operation_state = "FAILED"
4718 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004719 else:
tiernoa2143262020-03-27 16:20:40 +00004720 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004721 error_description_nsr = error_description_nslcmop = None
4722 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004723 db_nsr_update["operational-status"] = "terminated"
4724 db_nsr_update["detailed-status"] = "Done"
4725 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4726 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004727 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004728
tiernoe876f672020-02-13 14:34:48 +00004729 if db_nsr:
4730 self._write_ns_status(
4731 nsr_id=nsr_id,
4732 ns_state=ns_state,
4733 current_operation="IDLE",
4734 current_operation_id=None,
4735 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004736 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004737 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004738 )
tiernoa17d4f42020-04-28 09:59:23 +00004739 self._write_op_status(
4740 op_id=nslcmop_id,
4741 stage="",
4742 error_message=error_description_nslcmop,
4743 operation_state=nslcmop_operation_state,
4744 other_update=db_nslcmop_update,
4745 )
Rahul Kumar54671c52024-05-09 15:34:01 +05304746 if nslcmop_operation_state == "COMPLETED":
4747 self.db.del_list("prometheus_jobs", {"nsr_id": nsr_id})
lloretgalleg6d488782020-07-22 10:13:46 +00004748 if ns_state == "NOT_INSTANTIATED":
4749 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004750 self.db.set_list(
4751 "vnfrs",
4752 {"nsr-id-ref": nsr_id},
4753 {"_admin.nsState": "NOT_INSTANTIATED"},
4754 )
lloretgalleg6d488782020-07-22 10:13:46 +00004755 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004756 self.logger.warn(
4757 logging_text
4758 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4759 nsr_id, e
4760 )
4761 )
tiernoa17d4f42020-04-28 09:59:23 +00004762 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004763 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004764 if nslcmop_operation_state:
4765 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004766 await self.msg.aiowrite(
4767 "ns",
4768 "terminated",
4769 {
4770 "nsr_id": nsr_id,
4771 "nslcmop_id": nslcmop_id,
4772 "operationState": nslcmop_operation_state,
4773 "autoremove": autoremove,
4774 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004775 )
tierno59d22d22018-09-25 18:10:19 +02004776 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004777 self.logger.error(
4778 logging_text + "kafka_write notification Exception {}".format(e)
4779 )
aguilard1ae3c562023-02-16 17:24:35 +00004780 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4781 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004782
tierno59d22d22018-09-25 18:10:19 +02004783 self.logger.debug(logging_text + "Exit")
4784 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4785
garciadeblas5697b8b2021-03-24 09:17:02 +01004786 async def _wait_for_tasks(
4787 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4788 ):
tiernoe876f672020-02-13 14:34:48 +00004789 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004790 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004791 error_list = []
4792 pending_tasks = list(created_tasks_info.keys())
4793 num_tasks = len(pending_tasks)
4794 num_done = 0
4795 stage[1] = "{}/{}.".format(num_done, num_tasks)
4796 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004797 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004798 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004799 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004800 done, pending_tasks = await asyncio.wait(
4801 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4802 )
tiernoe876f672020-02-13 14:34:48 +00004803 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004804 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004805 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004806 new_error = created_tasks_info[task] + ": Timeout"
4807 error_detail_list.append(new_error)
4808 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004809 break
4810 for task in done:
4811 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004812 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004813 else:
4814 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004815 if exc:
4816 if isinstance(exc, asyncio.TimeoutError):
4817 exc = "Timeout"
4818 new_error = created_tasks_info[task] + ": {}".format(exc)
4819 error_list.append(created_tasks_info[task])
4820 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004821 if isinstance(
4822 exc,
4823 (
4824 str,
4825 DbException,
4826 N2VCException,
4827 ROclient.ROClientException,
4828 LcmException,
4829 K8sException,
4830 NgRoException,
4831 ),
4832 ):
tierno067e04a2020-03-31 12:53:13 +00004833 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004834 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004835 exc_traceback = "".join(
4836 traceback.format_exception(None, exc, exc.__traceback__)
4837 )
4838 self.logger.error(
4839 logging_text
4840 + created_tasks_info[task]
4841 + " "
4842 + exc_traceback
4843 )
tierno067e04a2020-03-31 12:53:13 +00004844 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004845 self.logger.debug(
4846 logging_text + created_tasks_info[task] + ": Done"
4847 )
tiernoe876f672020-02-13 14:34:48 +00004848 stage[1] = "{}/{}.".format(num_done, num_tasks)
4849 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004850 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004851 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004852 self.update_db_2(
4853 "nsrs",
4854 nsr_id,
4855 {
4856 "errorDescription": "Error at: " + ", ".join(error_list),
4857 "errorDetail": ". ".join(error_detail_list),
4858 },
4859 )
tiernoe876f672020-02-13 14:34:48 +00004860 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004861 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004862
Gabriel Cubab6049d32023-10-30 13:44:49 -05004863 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4864 for task, name in created_tasks_info.items():
4865 self.logger.debug(logging_text + "Cancelling task: " + name)
4866 task.cancel()
4867
tiernoda1ff8c2020-10-22 14:12:46 +00004868 @staticmethod
4869 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004870 """
4871 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4872 The default-value is used. If it is between < > it look for a value at instantiation_params
4873 :param primitive_desc: portion of VNFD/NSD that describes primitive
4874 :param params: Params provided by user
4875 :param instantiation_params: Instantiation params provided by user
4876 :return: a dictionary with the calculated params
4877 """
4878 calculated_params = {}
4879 for parameter in primitive_desc.get("parameter", ()):
4880 param_name = parameter["name"]
4881 if param_name in params:
4882 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004883 elif "default-value" in parameter or "value" in parameter:
4884 if "value" in parameter:
4885 calculated_params[param_name] = parameter["value"]
4886 else:
4887 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004888 if (
4889 isinstance(calculated_params[param_name], str)
4890 and calculated_params[param_name].startswith("<")
4891 and calculated_params[param_name].endswith(">")
4892 ):
tierno98ad6ea2019-05-30 17:16:28 +00004893 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004894 calculated_params[param_name] = instantiation_params[
4895 calculated_params[param_name][1:-1]
4896 ]
tiernoda964822019-01-14 15:53:47 +00004897 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004898 raise LcmException(
4899 "Parameter {} needed to execute primitive {} not provided".format(
4900 calculated_params[param_name], primitive_desc["name"]
4901 )
4902 )
tiernoda964822019-01-14 15:53:47 +00004903 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004904 raise LcmException(
4905 "Parameter {} needed to execute primitive {} not provided".format(
4906 param_name, primitive_desc["name"]
4907 )
4908 )
tierno59d22d22018-09-25 18:10:19 +02004909
tiernoda964822019-01-14 15:53:47 +00004910 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004911 calculated_params[param_name] = yaml.safe_dump(
4912 calculated_params[param_name], default_flow_style=True, width=256
4913 )
4914 elif isinstance(calculated_params[param_name], str) and calculated_params[
4915 param_name
4916 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004917 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004918 if parameter.get("data-type") == "INTEGER":
4919 try:
4920 calculated_params[param_name] = int(calculated_params[param_name])
4921 except ValueError: # error converting string to int
4922 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004923 "Parameter {} of primitive {} must be integer".format(
4924 param_name, primitive_desc["name"]
4925 )
4926 )
tiernofa40e692020-10-14 14:59:36 +00004927 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004928 calculated_params[param_name] = not (
4929 (str(calculated_params[param_name])).lower() == "false"
4930 )
tiernoc3f2a822019-11-05 13:45:04 +00004931
4932 # add always ns_config_info if primitive name is config
4933 if primitive_desc["name"] == "config":
4934 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004935 calculated_params["ns_config_info"] = instantiation_params[
4936 "ns_config_info"
4937 ]
tiernoda964822019-01-14 15:53:47 +00004938 return calculated_params
4939
garciadeblas5697b8b2021-03-24 09:17:02 +01004940 def _look_for_deployed_vca(
4941 self,
4942 deployed_vca,
4943 member_vnf_index,
4944 vdu_id,
4945 vdu_count_index,
4946 kdu_name=None,
4947 ee_descriptor_id=None,
4948 ):
tiernoe876f672020-02-13 14:34:48 +00004949 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4950 for vca in deployed_vca:
4951 if not vca:
4952 continue
4953 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4954 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004955 if (
4956 vdu_count_index is not None
4957 and vdu_count_index != vca["vdu_count_index"]
4958 ):
tiernoe876f672020-02-13 14:34:48 +00004959 continue
4960 if kdu_name and kdu_name != vca["kdu_name"]:
4961 continue
tiernoa278b842020-07-08 15:33:55 +00004962 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4963 continue
tiernoe876f672020-02-13 14:34:48 +00004964 break
4965 else:
4966 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004967 raise LcmException(
4968 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4969 " is not deployed".format(
4970 member_vnf_index,
4971 vdu_id,
4972 vdu_count_index,
4973 kdu_name,
4974 ee_descriptor_id,
4975 )
4976 )
tiernoe876f672020-02-13 14:34:48 +00004977 # get ee_id
4978 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004979 vca_type = vca.get(
4980 "type", "lxc_proxy_charm"
4981 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004982 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004983 raise LcmException(
4984 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4985 "execution environment".format(
4986 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4987 )
4988 )
tierno588547c2020-07-01 15:30:20 +00004989 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004990
David Garciac1fe90a2021-03-31 19:12:02 +02004991 async def _ns_execute_primitive(
4992 self,
4993 ee_id,
4994 primitive,
4995 primitive_params,
4996 retries=0,
4997 retries_interval=30,
4998 timeout=None,
4999 vca_type=None,
5000 db_dict=None,
5001 vca_id: str = None,
5002 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005003 try:
tierno98ad6ea2019-05-30 17:16:28 +00005004 if primitive == "config":
5005 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005006
tierno588547c2020-07-01 15:30:20 +00005007 vca_type = vca_type or "lxc_proxy_charm"
5008
quilesj7e13aeb2019-10-08 13:34:55 +02005009 while retries >= 0:
5010 try:
tierno067e04a2020-03-31 12:53:13 +00005011 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005012 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005013 ee_id=ee_id,
5014 primitive_name=primitive,
5015 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005016 progress_timeout=self.timeout.progress_primitive,
5017 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005018 db_dict=db_dict,
5019 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005020 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005021 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005022 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005023 )
quilesj7e13aeb2019-10-08 13:34:55 +02005024 # execution was OK
5025 break
tierno067e04a2020-03-31 12:53:13 +00005026 except asyncio.CancelledError:
5027 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005028 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005029 retries -= 1
5030 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005031 self.logger.debug(
5032 "Error executing action {} on {} -> {}".format(
5033 primitive, ee_id, e
5034 )
5035 )
quilesj7e13aeb2019-10-08 13:34:55 +02005036 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005037 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005038 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005039 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005040 e = N2VCException(
5041 message="Timed out waiting for action to complete"
5042 )
5043 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005044
garciadeblas5697b8b2021-03-24 09:17:02 +01005045 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005046
tierno067e04a2020-03-31 12:53:13 +00005047 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005048 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005049 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005050 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005051
ksaikiranr3fde2c72021-03-15 10:39:06 +05305052 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5053 """
5054 Updating the vca_status with latest juju information in nsrs record
5055 :param: nsr_id: Id of the nsr
5056 :param: nslcmop_id: Id of the nslcmop
5057 :return: None
5058 """
5059
5060 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5061 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005062 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005063 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005064 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5065 cluster_uuid, kdu_instance, cluster_type = (
5066 k8s["k8scluster-uuid"],
5067 k8s["kdu-instance"],
5068 k8s["k8scluster-type"],
5069 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005070 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005071 cluster_uuid=cluster_uuid,
5072 kdu_instance=kdu_instance,
5073 filter={"_id": nsr_id},
5074 vca_id=vca_id,
5075 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005076 )
3697083243632024-06-07 05:44:08 +00005077 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005078 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305079 table, filter = "nsrs", {"_id": nsr_id}
5080 path = "_admin.deployed.VCA.{}.".format(vca_index)
5081 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305082
5083 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5084 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5085
tierno59d22d22018-09-25 18:10:19 +02005086 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005087 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005088 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005089 if not task_is_locked_by_me:
5090 return
5091
tierno59d22d22018-09-25 18:10:19 +02005092 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5093 self.logger.debug(logging_text + "Enter")
5094 # get all needed from database
5095 db_nsr = None
5096 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005097 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005098 db_nslcmop_update = {}
5099 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005100 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005101 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005102 step = ""
tierno59d22d22018-09-25 18:10:19 +02005103 try:
kuused124bfe2019-06-18 12:09:24 +02005104 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005105 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005106 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005107
quilesj4cda56b2019-12-05 10:02:20 +00005108 self._write_ns_status(
5109 nsr_id=nsr_id,
5110 ns_state=None,
5111 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005112 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005113 )
5114
tierno59d22d22018-09-25 18:10:19 +02005115 step = "Getting information from database"
5116 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5117 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005118 if db_nslcmop["operationParams"].get("primitive_params"):
5119 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5120 db_nslcmop["operationParams"]["primitive_params"]
5121 )
tiernoda964822019-01-14 15:53:47 +00005122
tiernoe4f7e6c2018-11-27 14:55:30 +00005123 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005124 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005125 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005126 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005127 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005128 primitive = db_nslcmop["operationParams"]["primitive"]
5129 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005130 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005131 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005132 )
tierno59d22d22018-09-25 18:10:19 +02005133
tierno1b633412019-02-25 16:48:23 +00005134 if vnf_index:
5135 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005136 db_vnfr = self.db.get_one(
5137 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5138 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005139 if db_vnfr.get("kdur"):
5140 kdur_list = []
5141 for kdur in db_vnfr["kdur"]:
5142 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005143 kdur["additionalParams"] = json.loads(
5144 kdur["additionalParams"]
5145 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005146 kdur_list.append(kdur)
5147 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005148 step = "Getting vnfd from database"
5149 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005150
5151 # Sync filesystem before running a primitive
5152 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005153 else:
tierno067e04a2020-03-31 12:53:13 +00005154 step = "Getting nsd from database"
5155 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005156
David Garciac1fe90a2021-03-31 19:12:02 +02005157 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005158 # for backward compatibility
5159 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5160 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5161 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5162 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5163
tiernoda964822019-01-14 15:53:47 +00005164 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005165 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005166 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005167 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005168 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005169 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005170 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005171 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005172 else:
tiernoa278b842020-07-08 15:33:55 +00005173 descriptor_configuration = db_nsd.get("ns-configuration")
5174
garciadeblas5697b8b2021-03-24 09:17:02 +01005175 if descriptor_configuration and descriptor_configuration.get(
5176 "config-primitive"
5177 ):
tiernoa278b842020-07-08 15:33:55 +00005178 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005179 if config_primitive["name"] == primitive:
5180 config_primitive_desc = config_primitive
5181 break
tiernoda964822019-01-14 15:53:47 +00005182
garciadeblas6bed6b32020-07-20 11:05:42 +00005183 if not config_primitive_desc:
5184 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005185 raise LcmException(
5186 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5187 primitive
5188 )
5189 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005190 primitive_name = primitive
5191 ee_descriptor_id = None
5192 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005193 primitive_name = config_primitive_desc.get(
5194 "execution-environment-primitive", primitive
5195 )
5196 ee_descriptor_id = config_primitive_desc.get(
5197 "execution-environment-ref"
5198 )
tierno1b633412019-02-25 16:48:23 +00005199
tierno1b633412019-02-25 16:48:23 +00005200 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005201 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005202 vdur = next(
5203 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5204 )
bravof922c4172020-11-24 21:21:43 -03005205 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005206 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005207 kdur = next(
5208 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5209 )
bravof922c4172020-11-24 21:21:43 -03005210 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005211 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005212 desc_params = parse_yaml_strings(
5213 db_vnfr.get("additionalParamsForVnf")
5214 )
tierno1b633412019-02-25 16:48:23 +00005215 else:
bravof922c4172020-11-24 21:21:43 -03005216 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005217 if kdu_name and get_configuration(db_vnfd, kdu_name):
5218 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005219 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005220 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005221 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005222 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005223 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005224 kdu = find_in_list(
5225 nsr_deployed["K8s"],
5226 lambda kdu: kdu_name == kdu["kdu-name"]
5227 and kdu["member-vnf-index"] == vnf_index,
5228 )
5229 kdu_action = (
5230 True
5231 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005232 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005233 else False
5234 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005235
tiernoda964822019-01-14 15:53:47 +00005236 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005237 if kdu_name and (
5238 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5239 ):
tierno067e04a2020-03-31 12:53:13 +00005240 # TODO Check if we will need something at vnf level
5241 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005242 if (
5243 kdu_name == kdu["kdu-name"]
5244 and kdu["member-vnf-index"] == vnf_index
5245 ):
tierno067e04a2020-03-31 12:53:13 +00005246 break
5247 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005248 raise LcmException(
5249 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5250 )
quilesj7e13aeb2019-10-08 13:34:55 +02005251
tierno067e04a2020-03-31 12:53:13 +00005252 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005253 msg = "unknown k8scluster-type '{}'".format(
5254 kdu.get("k8scluster-type")
5255 )
tierno067e04a2020-03-31 12:53:13 +00005256 raise LcmException(msg)
5257
garciadeblas5697b8b2021-03-24 09:17:02 +01005258 db_dict = {
5259 "collection": "nsrs",
5260 "filter": {"_id": nsr_id},
5261 "path": "_admin.deployed.K8s.{}".format(index),
5262 }
5263 self.logger.debug(
5264 logging_text
5265 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5266 )
tiernoa278b842020-07-08 15:33:55 +00005267 step = "Executing kdu {}".format(primitive_name)
garciadeblas8eb84d52024-07-19 12:08:07 +02005268 if primitive_name == "upgrade" and primitive_params:
5269 if primitive_params.get("kdu_model"):
5270 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005271 else:
5272 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005273 if kdu_model.count("/") < 2: # helm chart is not embedded
5274 parts = kdu_model.split(sep=":")
5275 if len(parts) == 2:
5276 kdu_model = parts[0]
garciadeblas8eb84d52024-07-19 12:08:07 +02005277 if primitive_params.get("kdu_atomic_upgrade"):
5278 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005279 "kdu_atomic_upgrade"
5280 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005281 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005282 else:
5283 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005284 # Type of upgrade: reset, reuse, reset_then_reuse
5285 reset_values = False
5286 reuse_values = False
5287 reset_then_reuse_values = False
5288 # If no option is specified, default behaviour is reuse_values
5289 # Otherwise, options will be parsed and used
5290 if (
garciadeblas8eb84d52024-07-19 12:08:07 +02005291 ("kdu_reset_values" not in primitive_params)
5292 and ("kdu_reuse_values" not in primitive_params)
5293 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasb891d382024-02-08 14:11:51 +01005294 ):
5295 reuse_values = True
5296 else:
garciadeblas8eb84d52024-07-19 12:08:07 +02005297 if primitive_params.get("kdu_reset_values"):
5298 reset_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005299 "kdu_reset_values"
5300 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005301 if primitive_params.get("kdu_reuse_values"):
5302 reuse_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005303 "kdu_reuse_values"
5304 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005305 if primitive_params.get("kdu_reset_then_reuse_values"):
5306 reset_then_reuse_values = primitive_params.get(
garciadeblasb891d382024-02-08 14:11:51 +01005307 "kdu_reset_then_reuse_values"
5308 ).lower() in ("yes", "true", "1")
5309 # Two true options are not possible
5310 if (
5311 sum([reset_values, reuse_values, reset_then_reuse_values])
5312 >= 2
5313 ):
5314 raise LcmException(
5315 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5316 )
garciadeblas8eb84d52024-07-19 12:08:07 +02005317 # kdur and desc_params already set from before
5318 if reset_values:
5319 desc_params = primitive_params
5320 else:
5321 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005322 detailed_status = await asyncio.wait_for(
5323 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5324 cluster_uuid=kdu.get("k8scluster-uuid"),
5325 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005326 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005327 reset_values=reset_values,
5328 reuse_values=reuse_values,
5329 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005330 kdu_model=kdu_model,
5331 params=desc_params,
5332 db_dict=db_dict,
5333 timeout=timeout_ns_action,
5334 ),
5335 timeout=timeout_ns_action + 10,
5336 )
5337 self.logger.debug(
5338 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5339 )
tiernoa278b842020-07-08 15:33:55 +00005340 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005341 detailed_status = await asyncio.wait_for(
5342 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5343 cluster_uuid=kdu.get("k8scluster-uuid"),
5344 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005345 db_dict=db_dict,
5346 ),
5347 timeout=timeout_ns_action,
5348 )
tiernoa278b842020-07-08 15:33:55 +00005349 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005350 detailed_status = await asyncio.wait_for(
5351 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5352 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005353 kdu_instance=kdu.get("kdu-instance"),
5354 vca_id=vca_id,
5355 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005356 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005357 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005358 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005359 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5360 kdu["kdu-name"], nsr_id
5361 )
5362 params = self._map_primitive_params(
5363 config_primitive_desc, primitive_params, desc_params
5364 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005365
5366 detailed_status = await asyncio.wait_for(
5367 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5368 cluster_uuid=kdu.get("k8scluster-uuid"),
5369 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005370 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005371 params=params,
5372 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005373 timeout=timeout_ns_action,
5374 vca_id=vca_id,
5375 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005376 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005377 )
tierno067e04a2020-03-31 12:53:13 +00005378
5379 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005380 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005381 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005382 detailed_status = ""
5383 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005384 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005385 ee_id, vca_type = self._look_for_deployed_vca(
5386 nsr_deployed["VCA"],
5387 member_vnf_index=vnf_index,
5388 vdu_id=vdu_id,
5389 vdu_count_index=vdu_count_index,
5390 ee_descriptor_id=ee_descriptor_id,
5391 )
5392 for vca_index, vca_deployed in enumerate(
5393 db_nsr["_admin"]["deployed"]["VCA"]
5394 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305395 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005396 db_dict = {
5397 "collection": "nsrs",
5398 "filter": {"_id": nsr_id},
5399 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5400 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305401 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005402 (
5403 nslcmop_operation_state,
5404 detailed_status,
5405 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005406 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005407 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005408 primitive_params=self._map_primitive_params(
5409 config_primitive_desc, primitive_params, desc_params
5410 ),
tierno588547c2020-07-01 15:30:20 +00005411 timeout=timeout_ns_action,
5412 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005413 db_dict=db_dict,
5414 vca_id=vca_id,
5415 )
tierno067e04a2020-03-31 12:53:13 +00005416
5417 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005418 error_description_nslcmop = (
5419 detailed_status if nslcmop_operation_state == "FAILED" else ""
5420 )
5421 self.logger.debug(
5422 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005423 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005424 nslcmop_operation_state, detailed_status
5425 )
5426 )
tierno59d22d22018-09-25 18:10:19 +02005427 return # database update is called inside finally
5428
tiernof59ad6c2020-04-08 12:50:52 +00005429 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005430 self.logger.error(logging_text + "Exit Exception {}".format(e))
5431 exc = e
5432 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005433 self.logger.error(
5434 logging_text + "Cancelled Exception while '{}'".format(step)
5435 )
tierno59d22d22018-09-25 18:10:19 +02005436 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005437 except asyncio.TimeoutError:
5438 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5439 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005440 except Exception as e:
5441 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005442 self.logger.critical(
5443 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5444 exc_info=True,
5445 )
tierno59d22d22018-09-25 18:10:19 +02005446 finally:
tierno067e04a2020-03-31 12:53:13 +00005447 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005448 db_nslcmop_update[
5449 "detailed-status"
5450 ] = (
5451 detailed_status
5452 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005453 nslcmop_operation_state = "FAILED"
5454 if db_nsr:
5455 self._write_ns_status(
5456 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005457 ns_state=db_nsr[
5458 "nsState"
5459 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005460 current_operation="IDLE",
5461 current_operation_id=None,
5462 # error_description=error_description_nsr,
5463 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005464 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005465 )
5466
garciadeblas5697b8b2021-03-24 09:17:02 +01005467 self._write_op_status(
5468 op_id=nslcmop_id,
5469 stage="",
5470 error_message=error_description_nslcmop,
5471 operation_state=nslcmop_operation_state,
5472 other_update=db_nslcmop_update,
5473 )
tierno067e04a2020-03-31 12:53:13 +00005474
tierno59d22d22018-09-25 18:10:19 +02005475 if nslcmop_operation_state:
5476 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005477 await self.msg.aiowrite(
5478 "ns",
5479 "actioned",
5480 {
5481 "nsr_id": nsr_id,
5482 "nslcmop_id": nslcmop_id,
5483 "operationState": nslcmop_operation_state,
5484 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005485 )
tierno59d22d22018-09-25 18:10:19 +02005486 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005487 self.logger.error(
5488 logging_text + "kafka_write notification Exception {}".format(e)
5489 )
tierno59d22d22018-09-25 18:10:19 +02005490 self.logger.debug(logging_text + "Exit")
5491 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005492 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005493
elumalaica7ece02022-04-12 12:47:32 +05305494 async def terminate_vdus(
5495 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5496 ):
5497 """This method terminates VDUs
5498
5499 Args:
5500 db_vnfr: VNF instance record
5501 member_vnf_index: VNF index to identify the VDUs to be removed
5502 db_nsr: NS instance record
5503 update_db_nslcmops: Nslcmop update record
5504 """
5505 vca_scaling_info = []
5506 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5507 scaling_info["scaling_direction"] = "IN"
5508 scaling_info["vdu-delete"] = {}
5509 scaling_info["kdu-delete"] = {}
5510 db_vdur = db_vnfr.get("vdur")
5511 vdur_list = copy(db_vdur)
5512 count_index = 0
5513 for index, vdu in enumerate(vdur_list):
5514 vca_scaling_info.append(
5515 {
5516 "osm_vdu_id": vdu["vdu-id-ref"],
5517 "member-vnf-index": member_vnf_index,
5518 "type": "delete",
5519 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005520 }
5521 )
elumalaica7ece02022-04-12 12:47:32 +05305522 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5523 scaling_info["vdu"].append(
5524 {
5525 "name": vdu.get("name") or vdu.get("vdu-name"),
5526 "vdu_id": vdu["vdu-id-ref"],
5527 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005528 }
5529 )
elumalaica7ece02022-04-12 12:47:32 +05305530 for interface in vdu["interfaces"]:
5531 scaling_info["vdu"][index]["interface"].append(
5532 {
5533 "name": interface["name"],
5534 "ip_address": interface["ip-address"],
5535 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005536 }
5537 )
elumalaica7ece02022-04-12 12:47:32 +05305538 self.logger.info("NS update scaling info{}".format(scaling_info))
5539 stage[2] = "Terminating VDUs"
5540 if scaling_info.get("vdu-delete"):
5541 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005542 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305543 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005544 logging_text,
5545 db_nsr,
5546 update_db_nslcmops,
5547 db_vnfr,
5548 scaling_info,
5549 stage,
elumalaica7ece02022-04-12 12:47:32 +05305550 )
5551
preethika.p28b0bf82022-09-23 07:36:28 +00005552 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305553 """This method is to Remove VNF instances from NS.
5554
5555 Args:
5556 nsr_id: NS instance id
5557 nslcmop_id: nslcmop id of update
5558 vnf_instance_id: id of the VNF instance to be removed
5559
5560 Returns:
5561 result: (str, str) COMPLETED/FAILED, details
5562 """
5563 try:
5564 db_nsr_update = {}
5565 logging_text = "Task ns={} update ".format(nsr_id)
5566 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5567 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5568 if check_vnfr_count > 1:
5569 stage = ["", "", ""]
5570 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005571 self.logger.debug(
5572 step + " after having waited for previous tasks to be completed"
5573 )
elumalaica7ece02022-04-12 12:47:32 +05305574 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5575 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5576 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5577 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5578 """ db_vnfr = self.db.get_one(
5579 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5580
5581 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005582 await self.terminate_vdus(
5583 db_vnfr,
5584 member_vnf_index,
5585 db_nsr,
5586 update_db_nslcmops,
5587 stage,
5588 logging_text,
5589 )
elumalaica7ece02022-04-12 12:47:32 +05305590
5591 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5592 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005593 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5594 "constituent-vnfr-ref"
5595 )
elumalaica7ece02022-04-12 12:47:32 +05305596 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5597 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5598 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5599 return "COMPLETED", "Done"
5600 else:
5601 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005602 raise LcmException(
5603 "{} Cannot terminate the last VNF in this NS.".format(
5604 vnf_instance_id
5605 )
5606 )
elumalaica7ece02022-04-12 12:47:32 +05305607 except (LcmException, asyncio.CancelledError):
5608 raise
5609 except Exception as e:
5610 self.logger.debug("Error removing VNF {}".format(e))
5611 return "FAILED", "Error removing VNF {}".format(e)
5612
elumalaib9e357c2022-04-27 09:58:38 +05305613 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005614 self,
5615 nsr_id,
5616 nslcmop_id,
5617 db_vnfd,
5618 db_vnfr,
5619 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305620 ):
5621 """This method updates and redeploys VNF instances
5622
5623 Args:
5624 nsr_id: NS instance id
5625 nslcmop_id: nslcmop id
5626 db_vnfd: VNF descriptor
5627 db_vnfr: VNF instance record
5628 db_nsr: NS instance record
5629
5630 Returns:
5631 result: (str, str) COMPLETED/FAILED, details
5632 """
5633 try:
5634 count_index = 0
5635 stage = ["", "", ""]
5636 logging_text = "Task ns={} update ".format(nsr_id)
5637 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5638 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5639
5640 # Terminate old VNF resources
5641 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005642 await self.terminate_vdus(
5643 db_vnfr,
5644 member_vnf_index,
5645 db_nsr,
5646 update_db_nslcmops,
5647 stage,
5648 logging_text,
5649 )
elumalaib9e357c2022-04-27 09:58:38 +05305650
5651 # old_vnfd_id = db_vnfr["vnfd-id"]
5652 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5653 new_db_vnfd = db_vnfd
5654 # new_vnfd_ref = new_db_vnfd["id"]
5655 # new_vnfd_id = vnfd_id
5656
5657 # Create VDUR
5658 new_vnfr_cp = []
5659 for cp in new_db_vnfd.get("ext-cpd", ()):
5660 vnf_cp = {
5661 "name": cp.get("id"),
5662 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5663 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5664 "id": cp.get("id"),
5665 }
5666 new_vnfr_cp.append(vnf_cp)
5667 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5668 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5669 # 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 +00005670 new_vnfr_update = {
5671 "revision": latest_vnfd_revision,
5672 "connection-point": new_vnfr_cp,
5673 "vdur": new_vdur,
5674 "ip-address": "",
5675 }
elumalaib9e357c2022-04-27 09:58:38 +05305676 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5677 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005678 "vnfrs",
5679 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305680 )
5681
5682 # Instantiate new VNF resources
5683 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5684 vca_scaling_info = []
5685 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5686 scaling_info["scaling_direction"] = "OUT"
5687 scaling_info["vdu-create"] = {}
5688 scaling_info["kdu-create"] = {}
5689 vdud_instantiate_list = db_vnfd["vdu"]
5690 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005691 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305692 if cloud_init_text:
5693 additional_params = (
5694 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5695 or {}
5696 )
5697 cloud_init_list = []
5698 if cloud_init_text:
5699 # TODO Information of its own ip is not available because db_vnfr is not updated.
5700 additional_params["OSM"] = get_osm_params(
5701 updated_db_vnfr, vdud["id"], 1
5702 )
5703 cloud_init_list.append(
5704 self._parse_cloud_init(
5705 cloud_init_text,
5706 additional_params,
5707 db_vnfd["id"],
5708 vdud["id"],
5709 )
5710 )
5711 vca_scaling_info.append(
5712 {
5713 "osm_vdu_id": vdud["id"],
5714 "member-vnf-index": member_vnf_index,
5715 "type": "create",
5716 "vdu_index": count_index,
5717 }
5718 )
5719 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005720 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305721 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005722 "New Resources to be deployed: {}".format(scaling_info)
5723 )
elumalaib9e357c2022-04-27 09:58:38 +05305724 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005725 logging_text,
5726 db_nsr,
5727 update_db_nslcmops,
5728 updated_db_vnfr,
5729 scaling_info,
5730 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305731 )
5732 return "COMPLETED", "Done"
5733 except (LcmException, asyncio.CancelledError):
5734 raise
5735 except Exception as e:
5736 self.logger.debug("Error updating VNF {}".format(e))
5737 return "FAILED", "Error updating VNF {}".format(e)
5738
aticigdffa6212022-04-12 15:27:53 +03005739 async def _ns_charm_upgrade(
5740 self,
5741 ee_id,
5742 charm_id,
5743 charm_type,
5744 path,
5745 timeout: float = None,
5746 ) -> (str, str):
5747 """This method upgrade charms in VNF instances
5748
5749 Args:
5750 ee_id: Execution environment id
5751 path: Local path to the charm
5752 charm_id: charm-id
5753 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5754 timeout: (Float) Timeout for the ns update operation
5755
5756 Returns:
5757 result: (str, str) COMPLETED/FAILED, details
5758 """
5759 try:
5760 charm_type = charm_type or "lxc_proxy_charm"
5761 output = await self.vca_map[charm_type].upgrade_charm(
5762 ee_id=ee_id,
5763 path=path,
5764 charm_id=charm_id,
5765 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005766 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005767 )
5768
5769 if output:
5770 return "COMPLETED", output
5771
5772 except (LcmException, asyncio.CancelledError):
5773 raise
5774
5775 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005776 self.logger.debug("Error upgrading charm {}".format(path))
5777
5778 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5779
5780 async def update(self, nsr_id, nslcmop_id):
5781 """Update NS according to different update types
5782
5783 This method performs upgrade of VNF instances then updates the revision
5784 number in VNF record
5785
5786 Args:
5787 nsr_id: Network service will be updated
5788 nslcmop_id: ns lcm operation id
5789
5790 Returns:
5791 It may raise DbException, LcmException, N2VCException, K8sException
5792
5793 """
5794 # Try to lock HA task here
5795 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5796 if not task_is_locked_by_me:
5797 return
5798
5799 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5800 self.logger.debug(logging_text + "Enter")
5801
5802 # Set the required variables to be filled up later
5803 db_nsr = None
5804 db_nslcmop_update = {}
5805 vnfr_update = {}
5806 nslcmop_operation_state = None
5807 db_nsr_update = {}
5808 error_description_nslcmop = ""
5809 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305810 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005811 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005812 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005813
5814 try:
5815 # wait for any previous tasks in process
5816 step = "Waiting for previous operations to terminate"
5817 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5818 self._write_ns_status(
5819 nsr_id=nsr_id,
5820 ns_state=None,
5821 current_operation="UPDATING",
5822 current_operation_id=nslcmop_id,
5823 )
5824
5825 step = "Getting nslcmop from database"
5826 db_nslcmop = self.db.get_one(
5827 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5828 )
5829 update_type = db_nslcmop["operationParams"]["updateType"]
5830
5831 step = "Getting nsr from database"
5832 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5833 old_operational_status = db_nsr["operational-status"]
5834 db_nsr_update["operational-status"] = "updating"
5835 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5836 nsr_deployed = db_nsr["_admin"].get("deployed")
5837
5838 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005839 # Get the input parameters given through update request
5840 vnf_instance_id = db_nslcmop["operationParams"][
5841 "changeVnfPackageData"
5842 ].get("vnfInstanceId")
5843
5844 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5845 "vnfdId"
5846 )
5847 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5848
5849 step = "Getting vnfr from database"
5850 db_vnfr = self.db.get_one(
5851 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5852 )
5853
5854 step = "Getting vnfds from database"
5855 # Latest VNFD
5856 latest_vnfd = self.db.get_one(
5857 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5858 )
5859 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5860
5861 # Current VNFD
5862 current_vnf_revision = db_vnfr.get("revision", 1)
5863 current_vnfd = self.db.get_one(
5864 "vnfds_revisions",
5865 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5866 fail_on_empty=False,
5867 )
5868 # Charm artifact paths will be filled up later
5869 (
5870 current_charm_artifact_path,
5871 target_charm_artifact_path,
5872 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005873 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005874 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005875
5876 step = "Checking if revision has changed in VNFD"
5877 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305878 change_type = "policy_updated"
5879
aticigdffa6212022-04-12 15:27:53 +03005880 # There is new revision of VNFD, update operation is required
5881 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005882 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005883
5884 step = "Removing the VNFD packages if they exist in the local path"
5885 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5886 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5887
5888 step = "Get the VNFD packages from FSMongo"
5889 self.fs.sync(from_path=latest_vnfd_path)
5890 self.fs.sync(from_path=current_vnfd_path)
5891
5892 step = (
5893 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5894 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005895 current_base_folder = current_vnfd["_admin"]["storage"]
5896 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005897
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005898 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005899 get_iterable(nsr_deployed, "VCA")
5900 ):
5901 vnf_index = db_vnfr.get("member-vnf-index-ref")
5902
5903 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005904 if vca_deployed.get("member-vnf-index") == vnf_index:
5905 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5906 vca_type = vca_deployed.get("type")
5907 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005908
5909 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005910 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005911
5912 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005913 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005914 search_key = "kdu_name"
5915 else:
5916 search_key = "vnfd_id"
5917
5918 entity_id = vca_deployed.get(search_key)
5919
aticigdffa6212022-04-12 15:27:53 +03005920 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005921 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005922 )
5923
5924 if "execution-environment-list" in descriptor_config:
5925 ee_list = descriptor_config.get(
5926 "execution-environment-list", []
5927 )
5928 else:
5929 ee_list = []
5930
5931 # There could be several charm used in the same VNF
5932 for ee_item in ee_list:
5933 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005934 step = "Getting charm name"
5935 charm_name = ee_item["juju"].get("charm")
5936
5937 step = "Setting Charm artifact paths"
5938 current_charm_artifact_path.append(
5939 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005940 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005941 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005942 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005943 current_vnf_revision,
5944 )
5945 )
5946 target_charm_artifact_path.append(
5947 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005948 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005949 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005950 vca_type,
aticigd7083542022-05-30 20:45:55 +03005951 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005952 )
5953 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005954 elif ee_item.get("helm-chart"):
5955 # add chart to list and all parameters
5956 step = "Getting helm chart name"
5957 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00005958 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005959 step = "Setting Helm chart artifact paths"
5960
garciadeblasfb1e25f2022-11-18 14:36:22 +01005961 helm_artifacts.append(
5962 {
5963 "current_artifact_path": get_charm_artifact_path(
5964 current_base_folder,
5965 chart_name,
5966 vca_type,
5967 current_vnf_revision,
5968 ),
5969 "target_artifact_path": get_charm_artifact_path(
5970 latest_base_folder,
5971 chart_name,
5972 vca_type,
5973 latest_vnfd_revision,
5974 ),
5975 "ee_id": ee_id,
5976 "vca_index": vca_index,
5977 "vdu_index": vdu_count_index,
5978 }
5979 )
aticigdffa6212022-04-12 15:27:53 +03005980
5981 charm_artifact_paths = zip(
5982 current_charm_artifact_path, target_charm_artifact_path
5983 )
5984
5985 step = "Checking if software version has changed in VNFD"
5986 if find_software_version(current_vnfd) != find_software_version(
5987 latest_vnfd
5988 ):
aticigdffa6212022-04-12 15:27:53 +03005989 step = "Checking if existing VNF has charm"
5990 for current_charm_path, target_charm_path in list(
5991 charm_artifact_paths
5992 ):
5993 if current_charm_path:
5994 raise LcmException(
5995 "Software version change is not supported as VNF instance {} has charm.".format(
5996 vnf_instance_id
5997 )
5998 )
5999
kayal20010cd8af32024-03-13 10:23:16 +05306000 step = "Checking whether the descriptor has SFC"
6001 if db_nsr.get("nsd", {}).get("vnffgd"):
6002 raise LcmException(
6003 "Ns update is not allowed for NS with SFC"
6004 )
6005
aticigdffa6212022-04-12 15:27:53 +03006006 # There is no change in the charm package, then redeploy the VNF
6007 # based on new descriptor
6008 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306009 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006010 (result, detailed_status) = await self._ns_redeploy_vnf(
6011 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306012 )
6013 if result == "FAILED":
6014 nslcmop_operation_state = result
6015 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306016 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306017 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306018 db_nsr_update["detailed-status"] = detailed_status
6019 scaling_aspect = get_scaling_aspect(latest_vnfd)
6020 scaling_group_desc = db_nsr.get("_admin").get(
6021 "scaling-group", None
6022 )
6023 if scaling_group_desc:
6024 for aspect in scaling_aspect:
6025 scaling_group_id = aspect.get("id")
6026 for scale_index, scaling_group in enumerate(
6027 scaling_group_desc
6028 ):
6029 if scaling_group.get("name") == scaling_group_id:
6030 db_nsr_update[
6031 "_admin.scaling-group.{}.nb-scale-op".format(
6032 scale_index
6033 )
6034 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306035 self.logger.debug(
6036 logging_text
6037 + " step {} Done with result {} {}".format(
6038 step, nslcmop_operation_state, detailed_status
6039 )
6040 )
aticigdffa6212022-04-12 15:27:53 +03006041
6042 else:
6043 step = "Checking if any charm package has changed or not"
6044 for current_charm_path, target_charm_path in list(
6045 charm_artifact_paths
6046 ):
6047 if (
6048 current_charm_path
6049 and target_charm_path
6050 and self.check_charm_hash_changed(
6051 current_charm_path, target_charm_path
6052 )
6053 ):
aticigdffa6212022-04-12 15:27:53 +03006054 step = "Checking whether VNF uses juju bundle"
6055 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006056 raise LcmException(
6057 "Charm upgrade is not supported for the instance which"
6058 " uses juju-bundle: {}".format(
6059 check_juju_bundle_existence(current_vnfd)
6060 )
6061 )
6062
6063 step = "Upgrading Charm"
6064 (
6065 result,
6066 detailed_status,
6067 ) = await self._ns_charm_upgrade(
6068 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006069 charm_id=vca_id,
6070 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006071 path=self.fs.path + target_charm_path,
6072 timeout=timeout_seconds,
6073 )
6074
6075 if result == "FAILED":
6076 nslcmop_operation_state = result
6077 error_description_nslcmop = detailed_status
6078
6079 db_nslcmop_update["detailed-status"] = detailed_status
6080 self.logger.debug(
6081 logging_text
6082 + " step {} Done with result {} {}".format(
6083 step, nslcmop_operation_state, detailed_status
6084 )
6085 )
6086
6087 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306088 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6089 result = "COMPLETED"
6090 detailed_status = "Done"
6091 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006092
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006093 # helm base EE
6094 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006095 if not (
6096 item["current_artifact_path"]
6097 and item["target_artifact_path"]
6098 and self.check_charm_hash_changed(
6099 item["current_artifact_path"],
6100 item["target_artifact_path"],
6101 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006102 ):
6103 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006104 db_update_entry = "_admin.deployed.VCA.{}.".format(
6105 item["vca_index"]
6106 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006107 vnfr_id = db_vnfr["_id"]
6108 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6109 db_dict = {
6110 "collection": "nsrs",
6111 "filter": {"_id": nsr_id},
6112 "path": db_update_entry,
6113 }
6114 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006115 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006116 namespace=namespace,
6117 helm_id=helm_id,
6118 db_dict=db_dict,
6119 config=osm_config,
6120 artifact_path=item["target_artifact_path"],
6121 vca_type=vca_type,
6122 )
6123 vnf_id = db_vnfr.get("vnfd-ref")
6124 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6125 self.logger.debug("get ssh key block")
6126 rw_mgmt_ip = None
6127 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006128 config_descriptor,
6129 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006130 ):
6131 # Needed to inject a ssh key
6132 user = deep_get(
6133 config_descriptor,
6134 ("config-access", "ssh-access", "default-user"),
6135 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006136 step = (
6137 "Install configuration Software, getting public ssh key"
6138 )
6139 pub_key = await self.vca_map[
6140 vca_type
6141 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006142 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6143 )
6144
garciadeblasfb1e25f2022-11-18 14:36:22 +01006145 step = (
6146 "Insert public key into VM user={} ssh_key={}".format(
6147 user, pub_key
6148 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006149 )
6150 self.logger.debug(logging_text + step)
6151
6152 # wait for RO (ip-address) Insert pub_key into VM
6153 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6154 logging_text,
6155 nsr_id,
6156 vnfr_id,
6157 None,
6158 item["vdu_index"],
6159 user=user,
6160 pub_key=pub_key,
6161 )
6162
6163 initial_config_primitive_list = config_descriptor.get(
6164 "initial-config-primitive"
6165 )
6166 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006167 (
6168 p
6169 for p in initial_config_primitive_list
6170 if p["name"] == "config"
6171 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006172 None,
6173 )
6174 if not config_primitive:
6175 continue
6176
6177 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6178 if rw_mgmt_ip:
6179 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6180 if db_vnfr.get("additionalParamsForVnf"):
6181 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006182 parse_yaml_strings(
6183 db_vnfr["additionalParamsForVnf"].copy()
6184 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006185 )
6186 primitive_params_ = self._map_primitive_params(
6187 config_primitive, {}, deploy_params
6188 )
6189
6190 step = "execute primitive '{}' params '{}'".format(
6191 config_primitive["name"], primitive_params_
6192 )
6193 self.logger.debug(logging_text + step)
6194 await self.vca_map[vca_type].exec_primitive(
6195 ee_id=ee_id,
6196 primitive_name=config_primitive["name"],
6197 params_dict=primitive_params_,
6198 db_dict=db_dict,
6199 vca_id=vca_id,
6200 vca_type=vca_type,
6201 )
6202
6203 step = "Updating policies"
6204 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6205 detailed_status = "Done"
6206 db_nslcmop_update["detailed-status"] = "Done"
6207
aticigdffa6212022-04-12 15:27:53 +03006208 # If nslcmop_operation_state is None, so any operation is not failed.
6209 if not nslcmop_operation_state:
6210 nslcmop_operation_state = "COMPLETED"
6211
6212 # If update CHANGE_VNFPKG nslcmop_operation is successful
6213 # vnf revision need to be updated
6214 vnfr_update["revision"] = latest_vnfd_revision
6215 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6216
6217 self.logger.debug(
6218 logging_text
6219 + " task Done with result {} {}".format(
6220 nslcmop_operation_state, detailed_status
6221 )
6222 )
6223 elif update_type == "REMOVE_VNF":
6224 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306225 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6226 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6227 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6228 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006229 (result, detailed_status) = await self.remove_vnf(
6230 nsr_id, nslcmop_id, vnf_instance_id
6231 )
elumalaica7ece02022-04-12 12:47:32 +05306232 if result == "FAILED":
6233 nslcmop_operation_state = result
6234 error_description_nslcmop = detailed_status
6235 db_nslcmop_update["detailed-status"] = detailed_status
6236 change_type = "vnf_terminated"
6237 if not nslcmop_operation_state:
6238 nslcmop_operation_state = "COMPLETED"
6239 self.logger.debug(
6240 logging_text
6241 + " task Done with result {} {}".format(
6242 nslcmop_operation_state, detailed_status
6243 )
6244 )
aticigdffa6212022-04-12 15:27:53 +03006245
k4.rahulb827de92022-05-02 16:35:02 +00006246 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006247 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6248 "vnfInstanceId"
6249 ]
6250 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6251 "changeStateTo"
6252 ]
6253 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6254 "additionalParam"
6255 ]
k4.rahulb827de92022-05-02 16:35:02 +00006256 (result, detailed_status) = await self.rebuild_start_stop(
6257 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006258 )
k4.rahulb827de92022-05-02 16:35:02 +00006259 if result == "FAILED":
6260 nslcmop_operation_state = result
6261 error_description_nslcmop = detailed_status
6262 db_nslcmop_update["detailed-status"] = detailed_status
6263 if not nslcmop_operation_state:
6264 nslcmop_operation_state = "COMPLETED"
6265 self.logger.debug(
6266 logging_text
6267 + " task Done with result {} {}".format(
6268 nslcmop_operation_state, detailed_status
6269 )
6270 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306271 elif update_type == "VERTICAL_SCALE":
6272 self.logger.debug(
6273 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6274 )
6275 # Get the input parameters given through update request
6276 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6277 "vnfInstanceId"
6278 )
6279
6280 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6281 "vnfdId"
6282 )
6283 step = "Getting vnfr from database"
6284 db_vnfr = self.db.get_one(
6285 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6286 )
6287 self.logger.debug(step)
6288 step = "Getting vnfds from database"
6289 self.logger.debug("Start" + step)
6290 # Latest VNFD
6291 latest_vnfd = self.db.get_one(
6292 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6293 )
6294 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6295 # Current VNFD
6296 current_vnf_revision = db_vnfr.get("revision", 1)
6297 current_vnfd = self.db.get_one(
6298 "vnfds_revisions",
6299 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6300 fail_on_empty=False,
6301 )
6302 self.logger.debug("End" + step)
6303 # verify flavor changes
6304 step = "Checking for flavor change"
6305 if find_software_version(current_vnfd) != find_software_version(
6306 latest_vnfd
6307 ):
6308 self.logger.debug("Start" + step)
6309 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6310 "virtual-compute-desc"
6311 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6312 "virtual-storage-desc"
6313 ):
6314 raise LcmException(
6315 "No change in flavor check vnfd {}".format(vnfd_id)
6316 )
6317 else:
6318 raise LcmException(
6319 "No change in software_version of vnfd {}".format(vnfd_id)
6320 )
6321
6322 self.logger.debug("End" + step)
6323
6324 (result, detailed_status) = await self.vertical_scale(
6325 nsr_id, nslcmop_id
6326 )
6327 self.logger.debug(
6328 "vertical_scale result: {} detailed_status :{}".format(
6329 result, detailed_status
6330 )
6331 )
6332 if result == "FAILED":
6333 nslcmop_operation_state = result
6334 error_description_nslcmop = detailed_status
6335 db_nslcmop_update["detailed-status"] = detailed_status
6336 if not nslcmop_operation_state:
6337 nslcmop_operation_state = "COMPLETED"
6338 self.logger.debug(
6339 logging_text
6340 + " task Done with result {} {}".format(
6341 nslcmop_operation_state, detailed_status
6342 )
6343 )
k4.rahulb827de92022-05-02 16:35:02 +00006344
aticigdffa6212022-04-12 15:27:53 +03006345 # If nslcmop_operation_state is None, so any operation is not failed.
6346 # All operations are executed in overall.
6347 if not nslcmop_operation_state:
6348 nslcmop_operation_state = "COMPLETED"
6349 db_nsr_update["operational-status"] = old_operational_status
6350
6351 except (DbException, LcmException, N2VCException, K8sException) as e:
6352 self.logger.error(logging_text + "Exit Exception {}".format(e))
6353 exc = e
6354 except asyncio.CancelledError:
6355 self.logger.error(
6356 logging_text + "Cancelled Exception while '{}'".format(step)
6357 )
6358 exc = "Operation was cancelled"
6359 except asyncio.TimeoutError:
6360 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6361 exc = "Timeout"
6362 except Exception as e:
6363 exc = traceback.format_exc()
6364 self.logger.critical(
6365 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6366 exc_info=True,
6367 )
6368 finally:
6369 if exc:
6370 db_nslcmop_update[
6371 "detailed-status"
6372 ] = (
6373 detailed_status
6374 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6375 nslcmop_operation_state = "FAILED"
6376 db_nsr_update["operational-status"] = old_operational_status
6377 if db_nsr:
6378 self._write_ns_status(
6379 nsr_id=nsr_id,
6380 ns_state=db_nsr["nsState"],
6381 current_operation="IDLE",
6382 current_operation_id=None,
6383 other_update=db_nsr_update,
6384 )
6385
6386 self._write_op_status(
6387 op_id=nslcmop_id,
6388 stage="",
6389 error_message=error_description_nslcmop,
6390 operation_state=nslcmop_operation_state,
6391 other_update=db_nslcmop_update,
6392 )
6393
6394 if nslcmop_operation_state:
6395 try:
elumalaica7ece02022-04-12 12:47:32 +05306396 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306397 "nsr_id": nsr_id,
6398 "nslcmop_id": nslcmop_id,
6399 "operationState": nslcmop_operation_state,
6400 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006401 if (
6402 change_type in ("vnf_terminated", "policy_updated")
6403 and member_vnf_index
6404 ):
elumalaica7ece02022-04-12 12:47:32 +05306405 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006406 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006407 except Exception as e:
6408 self.logger.error(
6409 logging_text + "kafka_write notification Exception {}".format(e)
6410 )
6411 self.logger.debug(logging_text + "Exit")
6412 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6413 return nslcmop_operation_state, detailed_status
6414
tierno59d22d22018-09-25 18:10:19 +02006415 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006416 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006417 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006418 if not task_is_locked_by_me:
6419 return
6420
tierno59d22d22018-09-25 18:10:19 +02006421 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006422 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006423 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006424 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006425 self.logger.debug(logging_text + "Enter")
6426 # get all needed from database
6427 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006428 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006429 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006430 exc = None
tierno9ab95942018-10-10 16:44:22 +02006431 # in case of error, indicates what part of scale was failed to put nsr at error status
6432 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006433 old_operational_status = ""
6434 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006435 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006436 prom_job_name = ""
tierno59d22d22018-09-25 18:10:19 +02006437 try:
kuused124bfe2019-06-18 12:09:24 +02006438 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006439 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006440 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6441 self._write_ns_status(
6442 nsr_id=nsr_id,
6443 ns_state=None,
6444 current_operation="SCALING",
6445 current_operation_id=nslcmop_id,
6446 )
quilesj4cda56b2019-12-05 10:02:20 +00006447
ikalyvas02d9e7b2019-05-27 18:16:01 +03006448 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006449 self.logger.debug(
6450 step + " after having waited for previous tasks to be completed"
6451 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006452 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006453
ikalyvas02d9e7b2019-05-27 18:16:01 +03006454 step = "Getting nsr from database"
6455 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006456 old_operational_status = db_nsr["operational-status"]
6457 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006458
kayal20010cd8af32024-03-13 10:23:16 +05306459 step = "Checking whether the descriptor has SFC"
6460 if db_nsr.get("nsd", {}).get("vnffgd"):
6461 raise LcmException("Scaling is not allowed for NS with SFC")
6462
tierno59d22d22018-09-25 18:10:19 +02006463 step = "Parsing scaling parameters"
6464 db_nsr_update["operational-status"] = "scaling"
6465 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006466 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006467
garciadeblas5697b8b2021-03-24 09:17:02 +01006468 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6469 "scaleByStepData"
6470 ]["member-vnf-index"]
6471 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6472 "scaleByStepData"
6473 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006474 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006475 # for backward compatibility
6476 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6477 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6478 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6479 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6480
tierno59d22d22018-09-25 18:10:19 +02006481 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006482 db_vnfr = self.db.get_one(
6483 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6484 )
bravof922c4172020-11-24 21:21:43 -03006485
David Garciac1fe90a2021-03-31 19:12:02 +02006486 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6487
tierno59d22d22018-09-25 18:10:19 +02006488 step = "Getting vnfd from database"
6489 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006490
aktas13251562021-02-12 22:19:10 +03006491 base_folder = db_vnfd["_admin"]["storage"]
6492
tierno59d22d22018-09-25 18:10:19 +02006493 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006494 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006495 get_scaling_aspect(db_vnfd),
6496 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006497 )
6498 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006499 raise LcmException(
6500 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6501 "at vnfd:scaling-group-descriptor".format(scaling_group)
6502 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006503
tierno15b1cf12019-08-29 13:21:40 +00006504 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006505 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006506 nb_scale_op = 0
6507 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006508 self.update_db_2(
6509 "nsrs",
6510 nsr_id,
6511 {
6512 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006513 {
6514 "name": scaling_group,
6515 "vnf_index": vnf_index,
6516 "nb-scale-op": 0,
6517 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006518 ]
6519 },
6520 )
tierno59d22d22018-09-25 18:10:19 +02006521 admin_scale_index = 0
6522 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006523 for admin_scale_index, admin_scale_info in enumerate(
6524 db_nsr["_admin"]["scaling-group"]
6525 ):
36970ef037852024-04-01 15:41:31 +00006526 if (
6527 admin_scale_info["name"] == scaling_group
6528 and admin_scale_info["vnf_index"] == vnf_index
6529 ):
tierno59d22d22018-09-25 18:10:19 +02006530 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6531 break
tierno9ab95942018-10-10 16:44:22 +02006532 else: # not found, set index one plus last element and add new entry with the name
6533 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006534 db_nsr_update[
6535 "_admin.scaling-group.{}.name".format(admin_scale_index)
6536 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006537 db_nsr_update[
6538 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6539 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006540
6541 vca_scaling_info = []
6542 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006543 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006544 if "aspect-delta-details" not in scaling_descriptor:
6545 raise LcmException(
6546 "Aspect delta details not fount in scaling descriptor {}".format(
6547 scaling_descriptor["name"]
6548 )
6549 )
tierno59d22d22018-09-25 18:10:19 +02006550 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006551 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006552
aktas5f75f102021-03-15 11:26:10 +03006553 scaling_info["scaling_direction"] = "OUT"
6554 scaling_info["vdu-create"] = {}
6555 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006556 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006557 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006558 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006559 # vdu_index also provides the number of instance of the targeted vdu
6560 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006561 if vdu_index <= len(db_vnfr["vdur"]):
6562 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6563 prom_job_name = (
6564 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6565 )
6566 prom_job_name = prom_job_name.replace("_", "")
6567 prom_job_name = prom_job_name.replace("-", "")
6568 else:
6569 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006570 cloud_init_text = self._get_vdu_cloud_init_content(
6571 vdud, db_vnfd
6572 )
tierno72ef84f2020-10-06 08:22:07 +00006573 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006574 additional_params = (
6575 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6576 or {}
6577 )
bravof832f8992020-12-07 12:57:31 -03006578 cloud_init_list = []
6579
6580 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6581 max_instance_count = 10
6582 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006583 max_instance_count = vdu_profile.get(
6584 "max-number-of-instances", 10
6585 )
6586
6587 default_instance_num = get_number_of_instances(
6588 db_vnfd, vdud["id"]
6589 )
aktas5f75f102021-03-15 11:26:10 +03006590 instances_number = vdu_delta.get("number-of-instances", 1)
6591 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006592
aktas5f75f102021-03-15 11:26:10 +03006593 new_instance_count = nb_scale_op + default_instance_num
6594 # Control if new count is over max and vdu count is less than max.
6595 # Then assign new instance count
6596 if new_instance_count > max_instance_count > vdu_count:
6597 instances_number = new_instance_count - max_instance_count
6598 else:
6599 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006600
aktas5f75f102021-03-15 11:26:10 +03006601 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006602 raise LcmException(
6603 "reached the limit of {} (max-instance-count) "
6604 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006605 "scaling-group-descriptor '{}'".format(
6606 nb_scale_op, scaling_group
6607 )
bravof922c4172020-11-24 21:21:43 -03006608 )
bravof832f8992020-12-07 12:57:31 -03006609 for x in range(vdu_delta.get("number-of-instances", 1)):
6610 if cloud_init_text:
6611 # TODO Information of its own ip is not available because db_vnfr is not updated.
6612 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006613 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006614 )
bravof832f8992020-12-07 12:57:31 -03006615 cloud_init_list.append(
6616 self._parse_cloud_init(
6617 cloud_init_text,
6618 additional_params,
6619 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006620 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006621 )
6622 )
aktas5f75f102021-03-15 11:26:10 +03006623 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006624 {
6625 "osm_vdu_id": vdu_delta["id"],
6626 "member-vnf-index": vnf_index,
6627 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006628 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006629 }
6630 )
aktas5f75f102021-03-15 11:26:10 +03006631 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6632 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006633 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006634 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006635 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006636
6637 # Might have different kdus in the same delta
6638 # Should have list for each kdu
6639 if not scaling_info["kdu-create"].get(kdu_name, None):
6640 scaling_info["kdu-create"][kdu_name] = []
6641
6642 kdur = get_kdur(db_vnfr, kdu_name)
6643 if kdur.get("helm-chart"):
6644 k8s_cluster_type = "helm-chart-v3"
6645 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006646 elif kdur.get("juju-bundle"):
6647 k8s_cluster_type = "juju-bundle"
6648 else:
6649 raise LcmException(
6650 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6651 "juju-bundle. Maybe an old NBI version is running".format(
6652 db_vnfr["member-vnf-index-ref"], kdu_name
6653 )
6654 )
6655
6656 max_instance_count = 10
6657 if kdu_profile and "max-number-of-instances" in kdu_profile:
6658 max_instance_count = kdu_profile.get(
6659 "max-number-of-instances", 10
6660 )
6661
6662 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6663 deployed_kdu, _ = get_deployed_kdu(
6664 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006665 )
aktas5f75f102021-03-15 11:26:10 +03006666 if deployed_kdu is None:
6667 raise LcmException(
6668 "KDU '{}' for vnf '{}' not deployed".format(
6669 kdu_name, vnf_index
6670 )
6671 )
6672 kdu_instance = deployed_kdu.get("kdu-instance")
6673 instance_num = await self.k8scluster_map[
6674 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006675 ].get_scale_count(
6676 resource_name,
6677 kdu_instance,
6678 vca_id=vca_id,
6679 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6680 kdu_model=deployed_kdu.get("kdu-model"),
6681 )
aktas5f75f102021-03-15 11:26:10 +03006682 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006683 "number-of-instances", 1
6684 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006685
aktas5f75f102021-03-15 11:26:10 +03006686 # Control if new count is over max and instance_num is less than max.
6687 # Then assign max instance number to kdu replica count
6688 if kdu_replica_count > max_instance_count > instance_num:
6689 kdu_replica_count = max_instance_count
6690 if kdu_replica_count > max_instance_count:
6691 raise LcmException(
6692 "reached the limit of {} (max-instance-count) "
6693 "scaling-out operations for the "
6694 "scaling-group-descriptor '{}'".format(
6695 instance_num, scaling_group
6696 )
6697 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006698
aktas5f75f102021-03-15 11:26:10 +03006699 for x in range(kdu_delta.get("number-of-instances", 1)):
6700 vca_scaling_info.append(
6701 {
6702 "osm_kdu_id": kdu_name,
6703 "member-vnf-index": vnf_index,
6704 "type": "create",
6705 "kdu_index": instance_num + x - 1,
6706 }
6707 )
6708 scaling_info["kdu-create"][kdu_name].append(
6709 {
6710 "member-vnf-index": vnf_index,
6711 "type": "create",
6712 "k8s-cluster-type": k8s_cluster_type,
6713 "resource-name": resource_name,
6714 "scale": kdu_replica_count,
6715 }
6716 )
6717 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006718 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006719
6720 scaling_info["scaling_direction"] = "IN"
6721 scaling_info["vdu-delete"] = {}
6722 scaling_info["kdu-delete"] = {}
6723
bravof832f8992020-12-07 12:57:31 -03006724 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006725 for vdu_delta in delta.get("vdu-delta", {}):
6726 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006727 min_instance_count = 0
6728 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6729 if vdu_profile and "min-number-of-instances" in vdu_profile:
6730 min_instance_count = vdu_profile["min-number-of-instances"]
6731
garciadeblas5697b8b2021-03-24 09:17:02 +01006732 default_instance_num = get_number_of_instances(
6733 db_vnfd, vdu_delta["id"]
6734 )
aktas5f75f102021-03-15 11:26:10 +03006735 instance_num = vdu_delta.get("number-of-instances", 1)
6736 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006737
aktas5f75f102021-03-15 11:26:10 +03006738 new_instance_count = nb_scale_op + default_instance_num
6739
6740 if new_instance_count < min_instance_count < vdu_count:
6741 instances_number = min_instance_count - new_instance_count
6742 else:
6743 instances_number = instance_num
6744
6745 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006746 raise LcmException(
6747 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006748 "scaling-group-descriptor '{}'".format(
6749 nb_scale_op, scaling_group
6750 )
bravof832f8992020-12-07 12:57:31 -03006751 )
aktas13251562021-02-12 22:19:10 +03006752 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006753 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006754 {
6755 "osm_vdu_id": vdu_delta["id"],
6756 "member-vnf-index": vnf_index,
6757 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006758 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006759 }
6760 )
aktas5f75f102021-03-15 11:26:10 +03006761 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6762 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006763 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006764 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006765 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006766
6767 if not scaling_info["kdu-delete"].get(kdu_name, None):
6768 scaling_info["kdu-delete"][kdu_name] = []
6769
6770 kdur = get_kdur(db_vnfr, kdu_name)
6771 if kdur.get("helm-chart"):
6772 k8s_cluster_type = "helm-chart-v3"
6773 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006774 elif kdur.get("juju-bundle"):
6775 k8s_cluster_type = "juju-bundle"
6776 else:
6777 raise LcmException(
6778 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6779 "juju-bundle. Maybe an old NBI version is running".format(
6780 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6781 )
6782 )
6783
6784 min_instance_count = 0
6785 if kdu_profile and "min-number-of-instances" in kdu_profile:
6786 min_instance_count = kdu_profile["min-number-of-instances"]
6787
6788 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6789 deployed_kdu, _ = get_deployed_kdu(
6790 nsr_deployed, kdu_name, vnf_index
6791 )
6792 if deployed_kdu is None:
6793 raise LcmException(
6794 "KDU '{}' for vnf '{}' not deployed".format(
6795 kdu_name, vnf_index
6796 )
6797 )
6798 kdu_instance = deployed_kdu.get("kdu-instance")
6799 instance_num = await self.k8scluster_map[
6800 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006801 ].get_scale_count(
6802 resource_name,
6803 kdu_instance,
6804 vca_id=vca_id,
6805 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6806 kdu_model=deployed_kdu.get("kdu-model"),
6807 )
aktas5f75f102021-03-15 11:26:10 +03006808 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006809 "number-of-instances", 1
6810 )
tierno59d22d22018-09-25 18:10:19 +02006811
aktas5f75f102021-03-15 11:26:10 +03006812 if kdu_replica_count < min_instance_count < instance_num:
6813 kdu_replica_count = min_instance_count
6814 if kdu_replica_count < min_instance_count:
6815 raise LcmException(
6816 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6817 "scaling-group-descriptor '{}'".format(
6818 instance_num, scaling_group
6819 )
6820 )
6821
6822 for x in range(kdu_delta.get("number-of-instances", 1)):
6823 vca_scaling_info.append(
6824 {
6825 "osm_kdu_id": kdu_name,
6826 "member-vnf-index": vnf_index,
6827 "type": "delete",
6828 "kdu_index": instance_num - x - 1,
6829 }
6830 )
6831 scaling_info["kdu-delete"][kdu_name].append(
6832 {
6833 "member-vnf-index": vnf_index,
6834 "type": "delete",
6835 "k8s-cluster-type": k8s_cluster_type,
6836 "resource-name": resource_name,
6837 "scale": kdu_replica_count,
6838 }
6839 )
6840
tierno59d22d22018-09-25 18:10:19 +02006841 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006842 vdu_delete = copy(scaling_info.get("vdu-delete"))
6843 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006844 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006845 if vdu_delete.get(vdur["vdu-id-ref"]):
6846 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006847 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006848 {
6849 "name": vdur.get("name") or vdur.get("vdu-name"),
6850 "vdu_id": vdur["vdu-id-ref"],
6851 "interface": [],
6852 }
6853 )
tierno59d22d22018-09-25 18:10:19 +02006854 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006855 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006856 {
6857 "name": interface["name"],
6858 "ip_address": interface["ip-address"],
6859 "mac_address": interface.get("mac-address"),
6860 }
6861 )
tierno2357f4e2020-10-19 16:38:59 +00006862 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006863
kuuseac3a8882019-10-03 10:48:06 +02006864 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006865 step = "Executing pre-scale vnf-config-primitive"
6866 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006867 for scaling_config_action in scaling_descriptor[
6868 "scaling-config-action"
6869 ]:
6870 if (
6871 scaling_config_action.get("trigger") == "pre-scale-in"
6872 and scaling_type == "SCALE_IN"
6873 ) or (
6874 scaling_config_action.get("trigger") == "pre-scale-out"
6875 and scaling_type == "SCALE_OUT"
6876 ):
6877 vnf_config_primitive = scaling_config_action[
6878 "vnf-config-primitive-name-ref"
6879 ]
6880 step = db_nslcmop_update[
6881 "detailed-status"
6882 ] = "executing pre-scale scaling-config-action '{}'".format(
6883 vnf_config_primitive
6884 )
tiernoda964822019-01-14 15:53:47 +00006885
tierno59d22d22018-09-25 18:10:19 +02006886 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006887 for config_primitive in (
6888 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6889 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006890 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006891 break
6892 else:
6893 raise LcmException(
6894 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006895 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006896 "primitive".format(scaling_group, vnf_config_primitive)
6897 )
tiernoda964822019-01-14 15:53:47 +00006898
aktas5f75f102021-03-15 11:26:10 +03006899 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006900 if db_vnfr.get("additionalParamsForVnf"):
6901 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006902
tierno9ab95942018-10-10 16:44:22 +02006903 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006904 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006905 primitive_params = self._map_primitive_params(
6906 config_primitive, {}, vnfr_params
6907 )
kuuseac3a8882019-10-03 10:48:06 +02006908
tierno7c4e24c2020-05-13 08:41:35 +00006909 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006910 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006911 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006912 vnf_index,
6913 vnf_config_primitive,
6914 primitive_params,
6915 "PRE-SCALE",
6916 )
tierno7c4e24c2020-05-13 08:41:35 +00006917 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006918 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006919 result = "COMPLETED"
6920 result_detail = "Done"
6921 self.logger.debug(
6922 logging_text
6923 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6924 vnf_config_primitive, result, result_detail
6925 )
6926 )
kuuseac3a8882019-10-03 10:48:06 +02006927 else:
tierno7c4e24c2020-05-13 08:41:35 +00006928 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006929 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006930 op_index = (
6931 len(db_nslcmop.get("_admin", {}).get("operations"))
6932 - 1
6933 )
6934 self.logger.debug(
6935 logging_text
6936 + "vnf_config_primitive={} New sub-operation".format(
6937 vnf_config_primitive
6938 )
6939 )
kuuseac3a8882019-10-03 10:48:06 +02006940 else:
tierno7c4e24c2020-05-13 08:41:35 +00006941 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006942 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6943 op_index
6944 ]
6945 vnf_index = op.get("member_vnf_index")
6946 vnf_config_primitive = op.get("primitive")
6947 primitive_params = op.get("primitive_params")
6948 self.logger.debug(
6949 logging_text
6950 + "vnf_config_primitive={} Sub-operation retry".format(
6951 vnf_config_primitive
6952 )
6953 )
tierno588547c2020-07-01 15:30:20 +00006954 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006955 ee_descriptor_id = config_primitive.get(
6956 "execution-environment-ref"
6957 )
6958 primitive_name = config_primitive.get(
6959 "execution-environment-primitive", vnf_config_primitive
6960 )
6961 ee_id, vca_type = self._look_for_deployed_vca(
6962 nsr_deployed["VCA"],
6963 member_vnf_index=vnf_index,
6964 vdu_id=None,
6965 vdu_count_index=None,
6966 ee_descriptor_id=ee_descriptor_id,
6967 )
kuuseac3a8882019-10-03 10:48:06 +02006968 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006969 ee_id,
6970 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006971 primitive_params,
6972 vca_type=vca_type,
6973 vca_id=vca_id,
6974 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006975 self.logger.debug(
6976 logging_text
6977 + "vnf_config_primitive={} Done with result {} {}".format(
6978 vnf_config_primitive, result, result_detail
6979 )
6980 )
kuuseac3a8882019-10-03 10:48:06 +02006981 # Update operationState = COMPLETED | FAILED
6982 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006983 db_nslcmop, op_index, result, result_detail
6984 )
kuuseac3a8882019-10-03 10:48:06 +02006985
tierno59d22d22018-09-25 18:10:19 +02006986 if result == "FAILED":
6987 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006988 db_nsr_update["config-status"] = old_config_status
6989 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006990 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006991
garciadeblas5697b8b2021-03-24 09:17:02 +01006992 db_nsr_update[
6993 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6994 ] = nb_scale_op
6995 db_nsr_update[
6996 "_admin.scaling-group.{}.time".format(admin_scale_index)
6997 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006998
aktas13251562021-02-12 22:19:10 +03006999 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007000 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007001 step = db_nslcmop_update[
7002 "detailed-status"
7003 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007004 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007005 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007006 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007007 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007008 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007009 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007010 )
aktas5f75f102021-03-15 11:26:10 +03007011 if vca_info.get("osm_vdu_id"):
7012 vdu_id = vca_info["osm_vdu_id"]
7013 vdu_index = int(vca_info["vdu_index"])
7014 stage[
7015 1
7016 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7017 member_vnf_index, vdu_id, vdu_index
7018 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007019 stage[2] = step = "Scaling in VCA"
7020 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007021 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7022 config_update = db_nsr["configurationStatus"]
7023 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007024 if (
7025 (vca or vca.get("ee_id"))
7026 and vca["member-vnf-index"] == member_vnf_index
7027 and vca["vdu_count_index"] == vdu_index
7028 ):
aktas13251562021-02-12 22:19:10 +03007029 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007030 config_descriptor = get_configuration(
7031 db_vnfd, vca.get("vdu_id")
7032 )
aktas13251562021-02-12 22:19:10 +03007033 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007034 config_descriptor = get_configuration(
7035 db_vnfd, vca.get("kdu_name")
7036 )
aktas13251562021-02-12 22:19:10 +03007037 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007038 config_descriptor = get_configuration(
7039 db_vnfd, db_vnfd["id"]
7040 )
7041 operation_params = (
7042 db_nslcmop.get("operationParams") or {}
7043 )
7044 exec_terminate_primitives = not operation_params.get(
7045 "skip_terminate_primitives"
7046 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007047 task = asyncio.ensure_future(
7048 asyncio.wait_for(
7049 self.destroy_N2VC(
7050 logging_text,
7051 db_nslcmop,
7052 vca,
7053 config_descriptor,
7054 vca_index,
7055 destroy_ee=True,
7056 exec_primitives=exec_terminate_primitives,
7057 scaling_in=True,
7058 vca_id=vca_id,
7059 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007060 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007061 )
7062 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007063 tasks_dict_info[task] = "Terminating VCA {}".format(
7064 vca.get("ee_id")
7065 )
aktas13251562021-02-12 22:19:10 +03007066 del vca_update[vca_index]
7067 del config_update[vca_index]
7068 # wait for pending tasks of terminate primitives
7069 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007070 self.logger.debug(
7071 logging_text
7072 + "Waiting for tasks {}".format(
7073 list(tasks_dict_info.keys())
7074 )
7075 )
7076 error_list = await self._wait_for_tasks(
7077 logging_text,
7078 tasks_dict_info,
7079 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007080 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007081 ),
7082 stage,
7083 nslcmop_id,
7084 )
aktas13251562021-02-12 22:19:10 +03007085 tasks_dict_info.clear()
7086 if error_list:
7087 raise LcmException("; ".join(error_list))
7088
7089 db_vca_and_config_update = {
7090 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007091 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007092 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007093 self.update_db_2(
7094 "nsrs", db_nsr["_id"], db_vca_and_config_update
7095 )
aktas13251562021-02-12 22:19:10 +03007096 scale_process = None
7097 # SCALE-IN VCA - END
7098
kuuseac3a8882019-10-03 10:48:06 +02007099 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007100 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007101 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007102 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007103 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007104 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007105 )
aktas5f75f102021-03-15 11:26:10 +03007106 scaling_info.pop("vdu-create", None)
7107 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007108
tierno9ab95942018-10-10 16:44:22 +02007109 scale_process = None
aktas13251562021-02-12 22:19:10 +03007110 # SCALE RO - END
7111
aktas5f75f102021-03-15 11:26:10 +03007112 # SCALE KDU - BEGIN
7113 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7114 scale_process = "KDU"
7115 await self._scale_kdu(
7116 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7117 )
7118 scaling_info.pop("kdu-create", None)
7119 scaling_info.pop("kdu-delete", None)
7120
7121 scale_process = None
7122 # SCALE KDU - END
7123
7124 if db_nsr_update:
7125 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7126
aktas13251562021-02-12 22:19:10 +03007127 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007128 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007129 step = db_nslcmop_update[
7130 "detailed-status"
7131 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007132 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007133 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007134 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007135 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007136 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007137 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007138 )
aktas13251562021-02-12 22:19:10 +03007139 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007140 if vca_info.get("osm_vdu_id"):
7141 vdu_index = int(vca_info["vdu_index"])
7142 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7143 if db_vnfr.get("additionalParamsForVnf"):
7144 deploy_params.update(
7145 parse_yaml_strings(
7146 db_vnfr["additionalParamsForVnf"].copy()
7147 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007148 )
aktas5f75f102021-03-15 11:26:10 +03007149 descriptor_config = get_configuration(
7150 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007151 )
aktas5f75f102021-03-15 11:26:10 +03007152 if descriptor_config:
7153 vdu_id = None
7154 vdu_name = None
7155 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007156 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007157 self._deploy_n2vc(
7158 logging_text=logging_text
7159 + "member_vnf_index={} ".format(member_vnf_index),
7160 db_nsr=db_nsr,
7161 db_vnfr=db_vnfr,
7162 nslcmop_id=nslcmop_id,
7163 nsr_id=nsr_id,
7164 nsi_id=nsi_id,
7165 vnfd_id=vnfd_id,
7166 vdu_id=vdu_id,
7167 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007168 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007169 member_vnf_index=member_vnf_index,
7170 vdu_index=vdu_index,
7171 vdu_name=vdu_name,
7172 deploy_params=deploy_params,
7173 descriptor_config=descriptor_config,
7174 base_folder=base_folder,
7175 task_instantiation_info=tasks_dict_info,
7176 stage=stage,
7177 )
7178 vdu_id = vca_info["osm_vdu_id"]
7179 vdur = find_in_list(
7180 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007181 )
aktas5f75f102021-03-15 11:26:10 +03007182 descriptor_config = get_configuration(db_vnfd, vdu_id)
7183 if vdur.get("additionalParams"):
7184 deploy_params_vdu = parse_yaml_strings(
7185 vdur["additionalParams"]
7186 )
7187 else:
7188 deploy_params_vdu = deploy_params
7189 deploy_params_vdu["OSM"] = get_osm_params(
7190 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007191 )
aktas5f75f102021-03-15 11:26:10 +03007192 if descriptor_config:
7193 vdu_name = None
7194 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007195 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007196 stage[
7197 1
7198 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007199 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007200 )
7201 stage[2] = step = "Scaling out VCA"
7202 self._write_op_status(op_id=nslcmop_id, stage=stage)
7203 self._deploy_n2vc(
7204 logging_text=logging_text
7205 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7206 member_vnf_index, vdu_id, vdu_index
7207 ),
7208 db_nsr=db_nsr,
7209 db_vnfr=db_vnfr,
7210 nslcmop_id=nslcmop_id,
7211 nsr_id=nsr_id,
7212 nsi_id=nsi_id,
7213 vnfd_id=vnfd_id,
7214 vdu_id=vdu_id,
7215 kdu_name=kdu_name,
7216 member_vnf_index=member_vnf_index,
7217 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007218 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007219 vdu_name=vdu_name,
7220 deploy_params=deploy_params_vdu,
7221 descriptor_config=descriptor_config,
7222 base_folder=base_folder,
7223 task_instantiation_info=tasks_dict_info,
7224 stage=stage,
7225 )
aktas13251562021-02-12 22:19:10 +03007226 # SCALE-UP VCA - END
7227 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007228
kuuseac3a8882019-10-03 10:48:06 +02007229 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007230 # execute primitive service POST-SCALING
7231 step = "Executing post-scale vnf-config-primitive"
7232 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007233 for scaling_config_action in scaling_descriptor[
7234 "scaling-config-action"
7235 ]:
7236 if (
7237 scaling_config_action.get("trigger") == "post-scale-in"
7238 and scaling_type == "SCALE_IN"
7239 ) or (
7240 scaling_config_action.get("trigger") == "post-scale-out"
7241 and scaling_type == "SCALE_OUT"
7242 ):
7243 vnf_config_primitive = scaling_config_action[
7244 "vnf-config-primitive-name-ref"
7245 ]
7246 step = db_nslcmop_update[
7247 "detailed-status"
7248 ] = "executing post-scale scaling-config-action '{}'".format(
7249 vnf_config_primitive
7250 )
tiernoda964822019-01-14 15:53:47 +00007251
aktas5f75f102021-03-15 11:26:10 +03007252 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007253 if db_vnfr.get("additionalParamsForVnf"):
7254 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7255
tierno59d22d22018-09-25 18:10:19 +02007256 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007257 for config_primitive in (
7258 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7259 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007260 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007261 break
7262 else:
tiernoa278b842020-07-08 15:33:55 +00007263 raise LcmException(
7264 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7265 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007266 "config-primitive".format(
7267 scaling_group, vnf_config_primitive
7268 )
7269 )
tierno9ab95942018-10-10 16:44:22 +02007270 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007271 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007272 primitive_params = self._map_primitive_params(
7273 config_primitive, {}, vnfr_params
7274 )
tiernod6de1992018-10-11 13:05:52 +02007275
tierno7c4e24c2020-05-13 08:41:35 +00007276 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007277 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007278 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007279 vnf_index,
7280 vnf_config_primitive,
7281 primitive_params,
7282 "POST-SCALE",
7283 )
quilesj4cda56b2019-12-05 10:02:20 +00007284 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007285 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007286 result = "COMPLETED"
7287 result_detail = "Done"
7288 self.logger.debug(
7289 logging_text
7290 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7291 vnf_config_primitive, result, result_detail
7292 )
7293 )
kuuseac3a8882019-10-03 10:48:06 +02007294 else:
quilesj4cda56b2019-12-05 10:02:20 +00007295 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007296 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007297 op_index = (
7298 len(db_nslcmop.get("_admin", {}).get("operations"))
7299 - 1
7300 )
7301 self.logger.debug(
7302 logging_text
7303 + "vnf_config_primitive={} New sub-operation".format(
7304 vnf_config_primitive
7305 )
7306 )
kuuseac3a8882019-10-03 10:48:06 +02007307 else:
tierno7c4e24c2020-05-13 08:41:35 +00007308 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007309 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7310 op_index
7311 ]
7312 vnf_index = op.get("member_vnf_index")
7313 vnf_config_primitive = op.get("primitive")
7314 primitive_params = op.get("primitive_params")
7315 self.logger.debug(
7316 logging_text
7317 + "vnf_config_primitive={} Sub-operation retry".format(
7318 vnf_config_primitive
7319 )
7320 )
tierno588547c2020-07-01 15:30:20 +00007321 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007322 ee_descriptor_id = config_primitive.get(
7323 "execution-environment-ref"
7324 )
7325 primitive_name = config_primitive.get(
7326 "execution-environment-primitive", vnf_config_primitive
7327 )
7328 ee_id, vca_type = self._look_for_deployed_vca(
7329 nsr_deployed["VCA"],
7330 member_vnf_index=vnf_index,
7331 vdu_id=None,
7332 vdu_count_index=None,
7333 ee_descriptor_id=ee_descriptor_id,
7334 )
kuuseac3a8882019-10-03 10:48:06 +02007335 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007336 ee_id,
7337 primitive_name,
7338 primitive_params,
7339 vca_type=vca_type,
7340 vca_id=vca_id,
7341 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007342 self.logger.debug(
7343 logging_text
7344 + "vnf_config_primitive={} Done with result {} {}".format(
7345 vnf_config_primitive, result, result_detail
7346 )
7347 )
kuuseac3a8882019-10-03 10:48:06 +02007348 # Update operationState = COMPLETED | FAILED
7349 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007350 db_nslcmop, op_index, result, result_detail
7351 )
kuuseac3a8882019-10-03 10:48:06 +02007352
tierno59d22d22018-09-25 18:10:19 +02007353 if result == "FAILED":
7354 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007355 db_nsr_update["config-status"] = old_config_status
7356 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007357 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007358 # Check if each vnf has exporter for metric collection if so update prometheus job records
Rahul Kumar54671c52024-05-09 15:34:01 +05307359 if scaling_type == "SCALE_OUT" and bool(self.service_kpi.old_sa):
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007360 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7361 vnfr_id = db_vnfr["id"]
7362 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7363 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7364 self.logger.debug("exporter config :{}".format(exporter_config))
7365 artifact_path = "{}/{}/{}".format(
7366 base_folder["folder"],
7367 base_folder["pkg-dir"],
7368 "exporter-endpoint",
7369 )
7370 ee_id = None
7371 ee_config_descriptor = exporter_config
7372 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7373 logging_text,
7374 nsr_id,
7375 vnfr_id,
7376 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7377 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7378 user=None,
7379 pub_key=None,
7380 )
7381 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7382 self.logger.debug("Artifact_path:{}".format(artifact_path))
7383 vdu_id_for_prom = None
7384 vdu_index_for_prom = None
7385 for x in get_iterable(db_vnfr, "vdur"):
7386 vdu_id_for_prom = x.get("vdu-id-ref")
7387 vdu_index_for_prom = x.get("count-index")
7388 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7389 vnfr_id = vnfr_id.replace("_", "")
7390 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7391 ee_id=ee_id,
7392 artifact_path=artifact_path,
7393 ee_config_descriptor=ee_config_descriptor,
7394 vnfr_id=vnfr_id,
7395 nsr_id=nsr_id,
7396 target_ip=rw_mgmt_ip,
7397 element_type="VDU",
7398 vdu_id=vdu_id_for_prom,
7399 vdu_index=vdu_index_for_prom,
7400 )
tierno59d22d22018-09-25 18:10:19 +02007401
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007402 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7403 if prometheus_jobs:
7404 db_nsr_update[
7405 "_admin.deployed.prometheus_jobs"
7406 ] = prometheus_jobs
7407 self.update_db_2(
7408 "nsrs",
7409 nsr_id,
7410 db_nsr_update,
7411 )
7412
7413 for job in prometheus_jobs:
7414 self.db.set_one(
7415 "prometheus_jobs",
7416 {"job_name": ""},
7417 job,
7418 upsert=True,
7419 fail_on_empty=False,
7420 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007421 db_nsr_update[
7422 "detailed-status"
7423 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7424 db_nsr_update["operational-status"] = (
7425 "running"
7426 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007427 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007428 )
tiernod6de1992018-10-11 13:05:52 +02007429 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007430 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007431 except (
7432 ROclient.ROClientException,
7433 DbException,
7434 LcmException,
7435 NgRoException,
7436 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007437 self.logger.error(logging_text + "Exit Exception {}".format(e))
7438 exc = e
7439 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007440 self.logger.error(
7441 logging_text + "Cancelled Exception while '{}'".format(step)
7442 )
tierno59d22d22018-09-25 18:10:19 +02007443 exc = "Operation was cancelled"
7444 except Exception as e:
7445 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007446 self.logger.critical(
7447 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7448 exc_info=True,
7449 )
tierno59d22d22018-09-25 18:10:19 +02007450 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007451 error_list = list()
7452 if exc:
7453 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007454 self._write_ns_status(
7455 nsr_id=nsr_id,
7456 ns_state=None,
7457 current_operation="IDLE",
7458 current_operation_id=None,
7459 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007460 try:
7461 if tasks_dict_info:
7462 stage[1] = "Waiting for instantiate pending tasks."
7463 self.logger.debug(logging_text + stage[1])
7464 exc = await self._wait_for_tasks(
7465 logging_text,
7466 tasks_dict_info,
7467 self.timeout.ns_deploy,
7468 stage,
7469 nslcmop_id,
7470 nsr_id=nsr_id,
7471 )
7472 except asyncio.CancelledError:
7473 error_list.append("Cancelled")
7474 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7475 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007476 logging_text,
7477 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007478 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007479 stage,
7480 nslcmop_id,
7481 nsr_id=nsr_id,
7482 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007483 if error_list:
7484 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007485 db_nslcmop_update[
7486 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007487 ] = error_description_nslcmop = "FAILED {}: {}".format(
7488 step, error_detail
7489 )
tiernoa17d4f42020-04-28 09:59:23 +00007490 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007491 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007492 db_nsr_update["operational-status"] = old_operational_status
7493 db_nsr_update["config-status"] = old_config_status
7494 db_nsr_update["detailed-status"] = ""
7495 if scale_process:
7496 if "VCA" in scale_process:
7497 db_nsr_update["config-status"] = "failed"
7498 if "RO" in scale_process:
7499 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007500 db_nsr_update[
7501 "detailed-status"
7502 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007503 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007504 )
tiernoa17d4f42020-04-28 09:59:23 +00007505 else:
7506 error_description_nslcmop = None
7507 nslcmop_operation_state = "COMPLETED"
7508 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007509 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7510 self.db.del_one(
7511 "prometheus_jobs",
7512 {"job_name": prom_job_name},
7513 fail_on_empty=False,
7514 )
quilesj4cda56b2019-12-05 10:02:20 +00007515
garciadeblas5697b8b2021-03-24 09:17:02 +01007516 self._write_op_status(
7517 op_id=nslcmop_id,
7518 stage="",
7519 error_message=error_description_nslcmop,
7520 operation_state=nslcmop_operation_state,
7521 other_update=db_nslcmop_update,
7522 )
tiernoa17d4f42020-04-28 09:59:23 +00007523 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007524 self._write_ns_status(
7525 nsr_id=nsr_id,
7526 ns_state=None,
7527 current_operation="IDLE",
7528 current_operation_id=None,
7529 other_update=db_nsr_update,
7530 )
tiernoa17d4f42020-04-28 09:59:23 +00007531
tierno59d22d22018-09-25 18:10:19 +02007532 if nslcmop_operation_state:
7533 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007534 msg = {
7535 "nsr_id": nsr_id,
7536 "nslcmop_id": nslcmop_id,
7537 "operationState": nslcmop_operation_state,
7538 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007539 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007540 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007541 self.logger.error(
7542 logging_text + "kafka_write notification Exception {}".format(e)
7543 )
tierno59d22d22018-09-25 18:10:19 +02007544 self.logger.debug(logging_text + "Exit")
7545 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007546
aktas5f75f102021-03-15 11:26:10 +03007547 async def _scale_kdu(
7548 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7549 ):
7550 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7551 for kdu_name in _scaling_info:
7552 for kdu_scaling_info in _scaling_info[kdu_name]:
7553 deployed_kdu, index = get_deployed_kdu(
7554 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7555 )
7556 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7557 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007558 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007559 scale = int(kdu_scaling_info["scale"])
7560 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7561
7562 db_dict = {
7563 "collection": "nsrs",
7564 "filter": {"_id": nsr_id},
7565 "path": "_admin.deployed.K8s.{}".format(index),
7566 }
7567
7568 step = "scaling application {}".format(
7569 kdu_scaling_info["resource-name"]
7570 )
7571 self.logger.debug(logging_text + step)
7572
7573 if kdu_scaling_info["type"] == "delete":
7574 kdu_config = get_configuration(db_vnfd, kdu_name)
7575 if (
7576 kdu_config
7577 and kdu_config.get("terminate-config-primitive")
7578 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7579 ):
7580 terminate_config_primitive_list = kdu_config.get(
7581 "terminate-config-primitive"
7582 )
7583 terminate_config_primitive_list.sort(
7584 key=lambda val: int(val["seq"])
7585 )
7586
7587 for (
7588 terminate_config_primitive
7589 ) in terminate_config_primitive_list:
7590 primitive_params_ = self._map_primitive_params(
7591 terminate_config_primitive, {}, {}
7592 )
7593 step = "execute terminate config primitive"
7594 self.logger.debug(logging_text + step)
7595 await asyncio.wait_for(
7596 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7597 cluster_uuid=cluster_uuid,
7598 kdu_instance=kdu_instance,
7599 primitive_name=terminate_config_primitive["name"],
7600 params=primitive_params_,
7601 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007602 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007603 vca_id=vca_id,
7604 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007605 timeout=self.timeout.primitive
7606 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007607 )
7608
7609 await asyncio.wait_for(
7610 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007611 kdu_instance=kdu_instance,
7612 scale=scale,
7613 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007614 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007615 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007616 cluster_uuid=cluster_uuid,
7617 kdu_model=kdu_model,
7618 atomic=True,
7619 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007620 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007621 timeout=self.timeout.scale_on_error
7622 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007623 )
7624
7625 if kdu_scaling_info["type"] == "create":
7626 kdu_config = get_configuration(db_vnfd, kdu_name)
7627 if (
7628 kdu_config
7629 and kdu_config.get("initial-config-primitive")
7630 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7631 ):
7632 initial_config_primitive_list = kdu_config.get(
7633 "initial-config-primitive"
7634 )
7635 initial_config_primitive_list.sort(
7636 key=lambda val: int(val["seq"])
7637 )
7638
7639 for initial_config_primitive in initial_config_primitive_list:
7640 primitive_params_ = self._map_primitive_params(
7641 initial_config_primitive, {}, {}
7642 )
7643 step = "execute initial config primitive"
7644 self.logger.debug(logging_text + step)
7645 await asyncio.wait_for(
7646 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7647 cluster_uuid=cluster_uuid,
7648 kdu_instance=kdu_instance,
7649 primitive_name=initial_config_primitive["name"],
7650 params=primitive_params_,
7651 db_dict=db_dict,
7652 vca_id=vca_id,
7653 ),
7654 timeout=600,
7655 )
7656
garciadeblas5697b8b2021-03-24 09:17:02 +01007657 async def _scale_ng_ro(
7658 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7659 ):
tierno2357f4e2020-10-19 16:38:59 +00007660 nsr_id = db_nslcmop["nsInstanceId"]
7661 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7662 db_vnfrs = {}
7663
7664 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007665 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007666
7667 # for each vnf in ns, read vnfd
7668 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7669 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7670 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007671 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007672 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007673 # read from db
7674 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007675 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007676 n2vc_key = self.n2vc.get_public_key()
7677 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007678 self.scale_vnfr(
7679 db_vnfr,
7680 vdu_scaling_info.get("vdu-create"),
7681 vdu_scaling_info.get("vdu-delete"),
7682 mark_delete=True,
7683 )
tierno2357f4e2020-10-19 16:38:59 +00007684 # db_vnfr has been updated, update db_vnfrs to use it
7685 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007686 await self._instantiate_ng_ro(
7687 logging_text,
7688 nsr_id,
7689 db_nsd,
7690 db_nsr,
7691 db_nslcmop,
7692 db_vnfrs,
7693 db_vnfds,
7694 n2vc_key_list,
7695 stage=stage,
7696 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007697 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007698 )
tierno2357f4e2020-10-19 16:38:59 +00007699 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007700 self.scale_vnfr(
7701 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7702 )
tierno2357f4e2020-10-19 16:38:59 +00007703
bravof73bac502021-05-11 07:38:47 -04007704 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007705 self,
7706 ee_id: str,
7707 artifact_path: str,
7708 ee_config_descriptor: dict,
7709 vnfr_id: str,
7710 nsr_id: str,
7711 target_ip: str,
7712 element_type: str,
7713 vnf_member_index: str = "",
7714 vdu_id: str = "",
7715 vdu_index: int = None,
7716 kdu_name: str = "",
7717 kdu_index: int = None,
7718 ) -> dict:
7719 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7720 This method will wait until the corresponding VDU or KDU is fully instantiated
7721
7722 Args:
7723 ee_id (str): Execution Environment ID
7724 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7725 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7726 vnfr_id (str): VNFR ID where this EE applies
7727 nsr_id (str): NSR ID where this EE applies
7728 target_ip (str): VDU/KDU instance IP address
7729 element_type (str): NS or VNF or VDU or KDU
7730 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7731 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7732 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7733 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7734 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7735
7736 Raises:
7737 LcmException: When the VDU or KDU instance was not found in an hour
7738
7739 Returns:
7740 _type_: Prometheus jobs
7741 """
7742 # default the vdur and kdur names to an empty string, to avoid any later
7743 # problem with Prometheus when the element type is not VDU or KDU
7744 vdur_name = ""
7745 kdur_name = ""
7746
tiernob996d942020-07-03 14:52:28 +00007747 # look if exist a file called 'prometheus*.j2' and
7748 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007749 job_file = next(
7750 (
7751 f
7752 for f in artifact_content
7753 if f.startswith("prometheus") and f.endswith(".j2")
7754 ),
7755 None,
7756 )
tiernob996d942020-07-03 14:52:28 +00007757 if not job_file:
7758 return
k4.rahul74944982023-04-19 17:00:52 +05307759 self.logger.debug("Artifact path{}".format(artifact_path))
7760 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007761 with self.fs.file_open((artifact_path, job_file), "r") as f:
7762 job_data = f.read()
7763
Pedro Escaleira120695e2022-06-11 21:17:26 +01007764 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7765 if element_type in ("VDU", "KDU"):
7766 for _ in range(360):
7767 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7768 if vdu_id and vdu_index is not None:
7769 vdur = next(
7770 (
7771 x
7772 for x in get_iterable(db_vnfr, "vdur")
7773 if (
7774 x.get("vdu-id-ref") == vdu_id
7775 and x.get("count-index") == vdu_index
7776 )
7777 ),
7778 {},
7779 )
7780 if vdur.get("name"):
7781 vdur_name = vdur.get("name")
7782 break
7783 if kdu_name and kdu_index is not None:
7784 kdur = next(
7785 (
7786 x
7787 for x in get_iterable(db_vnfr, "kdur")
7788 if (
7789 x.get("kdu-name") == kdu_name
7790 and x.get("count-index") == kdu_index
7791 )
7792 ),
7793 {},
7794 )
7795 if kdur.get("name"):
7796 kdur_name = kdur.get("name")
7797 break
7798
Gabriel Cubae7898982023-05-11 01:57:21 -05007799 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007800 else:
7801 if vdu_id and vdu_index is not None:
7802 raise LcmException(
7803 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7804 )
7805 if kdu_name and kdu_index is not None:
7806 raise LcmException(
7807 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7808 )
7809
k4.rahul74944982023-04-19 17:00:52 +05307810 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007811 _, namespace, helm_id = get_ee_id_parts(
7812 ee_id
7813 ) # get namespace and EE gRPC service name
7814 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307815 host_port = "80"
7816 vnfr_id = vnfr_id.replace("-", "")
7817 variables = {
7818 "JOB_NAME": vnfr_id,
7819 "TARGET_IP": target_ip,
7820 "EXPORTER_POD_IP": host_name,
7821 "EXPORTER_POD_PORT": host_port,
7822 "NSR_ID": nsr_id,
7823 "VNF_MEMBER_INDEX": vnf_member_index,
7824 "VDUR_NAME": vdur_name,
7825 "KDUR_NAME": kdur_name,
7826 "ELEMENT_TYPE": element_type,
7827 }
7828 else:
7829 metric_path = ee_config_descriptor["metric-path"]
7830 target_port = ee_config_descriptor["metric-port"]
7831 vnfr_id = vnfr_id.replace("-", "")
7832 variables = {
7833 "JOB_NAME": vnfr_id,
7834 "TARGET_IP": target_ip,
7835 "TARGET_PORT": target_port,
7836 "METRIC_PATH": metric_path,
7837 }
7838
bravof73bac502021-05-11 07:38:47 -04007839 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007840 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7841 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007842 if (
7843 not isinstance(job.get("job_name"), str)
7844 or vnfr_id not in job["job_name"]
7845 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307846 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007847 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007848 job["vnfr_id"] = vnfr_id
7849 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007850
preethika.p28b0bf82022-09-23 07:36:28 +00007851 async def rebuild_start_stop(
7852 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7853 ):
k4.rahulb827de92022-05-02 16:35:02 +00007854 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7855 self.logger.info(logging_text + "Enter")
7856 stage = ["Preparing the environment", ""]
7857 # database nsrs record
7858 db_nsr_update = {}
7859 vdu_vim_name = None
7860 vim_vm_id = None
7861 # in case of error, indicates what part of scale was failed to put nsr at error status
7862 start_deploy = time()
7863 try:
7864 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7865 vim_account_id = db_vnfr.get("vim-account-id")
7866 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007867 vdu_id = additional_param["vdu_id"]
7868 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007869 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007870 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007871 )
k4.rahulb827de92022-05-02 16:35:02 +00007872 if vdur:
7873 vdu_vim_name = vdur["name"]
7874 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7875 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007876 else:
7877 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007878 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7879 # wait for any previous tasks in process
7880 stage[1] = "Waiting for previous operations to terminate"
7881 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007882 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007883
7884 stage[1] = "Reading from database."
7885 self.logger.info(stage[1])
7886 self._write_ns_status(
7887 nsr_id=nsr_id,
7888 ns_state=None,
7889 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007890 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007891 )
7892 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7893
7894 # read from db: ns
7895 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7896 db_nsr_update["operational-status"] = operation_type
7897 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7898 # Payload for RO
7899 desc = {
7900 operation_type: {
7901 "vim_vm_id": vim_vm_id,
7902 "vnf_id": vnf_id,
7903 "vdu_index": additional_param["count-index"],
7904 "vdu_id": vdur["id"],
7905 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007906 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007907 }
7908 }
7909 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7910 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7911 self.logger.info("ro nsr id: {}".format(nsr_id))
7912 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7913 self.logger.info("response from RO: {}".format(result_dict))
7914 action_id = result_dict["action_id"]
7915 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007916 nsr_id,
7917 action_id,
7918 nslcmop_id,
7919 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007920 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007921 None,
7922 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007923 )
7924 return "COMPLETED", "Done"
7925 except (ROclient.ROClientException, DbException, LcmException) as e:
7926 self.logger.error("Exit Exception {}".format(e))
7927 exc = e
7928 except asyncio.CancelledError:
7929 self.logger.error("Cancelled Exception while '{}'".format(stage))
7930 exc = "Operation was cancelled"
7931 except Exception as e:
7932 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007933 self.logger.critical(
7934 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7935 )
k4.rahulb827de92022-05-02 16:35:02 +00007936 return "FAILED", "Error in operate VNF {}".format(exc)
7937
elumalai80bcf1c2022-04-28 18:05:01 +05307938 async def migrate(self, nsr_id, nslcmop_id):
7939 """
7940 Migrate VNFs and VDUs instances in a NS
7941
7942 :param: nsr_id: NS Instance ID
7943 :param: nslcmop_id: nslcmop ID of migrate
7944
7945 """
7946 # Try to lock HA task here
7947 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7948 if not task_is_locked_by_me:
7949 return
7950 logging_text = "Task ns={} migrate ".format(nsr_id)
7951 self.logger.debug(logging_text + "Enter")
7952 # get all needed from database
7953 db_nslcmop = None
7954 db_nslcmop_update = {}
7955 nslcmop_operation_state = None
7956 db_nsr_update = {}
7957 target = {}
7958 exc = None
7959 # in case of error, indicates what part of scale was failed to put nsr at error status
7960 start_deploy = time()
7961
7962 try:
7963 # wait for any previous tasks in process
7964 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007965 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307966
7967 self._write_ns_status(
7968 nsr_id=nsr_id,
7969 ns_state=None,
7970 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007971 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307972 )
7973 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007974 self.logger.debug(
7975 step + " after having waited for previous tasks to be completed"
7976 )
elumalai80bcf1c2022-04-28 18:05:01 +05307977 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7978 migrate_params = db_nslcmop.get("operationParams")
7979
7980 target = {}
7981 target.update(migrate_params)
Pedro Pereirab6cccb22024-08-23 10:23:02 +01007982
7983 if "migrateToHost" in target:
7984 desc = await self.RO.migrate(nsr_id, target)
7985 self.logger.debug("RO return > {}".format(desc))
7986 action_id = desc["action_id"]
7987 await self._wait_ng_ro(
7988 nsr_id,
7989 action_id,
7990 nslcmop_id,
7991 start_deploy,
7992 self.timeout.migrate,
7993 operation="migrate",
7994 )
7995
7996 elif "targetHostK8sLabels" in target:
7997 await self.k8sclusterhelm3.migrate(nsr_id, target)
7998
elumalai80bcf1c2022-04-28 18:05:01 +05307999 except (ROclient.ROClientException, DbException, LcmException) as e:
8000 self.logger.error("Exit Exception {}".format(e))
8001 exc = e
8002 except asyncio.CancelledError:
8003 self.logger.error("Cancelled Exception while '{}'".format(step))
8004 exc = "Operation was cancelled"
8005 except Exception as e:
8006 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03008007 self.logger.critical(
8008 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8009 )
elumalai80bcf1c2022-04-28 18:05:01 +05308010 finally:
8011 self._write_ns_status(
8012 nsr_id=nsr_id,
8013 ns_state=None,
8014 current_operation="IDLE",
8015 current_operation_id=None,
8016 )
8017 if exc:
aticig349aa462022-05-19 12:29:35 +03008018 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308019 nslcmop_operation_state = "FAILED"
8020 else:
8021 nslcmop_operation_state = "COMPLETED"
8022 db_nslcmop_update["detailed-status"] = "Done"
8023 db_nsr_update["detailed-status"] = "Done"
8024
8025 self._write_op_status(
8026 op_id=nslcmop_id,
8027 stage="",
8028 error_message="",
8029 operation_state=nslcmop_operation_state,
8030 other_update=db_nslcmop_update,
8031 )
8032 if nslcmop_operation_state:
8033 try:
8034 msg = {
8035 "nsr_id": nsr_id,
8036 "nslcmop_id": nslcmop_id,
8037 "operationState": nslcmop_operation_state,
8038 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008039 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308040 except Exception as e:
8041 self.logger.error(
8042 logging_text + "kafka_write notification Exception {}".format(e)
8043 )
8044 self.logger.debug(logging_text + "Exit")
8045 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008046
garciadeblas07f4e4c2022-06-09 09:42:58 +02008047 async def heal(self, nsr_id, nslcmop_id):
8048 """
8049 Heal NS
8050
8051 :param nsr_id: ns instance to heal
8052 :param nslcmop_id: operation to run
8053 :return:
8054 """
8055
8056 # Try to lock HA task here
8057 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8058 if not task_is_locked_by_me:
8059 return
8060
8061 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8062 stage = ["", "", ""]
8063 tasks_dict_info = {}
8064 # ^ stage, step, VIM progress
8065 self.logger.debug(logging_text + "Enter")
8066 # get all needed from database
8067 db_nsr = None
8068 db_nslcmop_update = {}
8069 db_nsr_update = {}
8070 db_vnfrs = {} # vnf's info indexed by _id
8071 exc = None
8072 old_operational_status = ""
8073 old_config_status = ""
8074 nsi_id = None
8075 try:
8076 # wait for any previous tasks in process
8077 step = "Waiting for previous operations to terminate"
8078 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8079 self._write_ns_status(
8080 nsr_id=nsr_id,
8081 ns_state=None,
8082 current_operation="HEALING",
8083 current_operation_id=nslcmop_id,
8084 )
8085
8086 step = "Getting nslcmop from database"
8087 self.logger.debug(
8088 step + " after having waited for previous tasks to be completed"
8089 )
8090 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8091
8092 step = "Getting nsr from database"
8093 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8094 old_operational_status = db_nsr["operational-status"]
8095 old_config_status = db_nsr["config-status"]
8096
8097 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008098 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008099 "_admin.deployed.RO.operational-status": "healing",
8100 }
8101 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8102
8103 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008104 await self.heal_RO(
8105 logging_text=logging_text,
8106 nsr_id=nsr_id,
8107 db_nslcmop=db_nslcmop,
8108 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008109 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008110 # VCA tasks
8111 # read from db: nsd
8112 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8113 self.logger.debug(logging_text + stage[1])
8114 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8115 self.fs.sync(db_nsr["nsd-id"])
8116 db_nsr["nsd"] = nsd
8117 # read from db: vnfr's of this ns
8118 step = "Getting vnfrs from db"
8119 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8120 for vnfr in db_vnfrs_list:
8121 db_vnfrs[vnfr["_id"]] = vnfr
8122 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8123
8124 # Check for each target VNF
8125 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8126 for target_vnf in target_list:
8127 # Find this VNF in the list from DB
8128 vnfr_id = target_vnf.get("vnfInstanceId", None)
8129 if vnfr_id:
8130 db_vnfr = db_vnfrs[vnfr_id]
8131 vnfd_id = db_vnfr.get("vnfd-id")
8132 vnfd_ref = db_vnfr.get("vnfd-ref")
8133 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8134 base_folder = vnfd["_admin"]["storage"]
8135 vdu_id = None
8136 vdu_index = 0
8137 vdu_name = None
8138 kdu_name = None
8139 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8140 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8141
8142 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008143 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8144 "vdu", []
8145 )
garciadeblas50639832022-09-01 13:09:47 +02008146 if not target_vdu_list:
8147 # Codigo nuevo para crear diccionario
8148 target_vdu_list = []
8149 for existing_vdu in db_vnfr.get("vdur"):
8150 vdu_name = existing_vdu.get("vdu-name", None)
8151 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008152 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8153 "run-day1", False
8154 )
8155 vdu_to_be_healed = {
8156 "vdu-id": vdu_name,
8157 "count-index": vdu_index,
8158 "run-day1": vdu_run_day1,
8159 }
garciadeblas50639832022-09-01 13:09:47 +02008160 target_vdu_list.append(vdu_to_be_healed)
8161 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008162 deploy_params_vdu = target_vdu
8163 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008164 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8165 "additionalParams", {}
8166 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008167 deploy_params_vdu["run-day1"] = target_vnf[
8168 "additionalParams"
8169 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008170 vdu_name = target_vdu.get("vdu-id", None)
8171 # TODO: Get vdu_id from vdud.
8172 vdu_id = vdu_name
8173 # For multi instance VDU count-index is mandatory
8174 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008175 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008176
8177 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8178 stage[1] = "Deploying Execution Environments."
8179 self.logger.debug(logging_text + stage[1])
8180
8181 # VNF Level charm. Normal case when proxy charms.
8182 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8183 descriptor_config = get_configuration(vnfd, vnfd_ref)
8184 if descriptor_config:
8185 # Continue if healed machine is management machine
8186 vnf_ip_address = db_vnfr.get("ip-address")
8187 target_instance = None
8188 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008189 if (
8190 instance["vdu-name"] == vdu_name
8191 and instance["count-index"] == vdu_index
8192 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008193 target_instance = instance
8194 break
8195 if vnf_ip_address == target_instance.get("ip-address"):
8196 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008197 logging_text=logging_text
8198 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8199 member_vnf_index, vdu_name, vdu_index
8200 ),
8201 db_nsr=db_nsr,
8202 db_vnfr=db_vnfr,
8203 nslcmop_id=nslcmop_id,
8204 nsr_id=nsr_id,
8205 nsi_id=nsi_id,
8206 vnfd_id=vnfd_ref,
8207 vdu_id=None,
8208 kdu_name=None,
8209 member_vnf_index=member_vnf_index,
8210 vdu_index=0,
8211 vdu_name=None,
8212 deploy_params=deploy_params_vdu,
8213 descriptor_config=descriptor_config,
8214 base_folder=base_folder,
8215 task_instantiation_info=tasks_dict_info,
8216 stage=stage,
8217 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008218
8219 # VDU Level charm. Normal case with native charms.
8220 descriptor_config = get_configuration(vnfd, vdu_name)
8221 if descriptor_config:
8222 self._heal_n2vc(
8223 logging_text=logging_text
8224 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8225 member_vnf_index, vdu_name, vdu_index
8226 ),
8227 db_nsr=db_nsr,
8228 db_vnfr=db_vnfr,
8229 nslcmop_id=nslcmop_id,
8230 nsr_id=nsr_id,
8231 nsi_id=nsi_id,
8232 vnfd_id=vnfd_ref,
8233 vdu_id=vdu_id,
8234 kdu_name=kdu_name,
8235 member_vnf_index=member_vnf_index,
8236 vdu_index=vdu_index,
8237 vdu_name=vdu_name,
8238 deploy_params=deploy_params_vdu,
8239 descriptor_config=descriptor_config,
8240 base_folder=base_folder,
8241 task_instantiation_info=tasks_dict_info,
8242 stage=stage,
8243 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008244 except (
8245 ROclient.ROClientException,
8246 DbException,
8247 LcmException,
8248 NgRoException,
8249 ) as e:
8250 self.logger.error(logging_text + "Exit Exception {}".format(e))
8251 exc = e
8252 except asyncio.CancelledError:
8253 self.logger.error(
8254 logging_text + "Cancelled Exception while '{}'".format(step)
8255 )
8256 exc = "Operation was cancelled"
8257 except Exception as e:
8258 exc = traceback.format_exc()
8259 self.logger.critical(
8260 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8261 exc_info=True,
8262 )
8263 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008264 error_list = list()
36970544ef442024-04-01 10:58:42 +00008265 if db_vnfrs_list and target_list:
8266 for vnfrs in db_vnfrs_list:
8267 for vnf_instance in target_list:
8268 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8269 self.db.set_list(
8270 "vnfrs",
8271 {"_id": vnfrs["_id"]},
8272 {"_admin.modified": time()},
8273 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008274 if exc:
8275 error_list.append(str(exc))
8276 try:
8277 if tasks_dict_info:
8278 stage[1] = "Waiting for healing pending tasks."
8279 self.logger.debug(logging_text + stage[1])
8280 exc = await self._wait_for_tasks(
8281 logging_text,
8282 tasks_dict_info,
8283 self.timeout.ns_deploy,
8284 stage,
8285 nslcmop_id,
8286 nsr_id=nsr_id,
8287 )
8288 except asyncio.CancelledError:
8289 error_list.append("Cancelled")
8290 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8291 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008292 logging_text,
8293 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008294 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008295 stage,
8296 nslcmop_id,
8297 nsr_id=nsr_id,
8298 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008299 if error_list:
8300 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008301 db_nslcmop_update[
8302 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008303 ] = error_description_nslcmop = "FAILED {}: {}".format(
8304 step, error_detail
8305 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008306 nslcmop_operation_state = "FAILED"
8307 if db_nsr:
8308 db_nsr_update["operational-status"] = old_operational_status
8309 db_nsr_update["config-status"] = old_config_status
8310 db_nsr_update[
8311 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008312 ] = "FAILED healing nslcmop={} {}: {}".format(
8313 nslcmop_id, step, error_detail
8314 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008315 for task, task_name in tasks_dict_info.items():
8316 if not task.done() or task.cancelled() or task.exception():
8317 if task_name.startswith(self.task_name_deploy_vca):
8318 # A N2VC task is pending
8319 db_nsr_update["config-status"] = "failed"
8320 else:
8321 # RO task is pending
8322 db_nsr_update["operational-status"] = "failed"
8323 else:
8324 error_description_nslcmop = None
8325 nslcmop_operation_state = "COMPLETED"
8326 db_nslcmop_update["detailed-status"] = "Done"
8327 db_nsr_update["detailed-status"] = "Done"
8328 db_nsr_update["operational-status"] = "running"
8329 db_nsr_update["config-status"] = "configured"
8330
8331 self._write_op_status(
8332 op_id=nslcmop_id,
8333 stage="",
8334 error_message=error_description_nslcmop,
8335 operation_state=nslcmop_operation_state,
8336 other_update=db_nslcmop_update,
8337 )
8338 if db_nsr:
8339 self._write_ns_status(
8340 nsr_id=nsr_id,
8341 ns_state=None,
8342 current_operation="IDLE",
8343 current_operation_id=None,
8344 other_update=db_nsr_update,
8345 )
8346
8347 if nslcmop_operation_state:
8348 try:
8349 msg = {
8350 "nsr_id": nsr_id,
8351 "nslcmop_id": nslcmop_id,
8352 "operationState": nslcmop_operation_state,
8353 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008354 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008355 except Exception as e:
8356 self.logger.error(
8357 logging_text + "kafka_write notification Exception {}".format(e)
8358 )
8359 self.logger.debug(logging_text + "Exit")
8360 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8361
8362 async def heal_RO(
8363 self,
8364 logging_text,
8365 nsr_id,
8366 db_nslcmop,
8367 stage,
8368 ):
8369 """
8370 Heal at RO
8371 :param logging_text: preffix text to use at logging
8372 :param nsr_id: nsr identity
8373 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8374 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8375 :return: None or exception
8376 """
preethika.p28b0bf82022-09-23 07:36:28 +00008377
garciadeblas07f4e4c2022-06-09 09:42:58 +02008378 def get_vim_account(vim_account_id):
8379 nonlocal db_vims
8380 if vim_account_id in db_vims:
8381 return db_vims[vim_account_id]
8382 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8383 db_vims[vim_account_id] = db_vim
8384 return db_vim
8385
8386 try:
8387 start_heal = time()
8388 ns_params = db_nslcmop.get("operationParams")
8389 if ns_params and ns_params.get("timeout_ns_heal"):
8390 timeout_ns_heal = ns_params["timeout_ns_heal"]
8391 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008392 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008393
8394 db_vims = {}
8395
8396 nslcmop_id = db_nslcmop["_id"]
8397 target = {
8398 "action_id": nslcmop_id,
8399 }
preethika.p28b0bf82022-09-23 07:36:28 +00008400 self.logger.warning(
8401 "db_nslcmop={} and timeout_ns_heal={}".format(
8402 db_nslcmop, timeout_ns_heal
8403 )
8404 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008405 target.update(db_nslcmop.get("operationParams", {}))
8406
8407 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8408 desc = await self.RO.recreate(nsr_id, target)
8409 self.logger.debug("RO return > {}".format(desc))
8410 action_id = desc["action_id"]
8411 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8412 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008413 nsr_id,
8414 action_id,
8415 nslcmop_id,
8416 start_heal,
8417 timeout_ns_heal,
8418 stage,
8419 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008420 )
8421
8422 # Updating NSR
8423 db_nsr_update = {
8424 "_admin.deployed.RO.operational-status": "running",
8425 "detailed-status": " ".join(stage),
8426 }
8427 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8428 self._write_op_status(nslcmop_id, stage)
8429 self.logger.debug(
8430 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8431 )
8432
8433 except Exception as e:
8434 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008435 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008436 self.logger.error(
8437 "Error healing at VIM {}".format(e),
8438 exc_info=not isinstance(
8439 e,
8440 (
8441 ROclient.ROClientException,
8442 LcmException,
8443 DbException,
8444 NgRoException,
8445 ),
8446 ),
8447 )
8448 raise
8449
8450 def _heal_n2vc(
8451 self,
8452 logging_text,
8453 db_nsr,
8454 db_vnfr,
8455 nslcmop_id,
8456 nsr_id,
8457 nsi_id,
8458 vnfd_id,
8459 vdu_id,
8460 kdu_name,
8461 member_vnf_index,
8462 vdu_index,
8463 vdu_name,
8464 deploy_params,
8465 descriptor_config,
8466 base_folder,
8467 task_instantiation_info,
8468 stage,
8469 ):
8470 # launch instantiate_N2VC in a asyncio task and register task object
8471 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8472 # if not found, create one entry and update database
8473 # fill db_nsr._admin.deployed.VCA.<index>
8474
8475 self.logger.debug(
8476 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8477 )
aticig9bc63ac2022-07-27 09:32:06 +03008478
8479 charm_name = ""
8480 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008481 if "execution-environment-list" in descriptor_config:
8482 ee_list = descriptor_config.get("execution-environment-list", [])
8483 elif "juju" in descriptor_config:
8484 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008485 if "execution-environment-list" not in descriptor_config:
8486 # charm name is only required for ns charms
8487 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008488 else: # other types as script are not supported
8489 ee_list = []
8490
8491 for ee_item in ee_list:
8492 self.logger.debug(
8493 logging_text
8494 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8495 ee_item.get("juju"), ee_item.get("helm-chart")
8496 )
8497 )
8498 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008499 vca_name, charm_name, vca_type = self.get_vca_info(
8500 ee_item, db_nsr, get_charm_name
8501 )
8502 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008503 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008504 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008505 )
8506 continue
8507
8508 vca_index = -1
8509 for vca_index, vca_deployed in enumerate(
8510 db_nsr["_admin"]["deployed"]["VCA"]
8511 ):
8512 if not vca_deployed:
8513 continue
8514 if (
8515 vca_deployed.get("member-vnf-index") == member_vnf_index
8516 and vca_deployed.get("vdu_id") == vdu_id
8517 and vca_deployed.get("kdu_name") == kdu_name
8518 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8519 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8520 ):
8521 break
8522 else:
8523 # not found, create one.
8524 target = (
8525 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8526 )
8527 if vdu_id:
8528 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8529 elif kdu_name:
8530 target += "/kdu/{}".format(kdu_name)
8531 vca_deployed = {
8532 "target_element": target,
8533 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8534 "member-vnf-index": member_vnf_index,
8535 "vdu_id": vdu_id,
8536 "kdu_name": kdu_name,
8537 "vdu_count_index": vdu_index,
8538 "operational-status": "init", # TODO revise
8539 "detailed-status": "", # TODO revise
8540 "step": "initial-deploy", # TODO revise
8541 "vnfd_id": vnfd_id,
8542 "vdu_name": vdu_name,
8543 "type": vca_type,
8544 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008545 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008546 }
8547 vca_index += 1
8548
8549 # create VCA and configurationStatus in db
8550 db_dict = {
8551 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8552 "configurationStatus.{}".format(vca_index): dict(),
8553 }
8554 self.update_db_2("nsrs", nsr_id, db_dict)
8555
8556 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8557
8558 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8559 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8560 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8561
8562 # Launch task
8563 task_n2vc = asyncio.ensure_future(
8564 self.heal_N2VC(
8565 logging_text=logging_text,
8566 vca_index=vca_index,
8567 nsi_id=nsi_id,
8568 db_nsr=db_nsr,
8569 db_vnfr=db_vnfr,
8570 vdu_id=vdu_id,
8571 kdu_name=kdu_name,
8572 vdu_index=vdu_index,
8573 deploy_params=deploy_params,
8574 config_descriptor=descriptor_config,
8575 base_folder=base_folder,
8576 nslcmop_id=nslcmop_id,
8577 stage=stage,
8578 vca_type=vca_type,
8579 vca_name=vca_name,
8580 ee_config_descriptor=ee_item,
8581 )
8582 )
8583 self.lcm_tasks.register(
8584 "ns",
8585 nsr_id,
8586 nslcmop_id,
8587 "instantiate_N2VC-{}".format(vca_index),
8588 task_n2vc,
8589 )
8590 task_instantiation_info[
8591 task_n2vc
8592 ] = self.task_name_deploy_vca + " {}.{}".format(
8593 member_vnf_index or "", vdu_id or ""
8594 )
8595
8596 async def heal_N2VC(
8597 self,
8598 logging_text,
8599 vca_index,
8600 nsi_id,
8601 db_nsr,
8602 db_vnfr,
8603 vdu_id,
8604 kdu_name,
8605 vdu_index,
8606 config_descriptor,
8607 deploy_params,
8608 base_folder,
8609 nslcmop_id,
8610 stage,
8611 vca_type,
8612 vca_name,
8613 ee_config_descriptor,
8614 ):
8615 nsr_id = db_nsr["_id"]
8616 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8617 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8618 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8619 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8620 db_dict = {
8621 "collection": "nsrs",
8622 "filter": {"_id": nsr_id},
8623 "path": db_update_entry,
8624 }
8625 step = ""
8626 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008627 element_type = "NS"
8628 element_under_configuration = nsr_id
8629
8630 vnfr_id = None
8631 if db_vnfr:
8632 vnfr_id = db_vnfr["_id"]
8633 osm_config["osm"]["vnf_id"] = vnfr_id
8634
8635 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8636
8637 if vca_type == "native_charm":
8638 index_number = 0
8639 else:
8640 index_number = vdu_index or 0
8641
8642 if vnfr_id:
8643 element_type = "VNF"
8644 element_under_configuration = vnfr_id
8645 namespace += ".{}-{}".format(vnfr_id, index_number)
8646 if vdu_id:
8647 namespace += ".{}-{}".format(vdu_id, index_number)
8648 element_type = "VDU"
8649 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8650 osm_config["osm"]["vdu_id"] = vdu_id
8651 elif kdu_name:
8652 namespace += ".{}".format(kdu_name)
8653 element_type = "KDU"
8654 element_under_configuration = kdu_name
8655 osm_config["osm"]["kdu_name"] = kdu_name
8656
8657 # Get artifact path
8658 if base_folder["pkg-dir"]:
8659 artifact_path = "{}/{}/{}/{}".format(
8660 base_folder["folder"],
8661 base_folder["pkg-dir"],
8662 "charms"
8663 if vca_type
8664 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8665 else "helm-charts",
8666 vca_name,
8667 )
8668 else:
8669 artifact_path = "{}/Scripts/{}/{}/".format(
8670 base_folder["folder"],
8671 "charms"
8672 if vca_type
8673 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8674 else "helm-charts",
8675 vca_name,
8676 )
8677
8678 self.logger.debug("Artifact path > {}".format(artifact_path))
8679
8680 # get initial_config_primitive_list that applies to this element
8681 initial_config_primitive_list = config_descriptor.get(
8682 "initial-config-primitive"
8683 )
8684
8685 self.logger.debug(
8686 "Initial config primitive list > {}".format(
8687 initial_config_primitive_list
8688 )
8689 )
8690
8691 # add config if not present for NS charm
8692 ee_descriptor_id = ee_config_descriptor.get("id")
8693 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8694 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8695 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8696 )
8697
8698 self.logger.debug(
8699 "Initial config primitive list #2 > {}".format(
8700 initial_config_primitive_list
8701 )
8702 )
8703 # n2vc_redesign STEP 3.1
8704 # find old ee_id if exists
8705 ee_id = vca_deployed.get("ee_id")
8706
8707 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8708 # create or register execution environment in VCA. Only for native charms when healing
8709 if vca_type == "native_charm":
8710 step = "Waiting to VM being up and getting IP address"
8711 self.logger.debug(logging_text + step)
8712 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8713 logging_text,
8714 nsr_id,
8715 vnfr_id,
8716 vdu_id,
8717 vdu_index,
8718 user=None,
8719 pub_key=None,
8720 )
8721 credentials = {"hostname": rw_mgmt_ip}
8722 # get username
8723 username = deep_get(
8724 config_descriptor, ("config-access", "ssh-access", "default-user")
8725 )
8726 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8727 # merged. Meanwhile let's get username from initial-config-primitive
8728 if not username and initial_config_primitive_list:
8729 for config_primitive in initial_config_primitive_list:
8730 for param in config_primitive.get("parameter", ()):
8731 if param["name"] == "ssh-username":
8732 username = param["value"]
8733 break
8734 if not username:
8735 raise LcmException(
8736 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8737 "'config-access.ssh-access.default-user'"
8738 )
8739 credentials["username"] = username
8740
8741 # n2vc_redesign STEP 3.2
8742 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8743 self._write_configuration_status(
8744 nsr_id=nsr_id,
8745 vca_index=vca_index,
8746 status="REGISTERING",
8747 element_under_configuration=element_under_configuration,
8748 element_type=element_type,
8749 )
8750
8751 step = "register execution environment {}".format(credentials)
8752 self.logger.debug(logging_text + step)
8753 ee_id = await self.vca_map[vca_type].register_execution_environment(
8754 credentials=credentials,
8755 namespace=namespace,
8756 db_dict=db_dict,
8757 vca_id=vca_id,
8758 )
8759
8760 # update ee_id en db
8761 db_dict_ee_id = {
8762 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8763 }
8764 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8765
8766 # for compatibility with MON/POL modules, the need model and application name at database
8767 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8768 # Not sure if this need to be done when healing
8769 """
8770 ee_id_parts = ee_id.split(".")
8771 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8772 if len(ee_id_parts) >= 2:
8773 model_name = ee_id_parts[0]
8774 application_name = ee_id_parts[1]
8775 db_nsr_update[db_update_entry + "model"] = model_name
8776 db_nsr_update[db_update_entry + "application"] = application_name
8777 """
8778
8779 # n2vc_redesign STEP 3.3
8780 # Install configuration software. Only for native charms.
8781 step = "Install configuration Software"
8782
8783 self._write_configuration_status(
8784 nsr_id=nsr_id,
8785 vca_index=vca_index,
8786 status="INSTALLING SW",
8787 element_under_configuration=element_under_configuration,
8788 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008789 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008790 other_update=None,
8791 )
8792
8793 # TODO check if already done
8794 self.logger.debug(logging_text + step)
8795 config = None
8796 if vca_type == "native_charm":
8797 config_primitive = next(
8798 (p for p in initial_config_primitive_list if p["name"] == "config"),
8799 None,
8800 )
8801 if config_primitive:
8802 config = self._map_primitive_params(
8803 config_primitive, {}, deploy_params
8804 )
8805 await self.vca_map[vca_type].install_configuration_sw(
8806 ee_id=ee_id,
8807 artifact_path=artifact_path,
8808 db_dict=db_dict,
8809 config=config,
8810 num_units=1,
8811 vca_id=vca_id,
8812 vca_type=vca_type,
8813 )
8814
8815 # write in db flag of configuration_sw already installed
8816 self.update_db_2(
8817 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8818 )
8819
8820 # Not sure if this need to be done when healing
8821 """
8822 # add relations for this VCA (wait for other peers related with this VCA)
8823 await self._add_vca_relations(
8824 logging_text=logging_text,
8825 nsr_id=nsr_id,
8826 vca_type=vca_type,
8827 vca_index=vca_index,
8828 )
8829 """
8830
8831 # if SSH access is required, then get execution environment SSH public
8832 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00008833 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008834 pub_key = None
8835 user = None
8836 # self.logger.debug("get ssh key block")
8837 if deep_get(
8838 config_descriptor, ("config-access", "ssh-access", "required")
8839 ):
8840 # self.logger.debug("ssh key needed")
8841 # Needed to inject a ssh key
8842 user = deep_get(
8843 config_descriptor,
8844 ("config-access", "ssh-access", "default-user"),
8845 )
8846 step = "Install configuration Software, getting public ssh key"
8847 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8848 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8849 )
8850
8851 step = "Insert public key into VM user={} ssh_key={}".format(
8852 user, pub_key
8853 )
8854 else:
8855 # self.logger.debug("no need to get ssh key")
8856 step = "Waiting to VM being up and getting IP address"
8857 self.logger.debug(logging_text + step)
8858
8859 # n2vc_redesign STEP 5.1
8860 # wait for RO (ip-address) Insert pub_key into VM
8861 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008862 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008863 if vnfr_id:
8864 if kdu_name:
8865 rw_mgmt_ip = await self.wait_kdu_up(
8866 logging_text, nsr_id, vnfr_id, kdu_name
8867 )
8868 else:
8869 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8870 logging_text,
8871 nsr_id,
8872 vnfr_id,
8873 vdu_id,
8874 vdu_index,
8875 user=user,
8876 pub_key=pub_key,
8877 )
8878 else:
8879 rw_mgmt_ip = None # This is for a NS configuration
8880
8881 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8882
8883 # store rw_mgmt_ip in deploy params for later replacement
8884 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8885
8886 # Day1 operations.
8887 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008888 runDay1 = deploy_params.get("run-day1", False)
8889 self.logger.debug(
8890 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8891 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008892 if runDay1:
8893 # n2vc_redesign STEP 6 Execute initial config primitive
8894 step = "execute initial config primitive"
8895
8896 # wait for dependent primitives execution (NS -> VNF -> VDU)
8897 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008898 await self._wait_dependent_n2vc(
8899 nsr_id, vca_deployed_list, vca_index
8900 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008901
8902 # stage, in function of element type: vdu, kdu, vnf or ns
8903 my_vca = vca_deployed_list[vca_index]
8904 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8905 # VDU or KDU
8906 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8907 elif my_vca.get("member-vnf-index"):
8908 # VNF
8909 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8910 else:
8911 # NS
8912 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8913
8914 self._write_configuration_status(
8915 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8916 )
8917
8918 self._write_op_status(op_id=nslcmop_id, stage=stage)
8919
8920 check_if_terminated_needed = True
8921 for initial_config_primitive in initial_config_primitive_list:
8922 # adding information on the vca_deployed if it is a NS execution environment
8923 if not vca_deployed["member-vnf-index"]:
8924 deploy_params["ns_config_info"] = json.dumps(
8925 self._get_ns_config_info(nsr_id)
8926 )
8927 # TODO check if already done
8928 primitive_params_ = self._map_primitive_params(
8929 initial_config_primitive, {}, deploy_params
8930 )
8931
8932 step = "execute primitive '{}' params '{}'".format(
8933 initial_config_primitive["name"], primitive_params_
8934 )
8935 self.logger.debug(logging_text + step)
8936 await self.vca_map[vca_type].exec_primitive(
8937 ee_id=ee_id,
8938 primitive_name=initial_config_primitive["name"],
8939 params_dict=primitive_params_,
8940 db_dict=db_dict,
8941 vca_id=vca_id,
8942 vca_type=vca_type,
8943 )
8944 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8945 if check_if_terminated_needed:
8946 if config_descriptor.get("terminate-config-primitive"):
8947 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008948 "nsrs",
8949 nsr_id,
8950 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008951 )
8952 check_if_terminated_needed = False
8953
8954 # TODO register in database that primitive is done
8955
8956 # STEP 7 Configure metrics
8957 # Not sure if this need to be done when healing
8958 """
8959 if vca_type == "helm" or vca_type == "helm-v3":
8960 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8961 ee_id=ee_id,
8962 artifact_path=artifact_path,
8963 ee_config_descriptor=ee_config_descriptor,
8964 vnfr_id=vnfr_id,
8965 nsr_id=nsr_id,
8966 target_ip=rw_mgmt_ip,
8967 )
8968 if prometheus_jobs:
8969 self.update_db_2(
8970 "nsrs",
8971 nsr_id,
8972 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8973 )
8974
8975 for job in prometheus_jobs:
8976 self.db.set_one(
8977 "prometheus_jobs",
8978 {"job_name": job["job_name"]},
8979 job,
8980 upsert=True,
8981 fail_on_empty=False,
8982 )
8983
8984 """
8985 step = "instantiated at VCA"
8986 self.logger.debug(logging_text + step)
8987
8988 self._write_configuration_status(
8989 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8990 )
8991
8992 except Exception as e: # TODO not use Exception but N2VC exception
8993 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8994 if not isinstance(
8995 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8996 ):
8997 self.logger.error(
8998 "Exception while {} : {}".format(step, e), exc_info=True
8999 )
9000 self._write_configuration_status(
9001 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
9002 )
9003 raise LcmException("{} {}".format(step, e)) from e
9004
9005 async def _wait_heal_ro(
9006 self,
9007 nsr_id,
9008 timeout=600,
9009 ):
9010 start_time = time()
9011 while time() <= start_time + timeout:
9012 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009013 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9014 "operational-status"
9015 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009016 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9017 if operational_status_ro != "healing":
9018 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009019 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009020 else: # timeout_ns_deploy
9021 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309022
9023 async def vertical_scale(self, nsr_id, nslcmop_id):
9024 """
9025 Vertical Scale the VDUs in a NS
9026
9027 :param: nsr_id: NS Instance ID
9028 :param: nslcmop_id: nslcmop ID of migrate
9029
9030 """
govindarajul4ff4b512022-05-02 20:02:41 +05309031 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05309032 self.logger.info(logging_text + "Enter")
9033 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05309034 # get all needed from database
9035 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05309036 db_nsr_update = {}
9037 target = {}
9038 exc = None
9039 # in case of error, indicates what part of scale was failed to put nsr at error status
9040 start_deploy = time()
9041
9042 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05309043 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9044 operationParams = db_nslcmop.get("operationParams")
9045 vertical_scale_data = operationParams["verticalScaleVnf"]
9046 vnfd_id = vertical_scale_data["vnfdId"]
9047 count_index = vertical_scale_data["countIndex"]
9048 vdu_id_ref = vertical_scale_data["vduId"]
9049 vnfr_id = vertical_scale_data["vnfInstanceId"]
9050 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9051 db_flavor = db_nsr.get("flavor")
9052 db_flavor_index = str(len(db_flavor))
9053
9054 def set_flavor_refrence_to_vdur(diff=0):
9055 """
9056 Utility function to add and remove the
9057 ref to new ns-flavor-id to vdurs
9058 :param: diff: default 0
9059 """
9060 q_filter = {}
9061 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9062 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9063 if (
9064 vdur.get("count-index") == count_index
9065 and vdur.get("vdu-id-ref") == vdu_id_ref
9066 ):
9067 filter_text = {
9068 "_id": vnfr_id,
9069 "vdur.count-index": count_index,
9070 "vdur.vdu-id-ref": vdu_id_ref,
9071 }
9072 q_filter.update(filter_text)
9073 db_update = {}
9074 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9075 int(db_flavor_index) - diff
9076 )
9077 self.db.set_one(
9078 "vnfrs",
9079 q_filter=q_filter,
9080 update_dict=db_update,
9081 fail_on_empty=True,
9082 )
9083
govindarajul4ff4b512022-05-02 20:02:41 +05309084 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309085 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009086 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309087
9088 self._write_ns_status(
9089 nsr_id=nsr_id,
9090 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309091 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009092 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309093 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309094 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009095 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309096 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009097 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309098 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9099 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9100 virtual_compute = vnfd["virtual-compute-desc"][0]
9101 virtual_memory = round(
9102 float(virtual_compute["virtual-memory"]["size"]) * 1024
9103 )
9104 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9105 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009106 flavor_dict_update = {
9107 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309108 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009109 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309110 "storage-gb": str(virtual_storage),
9111 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009112 }
9113 db_flavor.append(flavor_dict_update)
9114 db_update = {}
9115 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309116 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009117 "_id": nsr_id,
9118 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309119 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009120 self.db.set_one(
9121 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309122 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009123 update_dict=db_update,
9124 fail_on_empty=True,
9125 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309126 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309127 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309128 new_operationParams = {
9129 "lcmOperationType": "verticalscale",
9130 "verticalScale": "CHANGE_VNFFLAVOR",
9131 "nsInstanceId": nsr_id,
9132 "changeVnfFlavorData": {
9133 "vnfInstanceId": vnfr_id,
9134 "additionalParams": {
9135 "vduid": vdu_id_ref,
9136 "vduCountIndex": count_index,
9137 "virtualMemory": virtual_memory,
9138 "numVirtualCpu": int(virtual_cpu),
9139 "sizeOfStorage": int(virtual_storage),
9140 },
9141 },
9142 }
9143 target.update(new_operationParams)
9144
9145 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9146 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9147 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309148 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309149 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309150 action_id = desc["action_id"]
9151 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009152 nsr_id,
9153 action_id,
9154 nslcmop_id,
9155 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009156 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009157 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309158 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009159 except (
9160 NgRoException,
9161 ROclient.ROClientException,
9162 DbException,
9163 LcmException,
9164 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309165 self.logger.error("Exit Exception {}".format(e))
9166 exc = e
9167 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309168 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309169 exc = "Operation was cancelled"
9170 except Exception as e:
9171 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009172 self.logger.critical(
9173 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9174 )
govindarajul4ff4b512022-05-02 20:02:41 +05309175 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309176 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009177 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309178 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009179 )
9180 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309181 "nsrs",
9182 {"_id": nsr_id},
9183 None,
9184 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009185 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309186 set_flavor_refrence_to_vdur(diff=1)
9187 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9188 else:
9189 return "COMPLETED", "Done"