blob: bad1b1f3ec212fcc3388879ad80aff9e550aa763 [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,
David Garciab4ebcd02021-10-28 02:00:43 +020087 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030088 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050089 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010090)
bravof922c4172020-11-24 21:21:43 -030091from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030092from osm_lcm.data_utils.vnfr import (
93 get_osm_params,
94 get_vdur_index,
95 get_kdur,
96 get_volumes_from_instantiation_params,
97)
bravof922c4172020-11-24 21:21:43 -030098from osm_lcm.data_utils.dict_utils import parse_yaml_strings
99from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +0200100from n2vc.definitions import RelationEndpoint
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000101from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -0500102from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200103
tierno27246d82018-09-27 15:59:09 +0200104from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200105from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200106
bravof922c4172020-11-24 21:21:43 -0300107from osm_lcm.data_utils.database.database import Database
108from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000109from osm_lcm.data_utils.wim import (
110 get_sdn_ports,
111 get_target_wim_attrs,
112 select_feasible_wim_account,
113)
bravof922c4172020-11-24 21:21:43 -0300114
quilesj7e13aeb2019-10-08 13:34:55 +0200115from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000116from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200117
tierno588547c2020-07-01 15:30:20 +0000118from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200119from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400120from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000121
tierno27246d82018-09-27 15:59:09 +0200122from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200123from time import time
tierno27246d82018-09-27 15:59:09 +0200124from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000125
k4.rahulcf47a3b2023-04-27 12:08:48 +0530126from random import SystemRandom
tierno59d22d22018-09-25 18:10:19 +0200127
tierno69f0d382020-05-07 13:08:09 +0000128__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200129
130
131class NsLcm(LcmBase):
kuuseac3a8882019-10-03 10:48:06 +0200132 SUBOPERATION_STATUS_NOT_FOUND = -1
133 SUBOPERATION_STATUS_NEW = -2
134 SUBOPERATION_STATUS_SKIP = -3
Gabriel Cubaeb585dd2023-04-25 16:48:41 -0500135 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000136 task_name_deploy_vca = "Deploying VCA"
garciadeblas9148fa82023-05-30 12:51:14 +0200137 rel_operation_types = {
138 "GE": ">=",
139 "LE": "<=",
140 "GT": ">",
141 "LT": "<",
142 "EQ": "==",
143 "NE": "!=",
144 }
kuuseac3a8882019-10-03 10:48:06 +0200145
Gabriel Cubae7898982023-05-11 01:57:21 -0500146 def __init__(self, msg, lcm_tasks, config: LcmCfg):
tierno59d22d22018-09-25 18:10:19 +0200147 """
148 Init, Connect to database, filesystem storage, and messaging
149 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
150 :return: None
151 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100152 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200153
bravof922c4172020-11-24 21:21:43 -0300154 self.db = Database().instance.db
155 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200156 self.lcm_tasks = lcm_tasks
Luis Vegaa27dc532022-11-11 20:10:49 +0000157 self.timeout = config.timeout
158 self.ro_config = config.RO
159 self.vca_config = config.VCA
tierno59d22d22018-09-25 18:10:19 +0200160
quilesj7e13aeb2019-10-08 13:34:55 +0200161 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100162 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200163 log=self.logger,
bravof922c4172020-11-24 21:21:43 -0300164 on_update_db=self._on_update_n2vc_db,
165 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100166 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200167 )
quilesj7e13aeb2019-10-08 13:34:55 +0200168
tierno588547c2020-07-01 15:30:20 +0000169 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000170 log=self.logger,
tierno588547c2020-07-01 15:30:20 +0000171 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100172 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000173 )
174
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000175 self.k8sclusterhelm3 = K8sHelm3Connector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000176 kubectl_command=self.vca_config.kubectlpath,
177 helm_command=self.vca_config.helm3path,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000178 fs=self.fs,
179 log=self.logger,
180 db=self.db,
181 on_update_db=None,
182 )
183
Adam Israelbaacc302019-12-01 12:41:39 -0500184 self.k8sclusterjuju = K8sJujuConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000185 kubectl_command=self.vca_config.kubectlpath,
186 juju_command=self.vca_config.jujupath,
Adam Israelbaacc302019-12-01 12:41:39 -0500187 log=self.logger,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530188 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300189 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100190 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500191 )
192
tiernoa2143262020-03-27 16:20:40 +0000193 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000194 "helm-chart-v3": self.k8sclusterhelm3,
195 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000196 "juju-bundle": self.k8sclusterjuju,
197 "juju": self.k8sclusterjuju,
198 }
tierno588547c2020-07-01 15:30:20 +0000199
200 self.vca_map = {
201 "lxc_proxy_charm": self.n2vc,
202 "native_charm": self.n2vc,
203 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000204 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100205 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000206 }
207
quilesj7e13aeb2019-10-08 13:34:55 +0200208 # create RO client
Gabriel Cubae7898982023-05-11 01:57:21 -0500209 self.RO = NgRoClient(**self.ro_config.to_dict())
tierno59d22d22018-09-25 18:10:19 +0200210
garciadeblas07f4e4c2022-06-09 09:42:58 +0200211 self.op_status_map = {
212 "instantiation": self.RO.status,
213 "termination": self.RO.status,
214 "migrate": self.RO.status,
215 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000216 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000217 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200218 }
219
tierno2357f4e2020-10-19 16:38:59 +0000220 @staticmethod
221 def increment_ip_mac(ip_mac, vm_index=1):
222 if not isinstance(ip_mac, str):
223 return ip_mac
224 try:
rahul72d90d92023-08-30 14:48:01 +0530225 next_ipv6 = None
226 next_ipv4 = None
227 dual_ip = ip_mac.split(";")
228 if len(dual_ip) == 2:
229 for ip in dual_ip:
230 if ipaddress.ip_address(ip).version == 6:
231 ipv6 = ipaddress.IPv6Address(ip)
232 next_ipv6 = str(ipaddress.IPv6Address(int(ipv6) + 1))
233 elif ipaddress.ip_address(ip).version == 4:
234 ipv4 = ipaddress.IPv4Address(ip)
235 next_ipv4 = str(ipaddress.IPv4Address(int(ipv4) + 1))
236 return [next_ipv4, next_ipv6]
tierno2357f4e2020-10-19 16:38:59 +0000237 # try with ipv4 look for last dot
238 i = ip_mac.rfind(".")
239 if i > 0:
240 i += 1
241 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
242 # try with ipv6 or mac look for last colon. Operate in hex
243 i = ip_mac.rfind(":")
244 if i > 0:
245 i += 1
246 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100247 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
248 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
249 )
tierno2357f4e2020-10-19 16:38:59 +0000250 except Exception:
251 pass
252 return None
253
David Garciac1fe90a2021-03-31 19:12:02 +0200254 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000255 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100256 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000257 path = path[:-1]
258
quilesj3655ae02019-12-12 16:08:35 +0000259 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
260 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000261 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100262 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000263
264 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100265 nsr = self.db.get_one(table="nsrs", q_filter=filter)
266 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000267
3697083243632024-06-07 05:44:08 +0000268 # First, we need to verify if the current vcaStatus is null, because if that is the case,
269 # MongoDB will not be able to create the fields used within the update key in the database
270 if not nsr.get("vcaStatus"):
271 # Write an empty dictionary to the vcaStatus field, it its value is null
272 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
273
274 # Get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100275 status_dict = await self.n2vc.get_status(
276 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
277 )
quilesj3655ae02019-12-12 16:08:35 +0000278
3697083243632024-06-07 05:44:08 +0000279 # Update the vcaStatus
280 db_key = f"vcaStatus.{nsr_id}.VNF"
quilesj3655ae02019-12-12 16:08:35 +0000281 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000282
283 db_dict[db_key] = status_dict[nsr_id]
284 await self.n2vc.update_vca_status(db_dict[db_key], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000285
286 # update configurationStatus for this VCA
287 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100288 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000289
garciadeblas5697b8b2021-03-24 09:17:02 +0100290 vca_list = deep_get(
291 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
292 )
293 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000294
garciadeblas5697b8b2021-03-24 09:17:02 +0100295 configuration_status_list = nsr.get("configurationStatus")
296 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000297
garciadeblas5697b8b2021-03-24 09:17:02 +0100298 if config_status == "BROKEN" and vca_status != "failed":
299 db_dict["configurationStatus"][vca_index] = "READY"
300 elif config_status != "BROKEN" and vca_status == "failed":
301 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000302 except Exception as e:
303 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100304 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000305
306 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
307 # if nsState = 'DEGRADED' check if all is OK
308 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100309 if current_ns_status in ("READY", "DEGRADED"):
310 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000311 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100312 if status_dict.get("machines"):
313 for machine_id in status_dict.get("machines"):
314 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000315 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100316 if machine.get("agent-status"):
317 s = machine.get("agent-status").get("status")
318 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000319 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100320 error_description += (
321 "machine {} agent-status={} ; ".format(
322 machine_id, s
323 )
324 )
quilesj3655ae02019-12-12 16:08:35 +0000325 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100326 if machine.get("instance-status"):
327 s = machine.get("instance-status").get("status")
328 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000329 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100330 error_description += (
331 "machine {} instance-status={} ; ".format(
332 machine_id, s
333 )
334 )
quilesj3655ae02019-12-12 16:08:35 +0000335 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100336 if status_dict.get("applications"):
337 for app_id in status_dict.get("applications"):
338 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000339 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100340 if app.get("status"):
341 s = app.get("status").get("status")
342 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000343 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100344 error_description += (
345 "application {} status={} ; ".format(app_id, s)
346 )
quilesj3655ae02019-12-12 16:08:35 +0000347
348 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100349 db_dict["errorDescription"] = error_description
350 if current_ns_status == "READY" and is_degraded:
351 db_dict["nsState"] = "DEGRADED"
352 if current_ns_status == "DEGRADED" and not is_degraded:
353 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000354
355 # write to database
356 self.update_db_2("nsrs", nsr_id, db_dict)
357
tierno51183952020-04-03 15:48:18 +0000358 except (asyncio.CancelledError, asyncio.TimeoutError):
359 raise
quilesj3655ae02019-12-12 16:08:35 +0000360 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100361 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200362
garciadeblas5697b8b2021-03-24 09:17:02 +0100363 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100364 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100365 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530366 """
367 Updating vca status in NSR record
368 :param cluster_uuid: UUID of a k8s cluster
369 :param kdu_instance: The unique name of the KDU instance
370 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100371 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530372 :return: none
373 """
374
375 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
376 # .format(cluster_uuid, kdu_instance, filter))
377
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100378 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530379 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100380 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
381 cluster_uuid=cluster_uuid,
382 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200383 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100384 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200385 vca_id=vca_id,
386 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100387
3697083243632024-06-07 05:44:08 +0000388 # First, we need to verify if the current vcaStatus is null, because if that is the case,
389 # MongoDB will not be able to create the fields used within the update key in the database
390 nsr = self.db.get_one(table="nsrs", q_filter=filter)
391 if not nsr.get("vcaStatus"):
392 # Write an empty dictionary to the vcaStatus field, it its value is null
393 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
394
395 # Update the vcaStatus
396 db_key = f"vcaStatus.{nsr_id}.KNF"
ksaikiranr656b6dd2021-02-19 10:25:18 +0530397 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000398
399 db_dict[db_key] = vca_status
400
401 if cluster_type in ("juju-bundle", "juju"):
402 # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA
403 # status in a similar way between Juju Bundles and Helm Charts on this side
404 await self.k8sclusterjuju.update_vca_status(
405 db_dict[db_key],
406 kdu_instance,
407 vca_id=vca_id,
408 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530409
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100410 self.logger.debug(
411 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200412 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530413
414 # write to database
415 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530416 except (asyncio.CancelledError, asyncio.TimeoutError):
417 raise
418 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100419 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530420
tierno72ef84f2020-10-06 08:22:07 +0000421 @staticmethod
422 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
423 try:
garciadeblasef91e082022-08-02 15:12:18 +0200424 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000425 undefined=StrictUndefined,
426 autoescape=select_autoescape(default_for_string=True, default=True),
427 )
tierno72ef84f2020-10-06 08:22:07 +0000428 template = env.from_string(cloud_init_text)
429 return template.render(additional_params or {})
430 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100431 raise LcmException(
432 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
433 "file, must be provided in the instantiation parameters inside the "
434 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
435 )
tierno72ef84f2020-10-06 08:22:07 +0000436 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100437 raise LcmException(
438 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
439 vnfd_id, vdu_id, e
440 )
441 )
tierno72ef84f2020-10-06 08:22:07 +0000442
bravof922c4172020-11-24 21:21:43 -0300443 def _get_vdu_cloud_init_content(self, vdu, vnfd):
444 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000445 try:
tierno72ef84f2020-10-06 08:22:07 +0000446 if vdu.get("cloud-init-file"):
447 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300448 if base_folder["pkg-dir"]:
449 cloud_init_file = "{}/{}/cloud_init/{}".format(
450 base_folder["folder"],
451 base_folder["pkg-dir"],
452 vdu["cloud-init-file"],
453 )
454 else:
455 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
456 base_folder["folder"],
457 vdu["cloud-init-file"],
458 )
tierno72ef84f2020-10-06 08:22:07 +0000459 with self.fs.file_open(cloud_init_file, "r") as ci_file:
460 cloud_init_content = ci_file.read()
461 elif vdu.get("cloud-init"):
462 cloud_init_content = vdu["cloud-init"]
463
464 return cloud_init_content
465 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100466 raise LcmException(
467 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
468 vnfd["id"], vdu["id"], cloud_init_file, e
469 )
470 )
tierno72ef84f2020-10-06 08:22:07 +0000471
tierno72ef84f2020-10-06 08:22:07 +0000472 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100473 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300474 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100475 )
tierno72ef84f2020-10-06 08:22:07 +0000476 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300477 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000478
tierno2357f4e2020-10-19 16:38:59 +0000479 @staticmethod
480 def ip_profile_2_RO(ip_profile):
481 RO_ip_profile = deepcopy(ip_profile)
482 if "dns-server" in RO_ip_profile:
483 if isinstance(RO_ip_profile["dns-server"], list):
484 RO_ip_profile["dns-address"] = []
485 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100486 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000487 else:
488 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
489 if RO_ip_profile.get("ip-version") == "ipv4":
490 RO_ip_profile["ip-version"] = "IPv4"
491 if RO_ip_profile.get("ip-version") == "ipv6":
492 RO_ip_profile["ip-version"] = "IPv6"
493 if "dhcp-params" in RO_ip_profile:
494 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
495 return RO_ip_profile
496
tierno2357f4e2020-10-19 16:38:59 +0000497 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000498 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000499 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000500 db_update = {"_admin.modified": time()}
501 if vdu_create:
502 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100503 vdur = next(
504 (
505 vdur
506 for vdur in reversed(db_vnfr["vdur"])
507 if vdur["vdu-id-ref"] == vdu_id
508 ),
509 None,
510 )
tierno2357f4e2020-10-19 16:38:59 +0000511 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000512 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300513 self.logger.debug(
514 "No vdur in the database. Using the vdur-template to scale"
515 )
vegall8d625f12022-03-22 16:23:30 +0000516 vdur_template = db_vnfr.get("vdur-template")
517 if not vdur_template:
518 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300519 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
520 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000521 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100522 )
vegall8d625f12022-03-22 16:23:30 +0000523 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300524 # Delete a template from the database after using it
525 self.db.set_one(
526 "vnfrs",
527 {"_id": db_vnfr["_id"]},
528 None,
529 pull={"vdur-template": {"_id": vdur["_id"]}},
530 )
tierno2357f4e2020-10-19 16:38:59 +0000531 for count in range(vdu_count):
532 vdur_copy = deepcopy(vdur)
533 vdur_copy["status"] = "BUILD"
534 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100535 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000536 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000537 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100538 vdur_copy["id"] = "{}-{}".format(
539 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
540 )
tierno2357f4e2020-10-19 16:38:59 +0000541 vdur_copy.pop("vim_info", None)
542 for iface in vdur_copy["interfaces"]:
543 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100544 iface["ip-address"] = self.increment_ip_mac(
545 iface["ip-address"], count + 1
546 )
tierno2357f4e2020-10-19 16:38:59 +0000547 else:
548 iface.pop("ip-address", None)
549 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100550 iface["mac-address"] = self.increment_ip_mac(
551 iface["mac-address"], count + 1
552 )
tierno2357f4e2020-10-19 16:38:59 +0000553 else:
554 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000555 if db_vnfr["vdur"]:
556 iface.pop(
557 "mgmt_vnf", None
558 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000559 db_vdu_push_list.append(vdur_copy)
560 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200561 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000562 if len(db_vnfr["vdur"]) == 1:
563 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300564 self.logger.debug(
565 "Scaling to 0 !, creating the template with the last vdur"
566 )
vegall8d625f12022-03-22 16:23:30 +0000567 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000568 for vdu_id, vdu_count in vdu_delete.items():
569 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100570 indexes_to_delete = [
571 iv[0]
572 for iv in enumerate(db_vnfr["vdur"])
573 if iv[1]["vdu-id-ref"] == vdu_id
574 ]
575 db_update.update(
576 {
577 "vdur.{}.status".format(i): "DELETING"
578 for i in indexes_to_delete[-vdu_count:]
579 }
580 )
tierno2357f4e2020-10-19 16:38:59 +0000581 else:
582 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100583 vdus_to_delete = [
584 v
585 for v in reversed(db_vnfr["vdur"])
586 if v["vdu-id-ref"] == vdu_id
587 ]
tierno2357f4e2020-10-19 16:38:59 +0000588 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100589 self.db.set_one(
590 "vnfrs",
591 {"_id": db_vnfr["_id"]},
592 None,
593 pull={"vdur": {"_id": vdu["_id"]}},
594 )
vegall8d625f12022-03-22 16:23:30 +0000595 db_push = {}
596 if db_vdu_push_list:
597 db_push["vdur"] = db_vdu_push_list
598 if template_vdur:
599 db_push["vdur-template"] = template_vdur
600 if not db_push:
601 db_push = None
602 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000603 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
604 # modify passed dictionary db_vnfr
605 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
606 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200607
tiernof578e552018-11-08 19:07:20 +0100608 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
609 """
610 Updates database nsr with the RO info for the created vld
611 :param ns_update_nsr: dictionary to be filled with the updated info
612 :param db_nsr: content of db_nsr. This is also modified
613 :param nsr_desc_RO: nsr descriptor from RO
614 :return: Nothing, LcmException is raised on errors
615 """
616
617 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
618 for net_RO in get_iterable(nsr_desc_RO, "nets"):
619 if vld["id"] != net_RO.get("ns_net_osm_id"):
620 continue
621 vld["vim-id"] = net_RO.get("vim_net_id")
622 vld["name"] = net_RO.get("vim_name")
623 vld["status"] = net_RO.get("status")
624 vld["status-detailed"] = net_RO.get("error_msg")
625 ns_update_nsr["vld.{}".format(vld_index)] = vld
626 break
627 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100628 raise LcmException(
629 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
630 )
tiernof578e552018-11-08 19:07:20 +0100631
tiernoe876f672020-02-13 14:34:48 +0000632 def set_vnfr_at_error(self, db_vnfrs, error_text):
633 try:
634 for db_vnfr in db_vnfrs.values():
635 vnfr_update = {"status": "ERROR"}
636 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
637 if "status" not in vdur:
638 vdur["status"] = "ERROR"
639 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
640 if error_text:
641 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100642 vnfr_update[
643 "vdur.{}.status-detailed".format(vdu_index)
644 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000645 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
646 except DbException as e:
647 self.logger.error("Cannot update vnf. {}".format(e))
648
tierno5ee02052019-12-05 19:55:02 +0000649 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000650 """
651 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000652 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000653 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
654 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
655 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
656 """
tierno5ee02052019-12-05 19:55:02 +0000657 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
658 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000659 mapping = {}
660 ns_config_info = {"osm-config-mapping": mapping}
661 for vca in vca_deployed_list:
662 if not vca["member-vnf-index"]:
663 continue
664 if not vca["vdu_id"]:
665 mapping[vca["member-vnf-index"]] = vca["application"]
666 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100667 mapping[
668 "{}.{}.{}".format(
669 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
670 )
671 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000672 return ns_config_info
673
garciadeblas5697b8b2021-03-24 09:17:02 +0100674 async def _instantiate_ng_ro(
675 self,
676 logging_text,
677 nsr_id,
678 nsd,
679 db_nsr,
680 db_nslcmop,
681 db_vnfrs,
682 db_vnfds,
683 n2vc_key_list,
684 stage,
685 start_deploy,
686 timeout_ns_deploy,
687 ):
tierno2357f4e2020-10-19 16:38:59 +0000688 db_vims = {}
689
690 def get_vim_account(vim_account_id):
691 nonlocal db_vims
692 if vim_account_id in db_vims:
693 return db_vims[vim_account_id]
694 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
695 db_vims[vim_account_id] = db_vim
696 return db_vim
697
698 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100699 def parse_vld_instantiation_params(
700 target_vim, target_vld, vld_params, target_sdn
701 ):
tierno2357f4e2020-10-19 16:38:59 +0000702 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500703 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
704 vld_params["ip-profile"]
705 )
tierno2357f4e2020-10-19 16:38:59 +0000706 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100707 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
708 "provider-network"
709 ]
tierno2357f4e2020-10-19 16:38:59 +0000710 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100711 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
712 "provider-network"
713 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000714
715 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
716 # if wim_account_id is specified in vld_params, validate if it is feasible.
717 wim_account_id, db_wim = select_feasible_wim_account(
718 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
719 )
720
721 if wim_account_id:
722 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
723 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
724 # update vld_params with correct WIM account Id
725 vld_params["wimAccountId"] = wim_account_id
726
727 target_wim = "wim:{}".format(wim_account_id)
728 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
729 sdn_ports = get_sdn_ports(vld_params, db_wim)
730 if len(sdn_ports) > 0:
731 target_vld["vim_info"][target_wim] = target_wim_attrs
732 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
733
734 self.logger.debug(
735 "Target VLD with WIM data: {:s}".format(str(target_vld))
736 )
737
tierno2357f4e2020-10-19 16:38:59 +0000738 for param in ("vim-network-name", "vim-network-id"):
739 if vld_params.get(param):
740 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300741 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300742 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100743 populate_dict(
744 target_vld["vim_info"],
745 (other_target_vim, param.replace("-", "_")),
746 vim_net,
747 )
tierno2357f4e2020-10-19 16:38:59 +0000748 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100749 target_vld["vim_info"][target_vim][
750 param.replace("-", "_")
751 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300752 if vld_params.get("common_id"):
753 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000754
aticig15db6142022-01-24 12:51:26 +0300755 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
756 def update_ns_vld_target(target, ns_params):
757 for vnf_params in ns_params.get("vnf", ()):
758 if vnf_params.get("vimAccountId"):
759 target_vnf = next(
760 (
761 vnfr
762 for vnfr in db_vnfrs.values()
763 if vnf_params["member-vnf-index"]
764 == vnfr["member-vnf-index-ref"]
765 ),
766 None,
767 )
768 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100769 if not vdur:
Pedro Escaleira556f5c72023-04-20 15:22:16 +0100770 continue
aticig15db6142022-01-24 12:51:26 +0300771 for a_index, a_vld in enumerate(target["ns"]["vld"]):
772 target_vld = find_in_list(
773 get_iterable(vdur, "interfaces"),
774 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
775 )
aticig84bd9a72022-06-14 03:01:36 +0300776
777 vld_params = find_in_list(
778 get_iterable(ns_params, "vld"),
779 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
780 )
aticig15db6142022-01-24 12:51:26 +0300781 if target_vld:
782 if vnf_params.get("vimAccountId") not in a_vld.get(
783 "vim_info", {}
784 ):
aticig84bd9a72022-06-14 03:01:36 +0300785 target_vim_network_list = [
786 v for _, v in a_vld.get("vim_info").items()
787 ]
788 target_vim_network_name = next(
789 (
790 item.get("vim_network_name", "")
791 for item in target_vim_network_list
792 ),
793 "",
794 )
795
aticig15db6142022-01-24 12:51:26 +0300796 target["ns"]["vld"][a_index].get("vim_info").update(
797 {
798 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300799 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300800 }
801 }
802 )
803
aticig84bd9a72022-06-14 03:01:36 +0300804 if vld_params:
805 for param in ("vim-network-name", "vim-network-id"):
806 if vld_params.get(param) and isinstance(
807 vld_params[param], dict
808 ):
809 for vim, vim_net in vld_params[
810 param
811 ].items():
812 other_target_vim = "vim:" + vim
813 populate_dict(
814 target["ns"]["vld"][a_index].get(
815 "vim_info"
816 ),
817 (
818 other_target_vim,
819 param.replace("-", "_"),
820 ),
821 vim_net,
822 )
823
tierno69f0d382020-05-07 13:08:09 +0000824 nslcmop_id = db_nslcmop["_id"]
825 target = {
826 "name": db_nsr["name"],
827 "ns": {"vld": []},
828 "vnf": [],
829 "image": deepcopy(db_nsr["image"]),
830 "flavor": deepcopy(db_nsr["flavor"]),
831 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000832 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000833 }
834 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000835 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000836 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000837 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000838 if db_nsr.get("shared-volumes"):
839 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
840 for shared_volumes in target["shared-volumes"]:
841 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100842 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100843 target["affinity-or-anti-affinity-group"] = deepcopy(
844 db_nsr["affinity-or-anti-affinity-group"]
845 )
846 for affinity_or_anti_affinity_group in target[
847 "affinity-or-anti-affinity-group"
848 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100849 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000850
tierno2357f4e2020-10-19 16:38:59 +0000851 if db_nslcmop.get("lcmOperationType") != "instantiate":
852 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100853 db_nslcmop_instantiate = self.db.get_list(
854 "nslcmops",
855 {
856 "nsInstanceId": db_nslcmop["nsInstanceId"],
857 "lcmOperationType": "instantiate",
858 },
859 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000860 ns_params = db_nslcmop_instantiate.get("operationParams")
861 else:
862 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300863 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
864 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000865
866 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000867 for vld_index, vld in enumerate(db_nsr.get("vld")):
868 target_vim = "vim:{}".format(ns_params["vimAccountId"])
869 target_vld = {
870 "id": vld["id"],
871 "name": vld["name"],
872 "mgmt-network": vld.get("mgmt-network", False),
873 "type": vld.get("type"),
874 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300875 target_vim: {
876 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100877 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -0300878 }
garciadeblas5697b8b2021-03-24 09:17:02 +0100879 },
tierno2357f4e2020-10-19 16:38:59 +0000880 }
881 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000882 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +0000883 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +0300884 if vim_config := db_vim.get("config"):
885 if sdnc_id := vim_config.get("sdn-controller"):
886 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
887 target_sdn = "sdn:{}".format(sdnc_id)
888 target_vld["vim_info"][target_sdn] = {
889 "sdn": True,
890 "target_vim": target_vim,
891 "vlds": [sdn_vld],
892 "type": vld.get("type"),
893 }
tierno2357f4e2020-10-19 16:38:59 +0000894
bravof922c4172020-11-24 21:21:43 -0300895 nsd_vnf_profiles = get_vnf_profiles(nsd)
896 for nsd_vnf_profile in nsd_vnf_profiles:
897 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
898 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100899 cp2target[
900 "member_vnf:{}.{}".format(
901 cp["constituent-cpd-id"][0][
902 "constituent-base-element-id"
903 ],
904 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
905 )
906 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000907
908 # check at nsd descriptor, if there is an ip-profile
909 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +0000910 nsd_vlp = find_in_list(
911 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100912 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
913 == vld["id"],
914 )
915 if (
916 nsd_vlp
917 and nsd_vlp.get("virtual-link-protocol-data")
918 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
919 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500920 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100921 "l3-protocol-data"
922 ]
bravof922c4172020-11-24 21:21:43 -0300923
tierno2357f4e2020-10-19 16:38:59 +0000924 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +0100925 vld_instantiation_params = find_in_list(
926 get_iterable(ns_params, "vld"),
927 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
928 )
tierno2357f4e2020-10-19 16:38:59 +0000929 if vld_instantiation_params:
930 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300931 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000932 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +0300933 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
934 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -0300935
tierno69f0d382020-05-07 13:08:09 +0000936 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +0100937 vnfd = find_in_list(
938 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
939 )
940 vnf_params = find_in_list(
941 get_iterable(ns_params, "vnf"),
942 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
943 )
tierno69f0d382020-05-07 13:08:09 +0000944 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000945 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000946 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000947 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +0100948 vnf_cp = find_in_list(
949 vnfd.get("int-virtual-link-desc", ()),
950 lambda cpd: cpd.get("id") == vld["id"],
951 )
tierno69f0d382020-05-07 13:08:09 +0000952 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +0100953 ns_cp = "member_vnf:{}.{}".format(
954 vnfr["member-vnf-index-ref"], vnf_cp["id"]
955 )
tierno69f0d382020-05-07 13:08:09 +0000956 if cp2target.get(ns_cp):
957 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300958
garciadeblas5697b8b2021-03-24 09:17:02 +0100959 vld["vim_info"] = {
960 target_vim: {"vim_network_name": vld.get("vim-network-name")}
961 }
tierno2357f4e2020-10-19 16:38:59 +0000962 # check if this network needs SDN assist
963 target_sdn = None
964 if vld.get("pci-interfaces"):
965 db_vim = get_vim_account(vnfr["vim-account-id"])
966 sdnc_id = db_vim["config"].get("sdn-controller")
967 if sdnc_id:
968 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
969 target_sdn = "sdn:{}".format(sdnc_id)
970 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +0100971 "sdn": True,
972 "target_vim": target_vim,
973 "vlds": [sdn_vld],
974 "type": vld.get("type"),
975 }
tierno69f0d382020-05-07 13:08:09 +0000976
tierno2357f4e2020-10-19 16:38:59 +0000977 # check at vnfd descriptor, if there is an ip-profile
978 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300979 vnfd_vlp = find_in_list(
980 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100981 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -0300982 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100983 if (
984 vnfd_vlp
985 and vnfd_vlp.get("virtual-link-protocol-data")
986 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
987 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500988 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100989 "l3-protocol-data"
990 ]
tierno2357f4e2020-10-19 16:38:59 +0000991 # update vld_params with instantiation params
992 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +0100993 vld_instantiation_params = find_in_list(
994 get_iterable(vnf_params, "internal-vld"),
995 lambda i_vld: i_vld["name"] == vld["id"],
996 )
tierno2357f4e2020-10-19 16:38:59 +0000997 if vld_instantiation_params:
998 vld_params.update(vld_instantiation_params)
999 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1000
1001 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001002 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001003 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1004 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001005 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001006
bravof922c4172020-11-24 21:21:43 -03001007 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1008
1009 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001010 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1011 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001012 if (
1013 vdu_configuration
1014 and vdu_configuration.get("config-access")
1015 and vdu_configuration.get("config-access").get("ssh-access")
1016 ):
bravof922c4172020-11-24 21:21:43 -03001017 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001018 vdur["ssh-access-required"] = vdu_configuration[
1019 "config-access"
1020 ]["ssh-access"]["required"]
1021 elif (
1022 vnf_configuration
1023 and vnf_configuration.get("config-access")
1024 and vnf_configuration.get("config-access").get("ssh-access")
1025 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1026 ):
bravof922c4172020-11-24 21:21:43 -03001027 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001028 vdur["ssh-access-required"] = vnf_configuration[
1029 "config-access"
1030 ]["ssh-access"]["required"]
1031 elif ssh_keys_instantiation and find_in_list(
1032 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1033 ):
bravof922c4172020-11-24 21:21:43 -03001034 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001035
bravof922c4172020-11-24 21:21:43 -03001036 self.logger.debug("NS > vdur > {}".format(vdur))
1037
1038 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001039 # cloud-init
1040 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001041 vdur["cloud-init"] = "{}:file:{}".format(
1042 vnfd["_id"], vdud.get("cloud-init-file")
1043 )
tierno2357f4e2020-10-19 16:38:59 +00001044 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1045 if vdur["cloud-init"] not in target["cloud_init_content"]:
1046 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001047 if base_folder["pkg-dir"]:
1048 cloud_init_file = "{}/{}/cloud_init/{}".format(
1049 base_folder["folder"],
1050 base_folder["pkg-dir"],
1051 vdud.get("cloud-init-file"),
1052 )
1053 else:
1054 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1055 base_folder["folder"],
1056 vdud.get("cloud-init-file"),
1057 )
tierno2357f4e2020-10-19 16:38:59 +00001058 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001059 target["cloud_init_content"][
1060 vdur["cloud-init"]
1061 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001062 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001063 vdur["cloud-init"] = "{}:vdu:{}".format(
1064 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1065 )
tierno2357f4e2020-10-19 16:38:59 +00001066 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001067 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1068 "cloud-init"
1069 ]
tierno2357f4e2020-10-19 16:38:59 +00001070 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001071 deploy_params_vdu = self._format_additional_params(
1072 vdur.get("additionalParams") or {}
1073 )
1074 deploy_params_vdu["OSM"] = get_osm_params(
1075 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1076 )
tierno2357f4e2020-10-19 16:38:59 +00001077 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001078
1079 # flavor
1080 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001081 if target_vim not in ns_flavor["vim_info"]:
1082 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001083
1084 # deal with images
1085 # in case alternative images are provided we must check if they should be applied
1086 # for the vim_type, modify the vim_type taking into account
1087 ns_image_id = int(vdur["ns-image-id"])
1088 if vdur.get("alt-image-ids"):
1089 db_vim = get_vim_account(vnfr["vim-account-id"])
1090 vim_type = db_vim["vim_type"]
1091 for alt_image_id in vdur.get("alt-image-ids"):
1092 ns_alt_image = target["image"][int(alt_image_id)]
1093 if vim_type == ns_alt_image.get("vim-type"):
1094 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001095 self.logger.debug(
1096 "use alternative image id: {}".format(alt_image_id)
1097 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001098 ns_image_id = alt_image_id
1099 vdur["ns-image-id"] = ns_image_id
1100 break
1101 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001102 if target_vim not in ns_image["vim_info"]:
1103 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001104
Alexis Romero305b5c42022-03-11 15:29:18 +01001105 # Affinity groups
1106 if vdur.get("affinity-or-anti-affinity-group-id"):
1107 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1108 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1109 if target_vim not in ns_ags["vim_info"]:
1110 ns_ags["vim_info"][target_vim] = {}
1111
vegall63162192023-03-06 14:19:16 +00001112 # shared-volumes
1113 if vdur.get("shared-volumes-id"):
1114 for sv_id in vdur["shared-volumes-id"]:
1115 ns_sv = find_in_list(
1116 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1117 )
1118 if ns_sv:
1119 ns_sv["vim_info"][target_vim] = {}
1120
tierno2357f4e2020-10-19 16:38:59 +00001121 vdur["vim_info"] = {target_vim: {}}
1122 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001123 if vnf_params:
1124 vdu_instantiation_params = find_in_list(
1125 get_iterable(vnf_params, "vdu"),
1126 lambda i_vdu: i_vdu["id"] == vdud["id"],
1127 )
1128 if vdu_instantiation_params:
1129 # Parse the vdu_volumes from the instantiation params
1130 vdu_volumes = get_volumes_from_instantiation_params(
1131 vdu_instantiation_params, vdud
1132 )
1133 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001134 vdur["additionalParams"]["OSM"][
1135 "vim_flavor_id"
1136 ] = vdu_instantiation_params.get("vim-flavor-id")
kayal20011028e362024-06-27 08:23:36 +05301137 vdur["additionalParams"]["OSM"][
1138 "instance_name"
1139 ] = vdu_instantiation_params.get("instance_name")
tierno2357f4e2020-10-19 16:38:59 +00001140 vdur_list.append(vdur)
1141 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001142 target["vnf"].append(target_vnf)
1143
garciadeblas07f4e4c2022-06-09 09:42:58 +02001144 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001145 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001146 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001147 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001148 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001149 nsr_id,
1150 action_id,
1151 nslcmop_id,
1152 start_deploy,
1153 timeout_ns_deploy,
1154 stage,
1155 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001156 )
tierno69f0d382020-05-07 13:08:09 +00001157
1158 # Updating NSR
1159 db_nsr_update = {
1160 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001161 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001162 }
1163 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1164 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1165 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001166 self.logger.debug(
1167 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1168 )
tierno69f0d382020-05-07 13:08:09 +00001169 return
1170
garciadeblas5697b8b2021-03-24 09:17:02 +01001171 async def _wait_ng_ro(
1172 self,
1173 nsr_id,
1174 action_id,
1175 nslcmop_id=None,
1176 start_time=None,
1177 timeout=600,
1178 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001179 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001180 ):
tierno69f0d382020-05-07 13:08:09 +00001181 detailed_status_old = None
1182 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001183 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001184 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001185 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001186 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001187 if desc_status["status"] == "FAILED":
1188 raise NgRoException(desc_status["details"])
1189 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001190 if stage:
1191 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001192 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001193 if stage:
1194 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001195 break
1196 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001197 assert False, "ROclient.check_ns_status returns unknown {}".format(
1198 desc_status["status"]
1199 )
tierno2357f4e2020-10-19 16:38:59 +00001200 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001201 detailed_status_old = stage[2]
1202 db_nsr_update["detailed-status"] = " ".join(stage)
1203 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1204 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001205 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001206 else: # timeout_ns_deploy
1207 raise NgRoException("Timeout waiting ns to deploy")
1208
garciadeblas5697b8b2021-03-24 09:17:02 +01001209 async def _terminate_ng_ro(
1210 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1211 ):
tierno69f0d382020-05-07 13:08:09 +00001212 db_nsr_update = {}
1213 failed_detail = []
1214 action_id = None
1215 start_deploy = time()
1216 try:
1217 target = {
1218 "ns": {"vld": []},
1219 "vnf": [],
1220 "image": [],
1221 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001222 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001223 }
1224 desc = await self.RO.deploy(nsr_id, target)
1225 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001226 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001227 self.logger.debug(
1228 logging_text
1229 + "ns terminate action at RO. action_id={}".format(action_id)
1230 )
tierno69f0d382020-05-07 13:08:09 +00001231
1232 # wait until done
1233 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001234 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001235 nsr_id,
1236 action_id,
1237 nslcmop_id,
1238 start_deploy,
1239 delete_timeout,
1240 stage,
1241 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001242 )
tierno69f0d382020-05-07 13:08:09 +00001243 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1244 # delete all nsr
1245 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001246 except NgRoException as e:
1247 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001248 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1249 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001250 self.logger.debug(
1251 logging_text + "RO_action_id={} already deleted".format(action_id)
1252 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001253 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001254 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001255 self.logger.debug(
1256 logging_text
1257 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1258 )
tierno69f0d382020-05-07 13:08:09 +00001259 else:
1260 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001261 self.logger.error(
1262 logging_text
1263 + "RO_action_id={} delete error: {}".format(action_id, e)
1264 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001265 except Exception as e:
1266 failed_detail.append("delete error: {}".format(e))
1267 self.logger.error(
1268 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1269 )
tierno69f0d382020-05-07 13:08:09 +00001270
1271 if failed_detail:
1272 stage[2] = "Error deleting from VIM"
1273 else:
1274 stage[2] = "Deleted from VIM"
1275 db_nsr_update["detailed-status"] = " ".join(stage)
1276 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1277 self._write_op_status(nslcmop_id, stage)
1278
1279 if failed_detail:
1280 raise LcmException("; ".join(failed_detail))
1281 return
1282
garciadeblas5697b8b2021-03-24 09:17:02 +01001283 async def instantiate_RO(
1284 self,
1285 logging_text,
1286 nsr_id,
1287 nsd,
1288 db_nsr,
1289 db_nslcmop,
1290 db_vnfrs,
1291 db_vnfds,
1292 n2vc_key_list,
1293 stage,
1294 ):
tiernoe95ed362020-04-23 08:24:57 +00001295 """
1296 Instantiate at RO
1297 :param logging_text: preffix text to use at logging
1298 :param nsr_id: nsr identity
1299 :param nsd: database content of ns descriptor
1300 :param db_nsr: database content of ns record
1301 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1302 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001303 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001304 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1305 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1306 :return: None or exception
1307 """
tiernoe876f672020-02-13 14:34:48 +00001308 try:
tiernoe876f672020-02-13 14:34:48 +00001309 start_deploy = time()
1310 ns_params = db_nslcmop.get("operationParams")
1311 if ns_params and ns_params.get("timeout_ns_deploy"):
1312 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1313 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001314 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001315
tiernoe876f672020-02-13 14:34:48 +00001316 # Check for and optionally request placement optimization. Database will be updated if placement activated
1317 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001318 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1319 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1320 for vnfr in db_vnfrs.values():
1321 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1322 break
1323 else:
1324 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001325
garciadeblas5697b8b2021-03-24 09:17:02 +01001326 return await self._instantiate_ng_ro(
1327 logging_text,
1328 nsr_id,
1329 nsd,
1330 db_nsr,
1331 db_nslcmop,
1332 db_vnfrs,
1333 db_vnfds,
1334 n2vc_key_list,
1335 stage,
1336 start_deploy,
1337 timeout_ns_deploy,
1338 )
tierno2357f4e2020-10-19 16:38:59 +00001339 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001340 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001341 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001342 self.logger.error(
1343 "Error deploying at VIM {}".format(e),
1344 exc_info=not isinstance(
1345 e,
1346 (
1347 ROclient.ROClientException,
1348 LcmException,
1349 DbException,
1350 NgRoException,
1351 ),
1352 ),
1353 )
tiernoe876f672020-02-13 14:34:48 +00001354 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001355
tierno7ecbc342020-09-21 14:05:39 +00001356 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1357 """
1358 Wait for kdu to be up, get ip address
1359 :param logging_text: prefix use for logging
1360 :param nsr_id:
1361 :param vnfr_id:
1362 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001363 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001364 """
1365
1366 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1367 nb_tries = 0
1368
1369 while nb_tries < 360:
1370 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001371 kdur = next(
1372 (
1373 x
1374 for x in get_iterable(db_vnfr, "kdur")
1375 if x.get("kdu-name") == kdu_name
1376 ),
1377 None,
1378 )
tierno7ecbc342020-09-21 14:05:39 +00001379 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001380 raise LcmException(
1381 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1382 )
tierno7ecbc342020-09-21 14:05:39 +00001383 if kdur.get("status"):
1384 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001385 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001386 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001387 raise LcmException(
1388 "target KDU={} is in error state".format(kdu_name)
1389 )
tierno7ecbc342020-09-21 14:05:39 +00001390
Gabriel Cubae7898982023-05-11 01:57:21 -05001391 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001392 nb_tries += 1
1393 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1394
garciadeblas5697b8b2021-03-24 09:17:02 +01001395 async def wait_vm_up_insert_key_ro(
1396 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1397 ):
tiernoa5088192019-11-26 16:12:53 +00001398 """
1399 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1400 :param logging_text: prefix use for logging
1401 :param nsr_id:
1402 :param vnfr_id:
1403 :param vdu_id:
1404 :param vdu_index:
1405 :param pub_key: public ssh key to inject, None to skip
1406 :param user: user to apply the public ssh key
1407 :return: IP address
1408 """
quilesj7e13aeb2019-10-08 13:34:55 +02001409
tierno2357f4e2020-10-19 16:38:59 +00001410 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001411 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001412 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001413 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001414
tiernod8323042019-08-09 11:32:23 +00001415 while True:
quilesj3149f262019-12-03 10:58:10 +00001416 ro_retries += 1
1417 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001418 raise LcmException(
1419 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1420 )
quilesj3149f262019-12-03 10:58:10 +00001421
Gabriel Cubae7898982023-05-11 01:57:21 -05001422 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001423
1424 # get ip address
tiernod8323042019-08-09 11:32:23 +00001425 if not target_vdu_id:
1426 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001427
1428 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001429 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001430 raise LcmException(
1431 "Cannot inject ssh-key because target VNF is in error state"
1432 )
tiernod8323042019-08-09 11:32:23 +00001433 ip_address = db_vnfr.get("ip-address")
1434 if not ip_address:
1435 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001436 vdur = next(
1437 (
1438 x
1439 for x in get_iterable(db_vnfr, "vdur")
1440 if x.get("ip-address") == ip_address
1441 ),
1442 None,
1443 )
quilesj3149f262019-12-03 10:58:10 +00001444 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001445 vdur = next(
1446 (
1447 x
1448 for x in get_iterable(db_vnfr, "vdur")
1449 if x.get("vdu-id-ref") == vdu_id
1450 and x.get("count-index") == vdu_index
1451 ),
1452 None,
1453 )
quilesj3149f262019-12-03 10:58:10 +00001454
garciadeblas5697b8b2021-03-24 09:17:02 +01001455 if (
1456 not vdur and len(db_vnfr.get("vdur", ())) == 1
1457 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001458 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001459 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001460 raise LcmException(
1461 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1462 vnfr_id, vdu_id, vdu_index
1463 )
1464 )
tierno2357f4e2020-10-19 16:38:59 +00001465 # New generation RO stores information at "vim_info"
1466 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001467 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001468 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001469 target_vim = next(
1470 t for t in vdur["vim_info"]
1471 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001472 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001473 if (
1474 vdur.get("pdu-type")
1475 or vdur.get("status") == "ACTIVE"
1476 or ng_ro_status == "ACTIVE"
1477 ):
quilesj3149f262019-12-03 10:58:10 +00001478 ip_address = vdur.get("ip-address")
1479 if not ip_address:
1480 continue
1481 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001482 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001483 raise LcmException(
1484 "Cannot inject ssh-key because target VM is in error state"
1485 )
quilesj3149f262019-12-03 10:58:10 +00001486
tiernod8323042019-08-09 11:32:23 +00001487 if not target_vdu_id:
1488 continue
tiernod8323042019-08-09 11:32:23 +00001489
quilesj7e13aeb2019-10-08 13:34:55 +02001490 # inject public key into machine
1491 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001492 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001493 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001494 if vdur.get("pdu-type"):
1495 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1496 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001497 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001498 target = {
1499 "action": {
1500 "action": "inject_ssh_key",
1501 "key": pub_key,
1502 "user": user,
1503 },
1504 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1505 }
1506 desc = await self.RO.deploy(nsr_id, target)
1507 action_id = desc["action_id"]
1508 await self._wait_ng_ro(
1509 nsr_id, action_id, timeout=600, operation="instantiation"
1510 )
1511 break
tierno69f0d382020-05-07 13:08:09 +00001512 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001513 raise LcmException(
1514 "Reaching max tries injecting key. Error: {}".format(e)
1515 )
quilesj7e13aeb2019-10-08 13:34:55 +02001516 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001517 break
1518
1519 return ip_address
1520
tierno5ee02052019-12-05 19:55:02 +00001521 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1522 """
1523 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1524 """
1525 my_vca = vca_deployed_list[vca_index]
1526 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001527 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001528 return
1529 timeout = 300
1530 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001531 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1532 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1533 configuration_status_list = db_nsr["configurationStatus"]
1534 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001535 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001536 # myself
tierno5ee02052019-12-05 19:55:02 +00001537 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001538 if not my_vca.get("member-vnf-index") or (
1539 vca_deployed.get("member-vnf-index")
1540 == my_vca.get("member-vnf-index")
1541 ):
quilesj3655ae02019-12-12 16:08:35 +00001542 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001543 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001544 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001545 elif internal_status == "BROKEN":
1546 raise LcmException(
1547 "Configuration aborted because dependent charm/s has failed"
1548 )
quilesj3655ae02019-12-12 16:08:35 +00001549 else:
1550 break
tierno5ee02052019-12-05 19:55:02 +00001551 else:
quilesj3655ae02019-12-12 16:08:35 +00001552 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001553 return
1554 await asyncio.sleep(10)
1555 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001556
1557 raise LcmException("Configuration aborted because dependent charm/s timeout")
1558
David Garciac1fe90a2021-03-31 19:12:02 +02001559 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001560 vca_id = None
1561 if db_vnfr:
1562 vca_id = deep_get(db_vnfr, ("vca-id",))
1563 elif db_nsr:
1564 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1565 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1566 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001567
garciadeblas5697b8b2021-03-24 09:17:02 +01001568 async def instantiate_N2VC(
1569 self,
1570 logging_text,
1571 vca_index,
1572 nsi_id,
1573 db_nsr,
1574 db_vnfr,
1575 vdu_id,
1576 kdu_name,
1577 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001578 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001579 config_descriptor,
1580 deploy_params,
1581 base_folder,
1582 nslcmop_id,
1583 stage,
1584 vca_type,
1585 vca_name,
1586 ee_config_descriptor,
1587 ):
tiernod8323042019-08-09 11:32:23 +00001588 nsr_id = db_nsr["_id"]
1589 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001590 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001591 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001592 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001593 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001594 "collection": "nsrs",
1595 "filter": {"_id": nsr_id},
1596 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001597 }
tiernod8323042019-08-09 11:32:23 +00001598 step = ""
1599 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001600 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001601 element_under_configuration = nsr_id
1602
tiernod8323042019-08-09 11:32:23 +00001603 vnfr_id = None
1604 if db_vnfr:
1605 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001606 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001607
garciadeblas5697b8b2021-03-24 09:17:02 +01001608 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001609
aktas98488ed2021-07-29 17:42:49 +03001610 if vca_type == "native_charm":
1611 index_number = 0
1612 else:
1613 index_number = vdu_index or 0
1614
tiernod8323042019-08-09 11:32:23 +00001615 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001616 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001617 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001618 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001619 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001620 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001621 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001622 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001623 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001624 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001625 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001626 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001627 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001628 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001629
1630 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001631 if base_folder["pkg-dir"]:
1632 artifact_path = "{}/{}/{}/{}".format(
1633 base_folder["folder"],
1634 base_folder["pkg-dir"],
1635 "charms"
aticig15db6142022-01-24 12:51:26 +03001636 if vca_type
1637 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001638 else "helm-charts",
1639 vca_name,
1640 )
1641 else:
1642 artifact_path = "{}/Scripts/{}/{}/".format(
1643 base_folder["folder"],
1644 "charms"
aticig15db6142022-01-24 12:51:26 +03001645 if vca_type
1646 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001647 else "helm-charts",
1648 vca_name,
1649 )
bravof922c4172020-11-24 21:21:43 -03001650
1651 self.logger.debug("Artifact path > {}".format(artifact_path))
1652
tiernoa278b842020-07-08 15:33:55 +00001653 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001654 initial_config_primitive_list = config_descriptor.get(
1655 "initial-config-primitive"
1656 )
tiernoa278b842020-07-08 15:33:55 +00001657
garciadeblas5697b8b2021-03-24 09:17:02 +01001658 self.logger.debug(
1659 "Initial config primitive list > {}".format(
1660 initial_config_primitive_list
1661 )
1662 )
bravof922c4172020-11-24 21:21:43 -03001663
tiernoa278b842020-07-08 15:33:55 +00001664 # add config if not present for NS charm
1665 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001666 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001667 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1668 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1669 )
tiernod8323042019-08-09 11:32:23 +00001670
garciadeblas5697b8b2021-03-24 09:17:02 +01001671 self.logger.debug(
1672 "Initial config primitive list #2 > {}".format(
1673 initial_config_primitive_list
1674 )
1675 )
tierno588547c2020-07-01 15:30:20 +00001676 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001677 # find old ee_id if exists
1678 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001679
David Garciac1fe90a2021-03-31 19:12:02 +02001680 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001681 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001682 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001683 self._write_configuration_status(
1684 nsr_id=nsr_id,
1685 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001686 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001687 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001688 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001689 )
tiernod8323042019-08-09 11:32:23 +00001690
tierno588547c2020-07-01 15:30:20 +00001691 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001692 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001693
1694 ee_id = None
1695 credentials = None
1696 if vca_type == "k8s_proxy_charm":
1697 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001698 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001699 namespace=namespace,
1700 artifact_path=artifact_path,
1701 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001702 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001703 )
Luis Vegae11384e2023-10-10 22:36:33 +00001704 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001705 ee_id, credentials = await self.vca_map[
1706 vca_type
1707 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001708 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001709 reuse_ee_id=ee_id,
1710 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001711 config=osm_config,
1712 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001713 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001714 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001715 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001716 else:
1717 ee_id, credentials = await self.vca_map[
1718 vca_type
1719 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001720 namespace=namespace,
1721 reuse_ee_id=ee_id,
1722 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001723 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001724 )
quilesj3655ae02019-12-12 16:08:35 +00001725
tierno588547c2020-07-01 15:30:20 +00001726 elif vca_type == "native_charm":
1727 step = "Waiting to VM being up and getting IP address"
1728 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001729 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1730 logging_text,
1731 nsr_id,
1732 vnfr_id,
1733 vdu_id,
1734 vdu_index,
1735 user=None,
1736 pub_key=None,
1737 )
tierno588547c2020-07-01 15:30:20 +00001738 credentials = {"hostname": rw_mgmt_ip}
1739 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001740 username = deep_get(
1741 config_descriptor, ("config-access", "ssh-access", "default-user")
1742 )
tierno588547c2020-07-01 15:30:20 +00001743 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1744 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001745 if not username and initial_config_primitive_list:
1746 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001747 for param in config_primitive.get("parameter", ()):
1748 if param["name"] == "ssh-username":
1749 username = param["value"]
1750 break
1751 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001752 raise LcmException(
1753 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1754 "'config-access.ssh-access.default-user'"
1755 )
tierno588547c2020-07-01 15:30:20 +00001756 credentials["username"] = username
1757 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001758
tierno588547c2020-07-01 15:30:20 +00001759 self._write_configuration_status(
1760 nsr_id=nsr_id,
1761 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001762 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001763 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001764 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001765 )
quilesj3655ae02019-12-12 16:08:35 +00001766
tierno588547c2020-07-01 15:30:20 +00001767 step = "register execution environment {}".format(credentials)
1768 self.logger.debug(logging_text + step)
1769 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001770 credentials=credentials,
1771 namespace=namespace,
1772 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001773 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001774 )
tierno3bedc9b2019-11-27 15:46:57 +00001775
tierno588547c2020-07-01 15:30:20 +00001776 # for compatibility with MON/POL modules, the need model and application name at database
1777 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001778 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001779 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1780 if len(ee_id_parts) >= 2:
1781 model_name = ee_id_parts[0]
1782 application_name = ee_id_parts[1]
1783 db_nsr_update[db_update_entry + "model"] = model_name
1784 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001785
1786 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001787 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001788
tiernoc231a872020-01-21 08:49:05 +00001789 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001790 nsr_id=nsr_id,
1791 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001792 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001793 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001794 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001795 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001796 )
1797
tierno3bedc9b2019-11-27 15:46:57 +00001798 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001799 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001800 config = None
tierno588547c2020-07-01 15:30:20 +00001801 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001802 config_primitive = next(
1803 (p for p in initial_config_primitive_list if p["name"] == "config"),
1804 None,
1805 )
tiernoa278b842020-07-08 15:33:55 +00001806 if config_primitive:
1807 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001808 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001809 )
tierno588547c2020-07-01 15:30:20 +00001810 num_units = 1
1811 if vca_type == "lxc_proxy_charm":
1812 if element_type == "NS":
1813 num_units = db_nsr.get("config-units") or 1
1814 elif element_type == "VNF":
1815 num_units = db_vnfr.get("config-units") or 1
1816 elif element_type == "VDU":
1817 for v in db_vnfr["vdur"]:
1818 if vdu_id == v["vdu-id-ref"]:
1819 num_units = v.get("config-units") or 1
1820 break
David Garciaaae391f2020-11-09 11:12:54 +01001821 if vca_type != "k8s_proxy_charm":
1822 await self.vca_map[vca_type].install_configuration_sw(
1823 ee_id=ee_id,
1824 artifact_path=artifact_path,
1825 db_dict=db_dict,
1826 config=config,
1827 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001828 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001829 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001830 )
quilesj7e13aeb2019-10-08 13:34:55 +02001831
quilesj63f90042020-01-17 09:53:55 +00001832 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001833 self.update_db_2(
1834 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1835 )
quilesj63f90042020-01-17 09:53:55 +00001836
1837 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001838 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001839 logging_text=logging_text,
1840 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001841 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001842 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001843 )
quilesj63f90042020-01-17 09:53:55 +00001844
Patricia Reinosob4312c02023-01-06 22:28:44 +00001845 if not is_relation_added:
1846 raise LcmException("Relations could not be added to VCA.")
1847
quilesj7e13aeb2019-10-08 13:34:55 +02001848 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001849 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001850 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001851 pub_key = None
1852 user = None
tierno588547c2020-07-01 15:30:20 +00001853 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001854 if deep_get(
1855 config_descriptor, ("config-access", "ssh-access", "required")
1856 ):
tierno588547c2020-07-01 15:30:20 +00001857 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001858 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001859 user = deep_get(
1860 config_descriptor,
1861 ("config-access", "ssh-access", "default-user"),
1862 )
tierno3bedc9b2019-11-27 15:46:57 +00001863 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001864 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001865 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001866 )
quilesj7e13aeb2019-10-08 13:34:55 +02001867
garciadeblas5697b8b2021-03-24 09:17:02 +01001868 step = "Insert public key into VM user={} ssh_key={}".format(
1869 user, pub_key
1870 )
tierno3bedc9b2019-11-27 15:46:57 +00001871 else:
tierno588547c2020-07-01 15:30:20 +00001872 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001873 step = "Waiting to VM being up and getting IP address"
1874 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001875
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001876 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1877 rw_mgmt_ip = None
1878
tierno3bedc9b2019-11-27 15:46:57 +00001879 # n2vc_redesign STEP 5.1
1880 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001881 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001882 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001883 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001884 logging_text, nsr_id, vnfr_id, kdu_name
1885 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001886 vnfd = self.db.get_one(
1887 "vnfds_revisions",
1888 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1889 )
1890 kdu = get_kdu(vnfd, kdu_name)
1891 kdu_services = [
1892 service["name"] for service in get_kdu_services(kdu)
1893 ]
1894 exposed_services = []
1895 for service in services:
1896 if any(s in service["name"] for s in kdu_services):
1897 exposed_services.append(service)
1898 await self.vca_map[vca_type].exec_primitive(
1899 ee_id=ee_id,
1900 primitive_name="config",
1901 params_dict={
1902 "osm-config": json.dumps(
1903 OsmConfigBuilder(
1904 k8s={"services": exposed_services}
1905 ).build()
1906 )
1907 },
1908 vca_id=vca_id,
1909 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001910
1911 # This verification is needed in order to avoid trying to add a public key
1912 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1913 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1914 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1915 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001916 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001917 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1918 logging_text,
1919 nsr_id,
1920 vnfr_id,
1921 vdu_id,
1922 vdu_index,
1923 user=user,
1924 pub_key=pub_key,
1925 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001926
garciadeblas5697b8b2021-03-24 09:17:02 +01001927 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001928
tiernoa5088192019-11-26 16:12:53 +00001929 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001930 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001931
1932 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001933 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001934
1935 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001936 if initial_config_primitive_list:
1937 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001938
1939 # stage, in function of element type: vdu, kdu, vnf or ns
1940 my_vca = vca_deployed_list[vca_index]
1941 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1942 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001943 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001944 elif my_vca.get("member-vnf-index"):
1945 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001946 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001947 else:
1948 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001949 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00001950
tiernoc231a872020-01-21 08:49:05 +00001951 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01001952 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00001953 )
1954
garciadeblas5697b8b2021-03-24 09:17:02 +01001955 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00001956
tiernoe876f672020-02-13 14:34:48 +00001957 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001958 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001959 # adding information on the vca_deployed if it is a NS execution environment
1960 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001961 deploy_params["ns_config_info"] = json.dumps(
1962 self._get_ns_config_info(nsr_id)
1963 )
tiernod8323042019-08-09 11:32:23 +00001964 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01001965 primitive_params_ = self._map_primitive_params(
1966 initial_config_primitive, {}, deploy_params
1967 )
tierno3bedc9b2019-11-27 15:46:57 +00001968
garciadeblas5697b8b2021-03-24 09:17:02 +01001969 step = "execute primitive '{}' params '{}'".format(
1970 initial_config_primitive["name"], primitive_params_
1971 )
tiernod8323042019-08-09 11:32:23 +00001972 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001973 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001974 ee_id=ee_id,
1975 primitive_name=initial_config_primitive["name"],
1976 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02001977 db_dict=db_dict,
1978 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001979 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02001980 )
tiernoe876f672020-02-13 14:34:48 +00001981 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1982 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01001983 if config_descriptor.get("terminate-config-primitive"):
1984 self.update_db_2(
1985 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
1986 )
tiernoe876f672020-02-13 14:34:48 +00001987 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001988
tiernod8323042019-08-09 11:32:23 +00001989 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001990
tiernob996d942020-07-03 14:52:28 +00001991 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00001992 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02001993 # TODO: review for those cases where the helm chart is a reference and
1994 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04001995 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00001996 ee_id=ee_id,
1997 artifact_path=artifact_path,
1998 ee_config_descriptor=ee_config_descriptor,
1999 vnfr_id=vnfr_id,
2000 nsr_id=nsr_id,
2001 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002002 element_type=element_type,
2003 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2004 vdu_id=vdu_id,
2005 vdu_index=vdu_index,
2006 kdu_name=kdu_name,
2007 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002008 )
2009 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002010 self.update_db_2(
2011 "nsrs",
2012 nsr_id,
2013 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2014 )
tiernob996d942020-07-03 14:52:28 +00002015
bravof73bac502021-05-11 07:38:47 -04002016 for job in prometheus_jobs:
2017 self.db.set_one(
2018 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002019 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002020 job,
2021 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002022 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002023 )
2024
quilesj7e13aeb2019-10-08 13:34:55 +02002025 step = "instantiated at VCA"
2026 self.logger.debug(logging_text + step)
2027
tiernoc231a872020-01-21 08:49:05 +00002028 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002029 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002030 )
2031
tiernod8323042019-08-09 11:32:23 +00002032 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002033 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002034 if not isinstance(
2035 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2036 ):
2037 self.logger.error(
2038 "Exception while {} : {}".format(step, e), exc_info=True
2039 )
tiernoc231a872020-01-21 08:49:05 +00002040 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002041 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002042 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002043 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002044
garciadeblas5697b8b2021-03-24 09:17:02 +01002045 def _write_ns_status(
2046 self,
2047 nsr_id: str,
2048 ns_state: str,
2049 current_operation: str,
2050 current_operation_id: str,
2051 error_description: str = None,
2052 error_detail: str = None,
2053 other_update: dict = None,
2054 ):
tiernoe876f672020-02-13 14:34:48 +00002055 """
2056 Update db_nsr fields.
2057 :param nsr_id:
2058 :param ns_state:
2059 :param current_operation:
2060 :param current_operation_id:
2061 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002062 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002063 :param other_update: Other required changes at database if provided, will be cleared
2064 :return:
2065 """
quilesj4cda56b2019-12-05 10:02:20 +00002066 try:
tiernoe876f672020-02-13 14:34:48 +00002067 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002068 db_dict[
2069 "_admin.nslcmop"
2070 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002071 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002072 db_dict["_admin.operation-type"] = (
2073 current_operation if current_operation != "IDLE" else None
2074 )
quilesj4cda56b2019-12-05 10:02:20 +00002075 db_dict["currentOperation"] = current_operation
2076 db_dict["currentOperationID"] = current_operation_id
2077 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002078 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002079
2080 if ns_state:
2081 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002082 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002083 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002084 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002085
garciadeblas5697b8b2021-03-24 09:17:02 +01002086 def _write_op_status(
2087 self,
2088 op_id: str,
2089 stage: list = None,
2090 error_message: str = None,
2091 queuePosition: int = 0,
2092 operation_state: str = None,
2093 other_update: dict = None,
2094 ):
quilesj3655ae02019-12-12 16:08:35 +00002095 try:
tiernoe876f672020-02-13 14:34:48 +00002096 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002097 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002098 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002099 db_dict["stage"] = stage[0]
2100 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002101 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002102 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002103
2104 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002105 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002106 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002107 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002108 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002109 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002110 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002111 self.logger.warn(
2112 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2113 )
quilesj3655ae02019-12-12 16:08:35 +00002114
tierno51183952020-04-03 15:48:18 +00002115 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002116 try:
tierno51183952020-04-03 15:48:18 +00002117 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002118 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002119 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002120 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002121 db_nsr_update = {
2122 "configurationStatus.{}.status".format(index): status
2123 for index, v in enumerate(config_status)
2124 if v
2125 }
quilesj3655ae02019-12-12 16:08:35 +00002126 # update status
tierno51183952020-04-03 15:48:18 +00002127 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002128
tiernoe876f672020-02-13 14:34:48 +00002129 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002130 self.logger.warn(
2131 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2132 )
quilesj3655ae02019-12-12 16:08:35 +00002133
garciadeblas5697b8b2021-03-24 09:17:02 +01002134 def _write_configuration_status(
2135 self,
2136 nsr_id: str,
2137 vca_index: int,
2138 status: str = None,
2139 element_under_configuration: str = None,
2140 element_type: str = None,
2141 other_update: dict = None,
2142 ):
quilesj3655ae02019-12-12 16:08:35 +00002143 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2144 # .format(vca_index, status))
2145
2146 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002147 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002148 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002149 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002150 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002151 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002152 db_dict[
2153 db_path + "elementUnderConfiguration"
2154 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002155 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002156 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002157 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002158 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002159 self.logger.warn(
2160 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2161 status, nsr_id, vca_index, e
2162 )
2163 )
quilesj4cda56b2019-12-05 10:02:20 +00002164
tierno38089af2020-04-16 07:56:58 +00002165 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2166 """
2167 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2168 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2169 Database is used because the result can be obtained from a different LCM worker in case of HA.
2170 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2171 :param db_nslcmop: database content of nslcmop
2172 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002173 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2174 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002175 """
tierno8790a3d2020-04-23 22:49:52 +00002176 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002177 nslcmop_id = db_nslcmop["_id"]
2178 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002179 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002180 self.logger.debug(
2181 logging_text + "Invoke and wait for placement optimization"
2182 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002183 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002184 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002185 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002186 pla_result = None
2187 while not pla_result and wait >= 0:
2188 await asyncio.sleep(db_poll_interval)
2189 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002190 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002191 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002192
2193 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002194 raise LcmException(
2195 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2196 )
magnussonle9198bb2020-01-21 13:00:51 +01002197
garciadeblas5697b8b2021-03-24 09:17:02 +01002198 for pla_vnf in pla_result["vnf"]:
2199 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2200 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002201 continue
tierno8790a3d2020-04-23 22:49:52 +00002202 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002203 self.db.set_one(
2204 "vnfrs",
2205 {"_id": vnfr["_id"]},
2206 {"vim-account-id": pla_vnf["vimAccountId"]},
2207 )
tierno38089af2020-04-16 07:56:58 +00002208 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002209 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002210 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002211
aguilard1ae3c562023-02-16 17:24:35 +00002212 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2213 alerts = []
2214 nsr_id = vnfr["nsr-id-ref"]
2215 df = vnfd.get("df", [{}])[0]
2216 # Checking for auto-healing configuration
2217 if "healing-aspect" in df:
2218 healing_aspects = df["healing-aspect"]
2219 for healing in healing_aspects:
2220 for healing_policy in healing.get("healing-policy", ()):
2221 vdu_id = healing_policy["vdu-id"]
2222 vdur = next(
2223 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2224 {},
2225 )
2226 if not vdur:
2227 continue
2228 metric_name = "vm_status"
2229 vdu_name = vdur.get("name")
2230 vnf_member_index = vnfr["member-vnf-index-ref"]
2231 uuid = str(uuid4())
2232 name = f"healing_{uuid}"
2233 action = healing_policy
2234 # action_on_recovery = healing.get("action-on-recovery")
2235 # cooldown_time = healing.get("cooldown-time")
2236 # day1 = healing.get("day1")
2237 alert = {
2238 "uuid": uuid,
2239 "name": name,
2240 "metric": metric_name,
2241 "tags": {
2242 "ns_id": nsr_id,
2243 "vnf_member_index": vnf_member_index,
2244 "vdu_name": vdu_name,
2245 },
2246 "alarm_status": "ok",
2247 "action_type": "healing",
2248 "action": action,
2249 }
2250 alerts.append(alert)
2251 return alerts
2252
2253 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2254 alerts = []
2255 nsr_id = vnfr["nsr-id-ref"]
2256 df = vnfd.get("df", [{}])[0]
2257 # Checking for auto-scaling configuration
2258 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002259 scaling_aspects = df["scaling-aspect"]
2260 all_vnfd_monitoring_params = {}
2261 for ivld in vnfd.get("int-virtual-link-desc", ()):
2262 for mp in ivld.get("monitoring-parameters", ()):
2263 all_vnfd_monitoring_params[mp.get("id")] = mp
2264 for vdu in vnfd.get("vdu", ()):
2265 for mp in vdu.get("monitoring-parameter", ()):
2266 all_vnfd_monitoring_params[mp.get("id")] = mp
2267 for df in vnfd.get("df", ()):
2268 for mp in df.get("monitoring-parameter", ()):
2269 all_vnfd_monitoring_params[mp.get("id")] = mp
2270 for scaling_aspect in scaling_aspects:
2271 scaling_group_name = scaling_aspect.get("name", "")
2272 # Get monitored VDUs
2273 all_monitored_vdus = set()
2274 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2275 "deltas", ()
2276 ):
2277 for vdu_delta in delta.get("vdu-delta", ()):
2278 all_monitored_vdus.add(vdu_delta.get("id"))
2279 monitored_vdurs = list(
2280 filter(
2281 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2282 vnfr["vdur"],
2283 )
2284 )
2285 if not monitored_vdurs:
2286 self.logger.error(
2287 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2288 )
2289 continue
2290 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2291 if scaling_policy["scaling-type"] != "automatic":
2292 continue
2293 threshold_time = scaling_policy.get("threshold-time", "1")
2294 cooldown_time = scaling_policy.get("cooldown-time", "0")
2295 for scaling_criteria in scaling_policy["scaling-criteria"]:
2296 monitoring_param_ref = scaling_criteria.get(
2297 "vnf-monitoring-param-ref"
2298 )
2299 vnf_monitoring_param = all_vnfd_monitoring_params[
2300 monitoring_param_ref
2301 ]
2302 for vdur in monitored_vdurs:
2303 vdu_id = vdur["vdu-id-ref"]
2304 metric_name = vnf_monitoring_param.get("performance-metric")
aguilarde416ea02023-05-08 15:09:37 +00002305 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002306 vnf_member_index = vnfr["member-vnf-index-ref"]
2307 scalein_threshold = scaling_criteria.get(
2308 "scale-in-threshold"
2309 )
2310 scaleout_threshold = scaling_criteria.get(
2311 "scale-out-threshold"
2312 )
2313 # Looking for min/max-number-of-instances
2314 instances_min_number = 1
2315 instances_max_number = 1
2316 vdu_profile = df["vdu-profile"]
2317 if vdu_profile:
2318 profile = next(
2319 item for item in vdu_profile if item["id"] == vdu_id
2320 )
2321 instances_min_number = profile.get(
2322 "min-number-of-instances", 1
2323 )
2324 instances_max_number = profile.get(
2325 "max-number-of-instances", 1
2326 )
2327
2328 if scalein_threshold:
2329 uuid = str(uuid4())
2330 name = f"scalein_{uuid}"
2331 operation = scaling_criteria[
2332 "scale-in-relational-operation"
2333 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002334 rel_operator = self.rel_operation_types.get(
2335 operation, "<="
2336 )
aguilard1ae3c562023-02-16 17:24:35 +00002337 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2338 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
2339 labels = {
2340 "ns_id": nsr_id,
2341 "vnf_member_index": vnf_member_index,
2342 "vdu_id": vdu_id,
2343 }
2344 prom_cfg = {
2345 "alert": name,
2346 "expr": expression,
2347 "for": str(threshold_time) + "m",
2348 "labels": labels,
2349 }
2350 action = scaling_policy
2351 action = {
2352 "scaling-group": scaling_group_name,
2353 "cooldown-time": cooldown_time,
2354 }
2355 alert = {
2356 "uuid": uuid,
2357 "name": name,
2358 "metric": metric_name,
2359 "tags": {
2360 "ns_id": nsr_id,
2361 "vnf_member_index": vnf_member_index,
2362 "vdu_id": vdu_id,
2363 },
2364 "alarm_status": "ok",
2365 "action_type": "scale_in",
2366 "action": action,
2367 "prometheus_config": prom_cfg,
2368 }
2369 alerts.append(alert)
2370
2371 if scaleout_threshold:
2372 uuid = str(uuid4())
2373 name = f"scaleout_{uuid}"
2374 operation = scaling_criteria[
2375 "scale-out-relational-operation"
2376 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002377 rel_operator = self.rel_operation_types.get(
2378 operation, "<="
2379 )
aguilard1ae3c562023-02-16 17:24:35 +00002380 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2381 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
2382 labels = {
2383 "ns_id": nsr_id,
2384 "vnf_member_index": vnf_member_index,
2385 "vdu_id": vdu_id,
2386 }
2387 prom_cfg = {
2388 "alert": name,
2389 "expr": expression,
2390 "for": str(threshold_time) + "m",
2391 "labels": labels,
2392 }
2393 action = scaling_policy
2394 action = {
2395 "scaling-group": scaling_group_name,
2396 "cooldown-time": cooldown_time,
2397 }
2398 alert = {
2399 "uuid": uuid,
2400 "name": name,
2401 "metric": metric_name,
2402 "tags": {
2403 "ns_id": nsr_id,
2404 "vnf_member_index": vnf_member_index,
2405 "vdu_id": vdu_id,
2406 },
2407 "alarm_status": "ok",
2408 "action_type": "scale_out",
2409 "action": action,
2410 "prometheus_config": prom_cfg,
2411 }
2412 alerts.append(alert)
2413 return alerts
2414
garciadeblas9148fa82023-05-30 12:51:14 +02002415 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2416 alerts = []
2417 nsr_id = vnfr["nsr-id-ref"]
2418 vnf_member_index = vnfr["member-vnf-index-ref"]
2419
2420 # Checking for VNF alarm configuration
2421 for vdur in vnfr["vdur"]:
2422 vdu_id = vdur["vdu-id-ref"]
2423 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2424 if "alarm" in vdu:
2425 # Get VDU monitoring params, since alerts are based on them
2426 vdu_monitoring_params = {}
2427 for mp in vdu.get("monitoring-parameter", []):
2428 vdu_monitoring_params[mp.get("id")] = mp
2429 if not vdu_monitoring_params:
2430 self.logger.error(
2431 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2432 )
2433 continue
2434 # Get alarms in the VDU
2435 alarm_descriptors = vdu["alarm"]
2436 # Create VDU alarms for each alarm in the VDU
2437 for alarm_descriptor in alarm_descriptors:
2438 # Check that the VDU alarm refers to a proper monitoring param
2439 alarm_monitoring_param = alarm_descriptor.get(
2440 "vnf-monitoring-param-ref", ""
2441 )
2442 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2443 alarm_monitoring_param, {}
2444 )
2445 if not vdu_specific_monitoring_param:
2446 self.logger.error(
2447 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2448 )
2449 continue
2450 metric_name = vdu_specific_monitoring_param.get(
2451 "performance-metric"
2452 )
2453 if not metric_name:
2454 self.logger.error(
2455 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2456 )
2457 continue
2458 # Set params of the alarm to be created in Prometheus
2459 metric_name = f"osm_{metric_name}"
2460 metric_threshold = alarm_descriptor.get("value")
2461 uuid = str(uuid4())
2462 alert_name = f"vdu_alarm_{uuid}"
2463 operation = alarm_descriptor["operation"]
2464 rel_operator = self.rel_operation_types.get(operation, "<=")
2465 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 +00002466 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002467 labels = {
2468 "ns_id": nsr_id,
2469 "vnf_member_index": vnf_member_index,
2470 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002471 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002472 }
2473 prom_cfg = {
2474 "alert": alert_name,
2475 "expr": expression,
2476 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2477 "labels": labels,
2478 }
2479 alarm_action = dict()
2480 for action_type in ["ok", "insufficient-data", "alarm"]:
2481 if (
2482 "actions" in alarm_descriptor
2483 and action_type in alarm_descriptor["actions"]
2484 ):
aguilardeb076722023-05-31 09:45:00 +00002485 alarm_action[action_type] = alarm_descriptor["actions"][
2486 action_type
2487 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002488 alert = {
2489 "uuid": uuid,
2490 "name": alert_name,
2491 "metric": metric_name,
2492 "tags": {
2493 "ns_id": nsr_id,
2494 "vnf_member_index": vnf_member_index,
2495 "vdu_id": vdu_id,
2496 },
2497 "alarm_status": "ok",
2498 "action_type": "vdu_alarm",
2499 "action": alarm_action,
2500 "prometheus_config": prom_cfg,
2501 }
2502 alerts.append(alert)
2503 return alerts
2504
magnussonle9198bb2020-01-21 13:00:51 +01002505 def update_nsrs_with_pla_result(self, params):
2506 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002507 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2508 self.update_db_2(
2509 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2510 )
magnussonle9198bb2020-01-21 13:00:51 +01002511 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002512 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002513
tierno59d22d22018-09-25 18:10:19 +02002514 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002515 """
2516
2517 :param nsr_id: ns instance to deploy
2518 :param nslcmop_id: operation to run
2519 :return:
2520 """
kuused124bfe2019-06-18 12:09:24 +02002521
2522 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002523 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002524 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002525 self.logger.debug(
2526 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2527 )
kuused124bfe2019-06-18 12:09:24 +02002528 return
2529
tierno59d22d22018-09-25 18:10:19 +02002530 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2531 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002532
tierno59d22d22018-09-25 18:10:19 +02002533 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002534
2535 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002536 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002537
2538 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002539 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002540
2541 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002542 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002543 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002544 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002545
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002546 timeout_ns_deploy = self.timeout.ns_deploy
2547
tierno59d22d22018-09-25 18:10:19 +02002548 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002549 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002550 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002551 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002552 exc = None
tiernoe876f672020-02-13 14:34:48 +00002553 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002554 stage = [
2555 "Stage 1/5: preparation of the environment.",
2556 "Waiting for previous operations to terminate.",
2557 "",
2558 ]
tiernoe876f672020-02-13 14:34:48 +00002559 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002560 try:
kuused124bfe2019-06-18 12:09:24 +02002561 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002562 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002563
quilesj7e13aeb2019-10-08 13:34:55 +02002564 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002565 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002566 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002567 db_nsr_update["detailed-status"] = "creating"
2568 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002569 self._write_ns_status(
2570 nsr_id=nsr_id,
2571 ns_state="BUILDING",
2572 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002573 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002574 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002575 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002576 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002577
quilesj7e13aeb2019-10-08 13:34:55 +02002578 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002579 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002580 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002581 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2582 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2583 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2584 )
tierno744303e2020-01-13 16:46:31 +00002585 ns_params = db_nslcmop.get("operationParams")
2586 if ns_params and ns_params.get("timeout_ns_deploy"):
2587 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002588
2589 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002590 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002591 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002592 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002593 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002594 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002595 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002596 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002597 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002598 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002599
quilesj7e13aeb2019-10-08 13:34:55 +02002600 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002601 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002602 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002603 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002604
quilesj7e13aeb2019-10-08 13:34:55 +02002605 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002606 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002607
2608 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002609 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002610 if vnfr.get("kdur"):
2611 kdur_list = []
2612 for kdur in vnfr["kdur"]:
2613 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002614 kdur["additionalParams"] = json.loads(
2615 kdur["additionalParams"]
2616 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002617 kdur_list.append(kdur)
2618 vnfr["kdur"] = kdur_list
2619
bravof922c4172020-11-24 21:21:43 -03002620 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2621 vnfd_id = vnfr["vnfd-id"]
2622 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002623 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002624
quilesj7e13aeb2019-10-08 13:34:55 +02002625 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002626 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002627 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002628 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2629 vnfd_id, vnfd_ref
2630 )
tiernoe876f672020-02-13 14:34:48 +00002631 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002632 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002633
quilesj7e13aeb2019-10-08 13:34:55 +02002634 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002635 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002636
2637 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002638 vca_deployed_list = None
2639 if db_nsr["_admin"].get("deployed"):
2640 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2641 if vca_deployed_list is None:
2642 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002643 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002644 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002645 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002646 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002647 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002648 elif isinstance(vca_deployed_list, dict):
2649 # maintain backward compatibility. Change a dict to list at database
2650 vca_deployed_list = list(vca_deployed_list.values())
2651 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002652 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002653
garciadeblas5697b8b2021-03-24 09:17:02 +01002654 if not isinstance(
2655 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2656 ):
tiernoa009e552019-01-30 16:45:44 +00002657 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2658 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002659
tiernobaa51102018-12-14 13:16:18 +00002660 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2661 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2662 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002663 self.db.set_list(
2664 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2665 )
quilesj3655ae02019-12-12 16:08:35 +00002666
2667 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002668 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2669 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002670
tiernob5203912020-08-11 11:20:13 +00002671 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002672 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002673 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002674 await self.deploy_kdus(
2675 logging_text=logging_text,
2676 nsr_id=nsr_id,
2677 nslcmop_id=nslcmop_id,
2678 db_vnfrs=db_vnfrs,
2679 db_vnfds=db_vnfds,
2680 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002681 )
tiernoe876f672020-02-13 14:34:48 +00002682
2683 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002684 # n2vc_redesign STEP 1 Get VCA public ssh-key
2685 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002686 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002687 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002688 if self.vca_config.public_key:
2689 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002690
tiernoe876f672020-02-13 14:34:48 +00002691 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002692 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002693 self.instantiate_RO(
2694 logging_text=logging_text,
2695 nsr_id=nsr_id,
2696 nsd=nsd,
2697 db_nsr=db_nsr,
2698 db_nslcmop=db_nslcmop,
2699 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002700 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002701 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002702 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002703 )
tiernod8323042019-08-09 11:32:23 +00002704 )
2705 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002706 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002707
tiernod8323042019-08-09 11:32:23 +00002708 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002709 stage[1] = "Deploying Execution Environments."
2710 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002711
Gabriel Cuba1411a002022-10-07 11:38:23 -05002712 # create namespace and certificate if any helm based EE is present in the NS
2713 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002714 await self.vca_map["helm-v3"].setup_ns_namespace(
2715 name=nsr_id,
2716 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002717 # create TLS certificates
2718 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002719 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002720 dns_prefix="*",
2721 nsr_id=nsr_id,
2722 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002723 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002724 )
2725
tiernod8323042019-08-09 11:32:23 +00002726 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002727 for vnf_profile in get_vnf_profiles(nsd):
2728 vnfd_id = vnf_profile["vnfd-id"]
2729 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2730 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002731 db_vnfr = db_vnfrs[member_vnf_index]
2732 base_folder = vnfd["_admin"]["storage"]
2733 vdu_id = None
2734 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002735 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002736 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002737 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002738
tierno8a518872018-12-21 13:42:14 +00002739 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002740 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002741 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002742 deploy_params.update(
2743 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2744 )
tierno8a518872018-12-21 13:42:14 +00002745
bravofe5a31bc2021-02-17 19:09:12 -03002746 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002747 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002748 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002749 logging_text=logging_text
2750 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002751 db_nsr=db_nsr,
2752 db_vnfr=db_vnfr,
2753 nslcmop_id=nslcmop_id,
2754 nsr_id=nsr_id,
2755 nsi_id=nsi_id,
2756 vnfd_id=vnfd_id,
2757 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002758 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002759 member_vnf_index=member_vnf_index,
2760 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002761 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002762 vdu_name=vdu_name,
2763 deploy_params=deploy_params,
2764 descriptor_config=descriptor_config,
2765 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002766 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002767 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002768 )
tierno59d22d22018-09-25 18:10:19 +02002769
2770 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002771 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002772 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002773 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002774 vdur = find_in_list(
2775 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2776 )
bravof922c4172020-11-24 21:21:43 -03002777
tierno626e0152019-11-29 14:16:16 +00002778 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002779 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002780 else:
2781 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002782 deploy_params_vdu["OSM"] = get_osm_params(
2783 db_vnfr, vdu_id, vdu_count_index=0
2784 )
endika76ba9232021-06-21 18:55:07 +02002785 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002786
2787 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002788 self.logger.debug(
2789 "Descriptor config > {}".format(descriptor_config)
2790 )
tierno588547c2020-07-01 15:30:20 +00002791 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002792 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002793 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002794 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002795 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002796 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002797 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002798 logging_text=logging_text
2799 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2800 member_vnf_index, vdu_id, vdu_index
2801 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002802 db_nsr=db_nsr,
2803 db_vnfr=db_vnfr,
2804 nslcmop_id=nslcmop_id,
2805 nsr_id=nsr_id,
2806 nsi_id=nsi_id,
2807 vnfd_id=vnfd_id,
2808 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002809 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002810 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002811 member_vnf_index=member_vnf_index,
2812 vdu_index=vdu_index,
2813 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002814 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002815 descriptor_config=descriptor_config,
2816 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002817 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002818 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002819 )
bravof922c4172020-11-24 21:21:43 -03002820 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002821 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002822 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002823 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002824 vdu_id = None
2825 vdu_index = 0
2826 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002827 kdu_index, kdur = next(
2828 x
2829 for x in enumerate(db_vnfr["kdur"])
2830 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002831 )
bravof922c4172020-11-24 21:21:43 -03002832 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002833 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002834 deploy_params_kdu.update(
2835 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002836 )
tierno59d22d22018-09-25 18:10:19 +02002837
calvinosanch9f9c6f22019-11-04 13:37:39 +01002838 self._deploy_n2vc(
2839 logging_text=logging_text,
2840 db_nsr=db_nsr,
2841 db_vnfr=db_vnfr,
2842 nslcmop_id=nslcmop_id,
2843 nsr_id=nsr_id,
2844 nsi_id=nsi_id,
2845 vnfd_id=vnfd_id,
2846 vdu_id=vdu_id,
2847 kdu_name=kdu_name,
2848 member_vnf_index=member_vnf_index,
2849 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002850 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002851 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002852 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002853 descriptor_config=descriptor_config,
2854 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002855 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002856 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002857 )
tierno59d22d22018-09-25 18:10:19 +02002858
k4.rahul74944982023-04-19 17:00:52 +05302859 # Check if each vnf has exporter for metric collection if so update prometheus job records
2860 if "exporters-endpoints" in vnfd.get("df")[0]:
2861 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2862 self.logger.debug("exporter config :{}".format(exporter_config))
2863 artifact_path = "{}/{}/{}".format(
2864 base_folder["folder"],
2865 base_folder["pkg-dir"],
2866 "exporter-endpoint",
2867 )
2868 ee_id = None
2869 ee_config_descriptor = exporter_config
2870 vnfr_id = db_vnfr["id"]
2871 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2872 logging_text,
2873 nsr_id,
2874 vnfr_id,
2875 vdu_id=None,
2876 vdu_index=None,
2877 user=None,
2878 pub_key=None,
2879 )
2880 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2881 self.logger.debug("Artifact_path:{}".format(artifact_path))
2882 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2883 vdu_id_for_prom = None
2884 vdu_index_for_prom = None
2885 for x in get_iterable(db_vnfr, "vdur"):
2886 vdu_id_for_prom = x.get("vdu-id-ref")
2887 vdu_index_for_prom = x.get("count-index")
2888 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2889 ee_id=ee_id,
2890 artifact_path=artifact_path,
2891 ee_config_descriptor=ee_config_descriptor,
2892 vnfr_id=vnfr_id,
2893 nsr_id=nsr_id,
2894 target_ip=rw_mgmt_ip,
2895 element_type="VDU",
2896 vdu_id=vdu_id_for_prom,
2897 vdu_index=vdu_index_for_prom,
2898 )
2899
2900 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2901 if prometheus_jobs:
2902 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2903 self.update_db_2(
2904 "nsrs",
2905 nsr_id,
2906 db_nsr_update,
2907 )
2908
2909 for job in prometheus_jobs:
2910 self.db.set_one(
2911 "prometheus_jobs",
2912 {"job_name": job["job_name"]},
2913 job,
2914 upsert=True,
2915 fail_on_empty=False,
2916 )
2917
tierno1b633412019-02-25 16:48:23 +00002918 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002919 descriptor_config = nsd.get("ns-configuration")
2920 if descriptor_config and descriptor_config.get("juju"):
2921 vnfd_id = None
2922 db_vnfr = None
2923 member_vnf_index = None
2924 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002925 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002926 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00002927 vdu_index = 0
2928 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002929
tiernod8323042019-08-09 11:32:23 +00002930 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002931 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002932 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002933 deploy_params.update(
2934 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2935 )
tiernod8323042019-08-09 11:32:23 +00002936 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002937 self._deploy_n2vc(
2938 logging_text=logging_text,
2939 db_nsr=db_nsr,
2940 db_vnfr=db_vnfr,
2941 nslcmop_id=nslcmop_id,
2942 nsr_id=nsr_id,
2943 nsi_id=nsi_id,
2944 vnfd_id=vnfd_id,
2945 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002946 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002947 member_vnf_index=member_vnf_index,
2948 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002949 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002950 vdu_name=vdu_name,
2951 deploy_params=deploy_params,
2952 descriptor_config=descriptor_config,
2953 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002954 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002955 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002956 )
tierno1b633412019-02-25 16:48:23 +00002957
tiernoe876f672020-02-13 14:34:48 +00002958 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002959
garciadeblas5697b8b2021-03-24 09:17:02 +01002960 except (
2961 ROclient.ROClientException,
2962 DbException,
2963 LcmException,
2964 N2VCException,
2965 ) as e:
2966 self.logger.error(
2967 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
2968 )
tierno59d22d22018-09-25 18:10:19 +02002969 exc = e
2970 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01002971 self.logger.error(
2972 logging_text + "Cancelled Exception while '{}'".format(stage[1])
2973 )
tierno59d22d22018-09-25 18:10:19 +02002974 exc = "Operation was cancelled"
2975 except Exception as e:
2976 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01002977 self.logger.critical(
2978 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
2979 exc_info=True,
2980 )
tierno59d22d22018-09-25 18:10:19 +02002981 finally:
2982 if exc:
tiernoe876f672020-02-13 14:34:48 +00002983 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00002984 try:
tiernoe876f672020-02-13 14:34:48 +00002985 # wait for pending tasks
2986 if tasks_dict_info:
2987 stage[1] = "Waiting for instantiate pending tasks."
2988 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01002989 error_list += await self._wait_for_tasks(
2990 logging_text,
2991 tasks_dict_info,
2992 timeout_ns_deploy,
2993 stage,
2994 nslcmop_id,
2995 nsr_id=nsr_id,
2996 )
tiernoe876f672020-02-13 14:34:48 +00002997 stage[1] = stage[2] = ""
2998 except asyncio.CancelledError:
2999 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003000 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3001 await self._wait_for_tasks(
3002 logging_text,
3003 tasks_dict_info,
3004 timeout_ns_deploy,
3005 stage,
3006 nslcmop_id,
3007 nsr_id=nsr_id,
3008 )
tiernoe876f672020-02-13 14:34:48 +00003009 except Exception as exc:
3010 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003011
tiernoe876f672020-02-13 14:34:48 +00003012 # update operation-status
3013 db_nsr_update["operational-status"] = "running"
3014 # let's begin with VCA 'configured' status (later we can change it)
3015 db_nsr_update["config-status"] = "configured"
3016 for task, task_name in tasks_dict_info.items():
3017 if not task.done() or task.cancelled() or task.exception():
3018 if task_name.startswith(self.task_name_deploy_vca):
3019 # A N2VC task is pending
3020 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003021 else:
tiernoe876f672020-02-13 14:34:48 +00003022 # RO or KDU task is pending
3023 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003024
tiernoe876f672020-02-13 14:34:48 +00003025 # update status at database
3026 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003027 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003028 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003029 error_description_nslcmop = "{} Detail: {}".format(
3030 stage[0], error_detail
3031 )
3032 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3033 nslcmop_id, stage[0]
3034 )
quilesj3655ae02019-12-12 16:08:35 +00003035
garciadeblas5697b8b2021-03-24 09:17:02 +01003036 db_nsr_update["detailed-status"] = (
3037 error_description_nsr + " Detail: " + error_detail
3038 )
tiernoe876f672020-02-13 14:34:48 +00003039 db_nslcmop_update["detailed-status"] = error_detail
3040 nslcmop_operation_state = "FAILED"
3041 ns_state = "BROKEN"
3042 else:
tiernoa2143262020-03-27 16:20:40 +00003043 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003044 error_description_nsr = error_description_nslcmop = None
3045 ns_state = "READY"
3046 db_nsr_update["detailed-status"] = "Done"
3047 db_nslcmop_update["detailed-status"] = "Done"
3048 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003049 # Gather auto-healing and auto-scaling alerts for each vnfr
3050 healing_alerts = []
3051 scaling_alerts = []
3052 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3053 vnfd = next(
3054 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3055 )
3056 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3057 for alert in healing_alerts:
3058 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3059 self.db.create("alerts", alert)
3060
3061 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3062 for alert in scaling_alerts:
3063 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3064 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003065
garciadeblas9148fa82023-05-30 12:51:14 +02003066 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3067 for alert in alarm_alerts:
3068 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3069 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003070 if db_nsr:
3071 self._write_ns_status(
3072 nsr_id=nsr_id,
3073 ns_state=ns_state,
3074 current_operation="IDLE",
3075 current_operation_id=None,
3076 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003077 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003078 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003079 )
tiernoa17d4f42020-04-28 09:59:23 +00003080 self._write_op_status(
3081 op_id=nslcmop_id,
3082 stage="",
3083 error_message=error_description_nslcmop,
3084 operation_state=nslcmop_operation_state,
3085 other_update=db_nslcmop_update,
3086 )
quilesj3655ae02019-12-12 16:08:35 +00003087
tierno59d22d22018-09-25 18:10:19 +02003088 if nslcmop_operation_state:
3089 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003090 await self.msg.aiowrite(
3091 "ns",
3092 "instantiated",
3093 {
3094 "nsr_id": nsr_id,
3095 "nslcmop_id": nslcmop_id,
3096 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003097 "startTime": db_nslcmop["startTime"],
3098 "links": db_nslcmop["links"],
3099 "operationParams": {
3100 "nsInstanceId": nsr_id,
3101 "nsdId": db_nsr["nsd-id"],
3102 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003103 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003104 )
tierno59d22d22018-09-25 18:10:19 +02003105 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003106 self.logger.error(
3107 logging_text + "kafka_write notification Exception {}".format(e)
3108 )
tierno59d22d22018-09-25 18:10:19 +02003109
3110 self.logger.debug(logging_text + "Exit")
3111 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3112
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003113 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003114 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003115 cached_vnfds[vnfd_id] = self.db.get_one(
3116 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3117 )
David Garciab4ebcd02021-10-28 02:00:43 +02003118 return cached_vnfds[vnfd_id]
3119
3120 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3121 if vnf_profile_id not in cached_vnfrs:
3122 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3123 "vnfrs",
3124 {
3125 "member-vnf-index-ref": vnf_profile_id,
3126 "nsr-id-ref": nsr_id,
3127 },
3128 )
3129 return cached_vnfrs[vnf_profile_id]
3130
3131 def _is_deployed_vca_in_relation(
3132 self, vca: DeployedVCA, relation: Relation
3133 ) -> bool:
3134 found = False
3135 for endpoint in (relation.provider, relation.requirer):
3136 if endpoint["kdu-resource-profile-id"]:
3137 continue
3138 found = (
3139 vca.vnf_profile_id == endpoint.vnf_profile_id
3140 and vca.vdu_profile_id == endpoint.vdu_profile_id
3141 and vca.execution_environment_ref == endpoint.execution_environment_ref
3142 )
3143 if found:
3144 break
3145 return found
3146
3147 def _update_ee_relation_data_with_implicit_data(
3148 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3149 ):
3150 ee_relation_data = safe_get_ee_relation(
3151 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3152 )
3153 ee_relation_level = EELevel.get_level(ee_relation_data)
3154 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3155 "execution-environment-ref"
3156 ]:
3157 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3158 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003159 project = nsd["_admin"]["projects_read"][0]
3160 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003161 entity_id = (
3162 vnfd_id
3163 if ee_relation_level == EELevel.VNF
3164 else ee_relation_data["vdu-profile-id"]
3165 )
3166 ee = get_juju_ee_ref(db_vnfd, entity_id)
3167 if not ee:
3168 raise Exception(
3169 f"not execution environments found for ee_relation {ee_relation_data}"
3170 )
3171 ee_relation_data["execution-environment-ref"] = ee["id"]
3172 return ee_relation_data
3173
3174 def _get_ns_relations(
3175 self,
3176 nsr_id: str,
3177 nsd: Dict[str, Any],
3178 vca: DeployedVCA,
3179 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003180 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003181 relations = []
3182 db_ns_relations = get_ns_configuration_relation_list(nsd)
3183 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003184 provider_dict = None
3185 requirer_dict = None
3186 if all(key in r for key in ("provider", "requirer")):
3187 provider_dict = r["provider"]
3188 requirer_dict = r["requirer"]
3189 elif "entities" in r:
3190 provider_id = r["entities"][0]["id"]
3191 provider_dict = {
3192 "nsr-id": nsr_id,
3193 "endpoint": r["entities"][0]["endpoint"],
3194 }
3195 if provider_id != nsd["id"]:
3196 provider_dict["vnf-profile-id"] = provider_id
3197 requirer_id = r["entities"][1]["id"]
3198 requirer_dict = {
3199 "nsr-id": nsr_id,
3200 "endpoint": r["entities"][1]["endpoint"],
3201 }
3202 if requirer_id != nsd["id"]:
3203 requirer_dict["vnf-profile-id"] = requirer_id
3204 else:
aticig15db6142022-01-24 12:51:26 +03003205 raise Exception(
3206 "provider/requirer or entities must be included in the relation."
3207 )
David Garciab4ebcd02021-10-28 02:00:43 +02003208 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003209 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003210 )
3211 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003212 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003213 )
3214 provider = EERelation(relation_provider)
3215 requirer = EERelation(relation_requirer)
3216 relation = Relation(r["name"], provider, requirer)
3217 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3218 if vca_in_relation:
3219 relations.append(relation)
3220 return relations
3221
3222 def _get_vnf_relations(
3223 self,
3224 nsr_id: str,
3225 nsd: Dict[str, Any],
3226 vca: DeployedVCA,
3227 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003228 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003229 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003230 if vca.target_element == "ns":
3231 self.logger.debug("VCA is a NS charm, not a VNF.")
3232 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003233 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3234 vnf_profile_id = vnf_profile["id"]
3235 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003236 project = nsd["_admin"]["projects_read"][0]
3237 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003238 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3239 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003240 provider_dict = None
3241 requirer_dict = None
3242 if all(key in r for key in ("provider", "requirer")):
3243 provider_dict = r["provider"]
3244 requirer_dict = r["requirer"]
3245 elif "entities" in r:
3246 provider_id = r["entities"][0]["id"]
3247 provider_dict = {
3248 "nsr-id": nsr_id,
3249 "vnf-profile-id": vnf_profile_id,
3250 "endpoint": r["entities"][0]["endpoint"],
3251 }
3252 if provider_id != vnfd_id:
3253 provider_dict["vdu-profile-id"] = provider_id
3254 requirer_id = r["entities"][1]["id"]
3255 requirer_dict = {
3256 "nsr-id": nsr_id,
3257 "vnf-profile-id": vnf_profile_id,
3258 "endpoint": r["entities"][1]["endpoint"],
3259 }
3260 if requirer_id != vnfd_id:
3261 requirer_dict["vdu-profile-id"] = requirer_id
3262 else:
aticig15db6142022-01-24 12:51:26 +03003263 raise Exception(
3264 "provider/requirer or entities must be included in the relation."
3265 )
David Garciab4ebcd02021-10-28 02:00:43 +02003266 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003267 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003268 )
3269 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003270 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003271 )
3272 provider = EERelation(relation_provider)
3273 requirer = EERelation(relation_requirer)
3274 relation = Relation(r["name"], provider, requirer)
3275 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3276 if vca_in_relation:
3277 relations.append(relation)
3278 return relations
3279
3280 def _get_kdu_resource_data(
3281 self,
3282 ee_relation: EERelation,
3283 db_nsr: Dict[str, Any],
3284 cached_vnfds: Dict[str, Any],
3285 ) -> DeployedK8sResource:
3286 nsd = get_nsd(db_nsr)
3287 vnf_profiles = get_vnf_profiles(nsd)
3288 vnfd_id = find_in_list(
3289 vnf_profiles,
3290 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3291 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003292 project = nsd["_admin"]["projects_read"][0]
3293 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003294 kdu_resource_profile = get_kdu_resource_profile(
3295 db_vnfd, ee_relation.kdu_resource_profile_id
3296 )
3297 kdu_name = kdu_resource_profile["kdu-name"]
3298 deployed_kdu, _ = get_deployed_kdu(
3299 db_nsr.get("_admin", ()).get("deployed", ()),
3300 kdu_name,
3301 ee_relation.vnf_profile_id,
3302 )
3303 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3304 return deployed_kdu
3305
3306 def _get_deployed_component(
3307 self,
3308 ee_relation: EERelation,
3309 db_nsr: Dict[str, Any],
3310 cached_vnfds: Dict[str, Any],
3311 ) -> DeployedComponent:
3312 nsr_id = db_nsr["_id"]
3313 deployed_component = None
3314 ee_level = EELevel.get_level(ee_relation)
3315 if ee_level == EELevel.NS:
3316 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3317 if vca:
3318 deployed_component = DeployedVCA(nsr_id, vca)
3319 elif ee_level == EELevel.VNF:
3320 vca = get_deployed_vca(
3321 db_nsr,
3322 {
3323 "vdu_id": None,
3324 "member-vnf-index": ee_relation.vnf_profile_id,
3325 "ee_descriptor_id": ee_relation.execution_environment_ref,
3326 },
3327 )
3328 if vca:
3329 deployed_component = DeployedVCA(nsr_id, vca)
3330 elif ee_level == EELevel.VDU:
3331 vca = get_deployed_vca(
3332 db_nsr,
3333 {
3334 "vdu_id": ee_relation.vdu_profile_id,
3335 "member-vnf-index": ee_relation.vnf_profile_id,
3336 "ee_descriptor_id": ee_relation.execution_environment_ref,
3337 },
3338 )
3339 if vca:
3340 deployed_component = DeployedVCA(nsr_id, vca)
3341 elif ee_level == EELevel.KDU:
3342 kdu_resource_data = self._get_kdu_resource_data(
3343 ee_relation, db_nsr, cached_vnfds
3344 )
3345 if kdu_resource_data:
3346 deployed_component = DeployedK8sResource(kdu_resource_data)
3347 return deployed_component
3348
3349 async def _add_relation(
3350 self,
3351 relation: Relation,
3352 vca_type: str,
3353 db_nsr: Dict[str, Any],
3354 cached_vnfds: Dict[str, Any],
3355 cached_vnfrs: Dict[str, Any],
3356 ) -> bool:
3357 deployed_provider = self._get_deployed_component(
3358 relation.provider, db_nsr, cached_vnfds
3359 )
3360 deployed_requirer = self._get_deployed_component(
3361 relation.requirer, db_nsr, cached_vnfds
3362 )
3363 if (
3364 deployed_provider
3365 and deployed_requirer
3366 and deployed_provider.config_sw_installed
3367 and deployed_requirer.config_sw_installed
3368 ):
3369 provider_db_vnfr = (
3370 self._get_vnfr(
3371 relation.provider.nsr_id,
3372 relation.provider.vnf_profile_id,
3373 cached_vnfrs,
3374 )
3375 if relation.provider.vnf_profile_id
3376 else None
3377 )
3378 requirer_db_vnfr = (
3379 self._get_vnfr(
3380 relation.requirer.nsr_id,
3381 relation.requirer.vnf_profile_id,
3382 cached_vnfrs,
3383 )
3384 if relation.requirer.vnf_profile_id
3385 else None
3386 )
3387 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3388 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3389 provider_relation_endpoint = RelationEndpoint(
3390 deployed_provider.ee_id,
3391 provider_vca_id,
3392 relation.provider.endpoint,
3393 )
3394 requirer_relation_endpoint = RelationEndpoint(
3395 deployed_requirer.ee_id,
3396 requirer_vca_id,
3397 relation.requirer.endpoint,
3398 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003399 try:
3400 await self.vca_map[vca_type].add_relation(
3401 provider=provider_relation_endpoint,
3402 requirer=requirer_relation_endpoint,
3403 )
3404 except N2VCException as exception:
3405 self.logger.error(exception)
3406 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003407 return True
3408 return False
3409
David Garciac1fe90a2021-03-31 19:12:02 +02003410 async def _add_vca_relations(
3411 self,
3412 logging_text,
3413 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003414 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003415 vca_index: int,
3416 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003417 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003418 # steps:
3419 # 1. find all relations for this VCA
3420 # 2. wait for other peers related
3421 # 3. add relations
3422
3423 try:
quilesj63f90042020-01-17 09:53:55 +00003424 # STEP 1: find all relations for this VCA
3425
3426 # read nsr record
3427 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003428 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003429
3430 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003431 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3432 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003433
David Garciab4ebcd02021-10-28 02:00:43 +02003434 cached_vnfds = {}
3435 cached_vnfrs = {}
3436 relations = []
3437 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3438 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003439
3440 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003441 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003442 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003443 return True
3444
David Garciab4ebcd02021-10-28 02:00:43 +02003445 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003446
3447 # add all relations
3448 start = time()
3449 while True:
3450 # check timeout
3451 now = time()
3452 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003453 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003454 return False
3455
David Garciab4ebcd02021-10-28 02:00:43 +02003456 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003457 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3458
David Garciab4ebcd02021-10-28 02:00:43 +02003459 # for each relation, find the VCA's related
3460 for relation in relations.copy():
3461 added = await self._add_relation(
3462 relation,
3463 vca_type,
3464 db_nsr,
3465 cached_vnfds,
3466 cached_vnfrs,
3467 )
3468 if added:
3469 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003470
David Garciab4ebcd02021-10-28 02:00:43 +02003471 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003472 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003473 break
David Garciab4ebcd02021-10-28 02:00:43 +02003474 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003475
3476 return True
3477
3478 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003479 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003480 return False
3481
garciadeblas5697b8b2021-03-24 09:17:02 +01003482 async def _install_kdu(
3483 self,
3484 nsr_id: str,
3485 nsr_db_path: str,
3486 vnfr_data: dict,
3487 kdu_index: int,
3488 kdud: dict,
3489 vnfd: dict,
3490 k8s_instance_info: dict,
3491 k8params: dict = None,
3492 timeout: int = 600,
3493 vca_id: str = None,
3494 ):
tiernob9018152020-04-16 14:18:24 +00003495 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003496 k8sclustertype = k8s_instance_info["k8scluster-type"]
3497 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003498 db_dict_install = {
3499 "collection": "nsrs",
3500 "filter": {"_id": nsr_id},
3501 "path": nsr_db_path,
3502 }
lloretgalleg7c121132020-07-08 07:53:22 +00003503
romeromonser4554a702021-05-28 12:00:08 +02003504 if k8s_instance_info.get("kdu-deployment-name"):
3505 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3506 else:
3507 kdu_instance = self.k8scluster_map[
3508 k8sclustertype
3509 ].generate_kdu_instance_name(
3510 db_dict=db_dict_install,
3511 kdu_model=k8s_instance_info["kdu-model"],
3512 kdu_name=k8s_instance_info["kdu-name"],
3513 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003514
3515 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003516 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003517 item="nsrs",
3518 _id=nsr_id,
3519 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003520 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003521
3522 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3523 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3524 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3525 # namespace, this first verification could be removed, and the next step would be done for any kind
3526 # of KNF.
3527 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3528 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3529 if k8sclustertype in ("juju", "juju-bundle"):
3530 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3531 # that the user passed a namespace which he wants its KDU to be deployed in)
3532 if (
3533 self.db.count(
3534 table="nsrs",
3535 q_filter={
3536 "_id": nsr_id,
3537 "_admin.projects_write": k8s_instance_info["namespace"],
3538 "_admin.projects_read": k8s_instance_info["namespace"],
3539 },
3540 )
3541 > 0
3542 ):
3543 self.logger.debug(
3544 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3545 )
3546 self.update_db_2(
3547 item="nsrs",
3548 _id=nsr_id,
3549 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3550 )
3551 k8s_instance_info["namespace"] = kdu_instance
3552
David Garciad64e2742021-02-25 20:19:18 +01003553 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003554 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3555 kdu_model=k8s_instance_info["kdu-model"],
3556 atomic=True,
3557 params=k8params,
3558 db_dict=db_dict_install,
3559 timeout=timeout,
3560 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003561 namespace=k8s_instance_info["namespace"],
3562 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003563 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003564 )
lloretgalleg7c121132020-07-08 07:53:22 +00003565
3566 # Obtain services to obtain management service ip
3567 services = await self.k8scluster_map[k8sclustertype].get_services(
3568 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3569 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003570 namespace=k8s_instance_info["namespace"],
3571 )
lloretgalleg7c121132020-07-08 07:53:22 +00003572
3573 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003574 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003575 kdu_config = get_configuration(vnfd, kdud["name"])
3576 if kdu_config:
3577 target_ee_list = kdu_config.get("execution-environment-list", [])
3578 else:
3579 target_ee_list = []
3580
lloretgalleg7c121132020-07-08 07:53:22 +00003581 if services:
tierno7ecbc342020-09-21 14:05:39 +00003582 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003583 mgmt_services = [
3584 service
3585 for service in kdud.get("service", [])
3586 if service.get("mgmt-service")
3587 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003588 for mgmt_service in mgmt_services:
3589 for service in services:
3590 if service["name"].startswith(mgmt_service["name"]):
3591 # Mgmt service found, Obtain service ip
3592 ip = service.get("external_ip", service.get("cluster_ip"))
3593 if isinstance(ip, list) and len(ip) == 1:
3594 ip = ip[0]
3595
garciadeblas5697b8b2021-03-24 09:17:02 +01003596 vnfr_update_dict[
3597 "kdur.{}.ip-address".format(kdu_index)
3598 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003599
3600 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003601 service_external_cp = mgmt_service.get(
3602 "external-connection-point-ref"
3603 )
lloretgalleg7c121132020-07-08 07:53:22 +00003604 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003605 if (
3606 deep_get(vnfd, ("mgmt-interface", "cp"))
3607 == service_external_cp
3608 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003609 vnfr_update_dict["ip-address"] = ip
3610
bravof6ec62b72021-02-25 17:20:35 -03003611 if find_in_list(
3612 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003613 lambda ee: ee.get(
3614 "external-connection-point-ref", ""
3615 )
3616 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003617 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003618 vnfr_update_dict[
3619 "kdur.{}.ip-address".format(kdu_index)
3620 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003621 break
3622 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003623 self.logger.warn(
3624 "Mgmt service name: {} not found".format(
3625 mgmt_service["name"]
3626 )
3627 )
lloretgalleg7c121132020-07-08 07:53:22 +00003628
tierno7ecbc342020-09-21 14:05:39 +00003629 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3630 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003631
bravof9a256db2021-02-22 18:02:07 -03003632 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003633 if (
3634 kdu_config
3635 and kdu_config.get("initial-config-primitive")
3636 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3637 ):
3638 initial_config_primitive_list = kdu_config.get(
3639 "initial-config-primitive"
3640 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003641 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3642
3643 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003644 primitive_params_ = self._map_primitive_params(
3645 initial_config_primitive, {}, {}
3646 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003647
3648 await asyncio.wait_for(
3649 self.k8scluster_map[k8sclustertype].exec_primitive(
3650 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3651 kdu_instance=kdu_instance,
3652 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003653 params=primitive_params_,
3654 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003655 vca_id=vca_id,
3656 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003657 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003658 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003659
tiernob9018152020-04-16 14:18:24 +00003660 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003661 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003662 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003663 self.update_db_2(
3664 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3665 )
3666 self.update_db_2(
3667 "vnfrs",
3668 vnfr_data.get("_id"),
3669 {"kdur.{}.status".format(kdu_index): "ERROR"},
3670 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003671 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003672 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003673 self.logger.warning(
3674 f"An exception occurred while updating DB: {str(error)}"
3675 )
lloretgalleg7c121132020-07-08 07:53:22 +00003676 # reraise original error
3677 raise
3678
3679 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003680
garciadeblas5697b8b2021-03-24 09:17:02 +01003681 async def deploy_kdus(
3682 self,
3683 logging_text,
3684 nsr_id,
3685 nslcmop_id,
3686 db_vnfrs,
3687 db_vnfds,
3688 task_instantiation_info,
3689 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003690 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003691
garciadeblas5697b8b2021-03-24 09:17:02 +01003692 k8scluster_id_2_uuic = {
3693 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003694 "juju-bundle": {},
3695 }
tierno626e0152019-11-29 14:16:16 +00003696
tierno16f4a4e2020-07-20 09:05:51 +00003697 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003698 nonlocal k8scluster_id_2_uuic
3699 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3700 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3701
tierno16f4a4e2020-07-20 09:05:51 +00003702 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003703 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3704 "k8scluster", cluster_id
3705 )
tierno16f4a4e2020-07-20 09:05:51 +00003706 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003707 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3708 task_name, cluster_id
3709 )
tierno16f4a4e2020-07-20 09:05:51 +00003710 self.logger.debug(logging_text + text)
3711 await asyncio.wait(task_dependency, timeout=3600)
3712
garciadeblas5697b8b2021-03-24 09:17:02 +01003713 db_k8scluster = self.db.get_one(
3714 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3715 )
tierno626e0152019-11-29 14:16:16 +00003716 if not db_k8scluster:
3717 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003718
tierno626e0152019-11-29 14:16:16 +00003719 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3720 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003721 if cluster_type == "helm-chart-v3":
3722 try:
3723 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003724 k8s_credentials = yaml.safe_dump(
3725 db_k8scluster.get("credentials")
3726 )
3727 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3728 k8s_credentials, reuse_cluster_uuid=cluster_id
3729 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003730 db_k8scluster_update = {}
3731 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3732 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003733 db_k8scluster_update[
3734 "_admin.helm-chart-v3.created"
3735 ] = uninstall_sw
3736 db_k8scluster_update[
3737 "_admin.helm-chart-v3.operationalState"
3738 ] = "ENABLED"
3739 self.update_db_2(
3740 "k8sclusters", cluster_id, db_k8scluster_update
3741 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003742 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003743 self.logger.error(
3744 logging_text
3745 + "error initializing helm-v3 cluster: {}".format(str(e))
3746 )
3747 raise LcmException(
3748 "K8s cluster '{}' has not been initialized for '{}'".format(
3749 cluster_id, cluster_type
3750 )
3751 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003752 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003753 raise LcmException(
3754 "K8s cluster '{}' has not been initialized for '{}'".format(
3755 cluster_id, cluster_type
3756 )
3757 )
tierno626e0152019-11-29 14:16:16 +00003758 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3759 return k8s_id
3760
3761 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003762 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003763 try:
tierno626e0152019-11-29 14:16:16 +00003764 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003765 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003766
tierno626e0152019-11-29 14:16:16 +00003767 index = 0
tiernoe876f672020-02-13 14:34:48 +00003768 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003769 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003770
tierno626e0152019-11-29 14:16:16 +00003771 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003772 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003773 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3774 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003775 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003776 vnfd_id = vnfr_data.get("vnfd-id")
3777 vnfd_with_id = find_in_list(
3778 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3779 )
3780 kdud = next(
3781 kdud
3782 for kdud in vnfd_with_id["kdu"]
3783 if kdud["name"] == kdur["kdu-name"]
3784 )
tiernode1584f2020-04-07 09:07:33 +00003785 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003786 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003787 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003788 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003789 # Default version: helm3, if helm-version is v2 assign v2
3790 k8sclustertype = "helm-chart-v3"
3791 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003792 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003793 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003794 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003795 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003796 raise LcmException(
3797 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3798 "juju-bundle. Maybe an old NBI version is running".format(
3799 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3800 )
3801 )
quilesjacde94f2020-01-23 10:07:08 +00003802 # check if kdumodel is a file and exists
3803 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003804 vnfd_with_id = find_in_list(
3805 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3806 )
3807 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003808 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003809 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003810 if storage["pkg-dir"]:
3811 filename = "{}/{}/{}s/{}".format(
3812 storage["folder"],
3813 storage["pkg-dir"],
3814 k8sclustertype,
3815 kdumodel,
3816 )
3817 else:
3818 filename = "{}/Scripts/{}s/{}".format(
3819 storage["folder"],
3820 k8sclustertype,
3821 kdumodel,
3822 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003823 if self.fs.file_exists(
3824 filename, mode="file"
3825 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003826 kdumodel = self.fs.path + filename
3827 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003828 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003829 except Exception as e: # it is not a file
3830 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003831
tiernoe876f672020-02-13 14:34:48 +00003832 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003833 step = "Synchronize repos for k8s cluster '{}'".format(
3834 k8s_cluster_id
3835 )
tierno16f4a4e2020-07-20 09:05:51 +00003836 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003837
lloretgalleg7c121132020-07-08 07:53:22 +00003838 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003839 if (
3840 k8sclustertype == "helm-chart"
3841 and cluster_uuid not in updated_cluster_list
3842 ) or (
3843 k8sclustertype == "helm-chart-v3"
3844 and cluster_uuid not in updated_v3_cluster_list
3845 ):
tiernoe876f672020-02-13 14:34:48 +00003846 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003847 self.k8scluster_map[k8sclustertype].synchronize_repos(
3848 cluster_uuid=cluster_uuid
3849 )
3850 )
tiernoe876f672020-02-13 14:34:48 +00003851 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003852 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003853 unset = {
3854 "_admin.helm_charts_added." + item: None
3855 for item in del_repo_list
3856 }
3857 updated = {
3858 "_admin.helm_charts_added." + item: name
3859 for item, name in added_repo_dict.items()
3860 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003861 updated_cluster_list.append(cluster_uuid)
3862 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003863 unset = {
3864 "_admin.helm_charts_v3_added." + item: None
3865 for item in del_repo_list
3866 }
3867 updated = {
3868 "_admin.helm_charts_v3_added." + item: name
3869 for item, name in added_repo_dict.items()
3870 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003871 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003872 self.logger.debug(
3873 logging_text + "repos synchronized on k8s cluster "
3874 "'{}' to_delete: {}, to_add: {}".format(
3875 k8s_cluster_id, del_repo_list, added_repo_dict
3876 )
3877 )
3878 self.db.set_one(
3879 "k8sclusters",
3880 {"_id": k8s_cluster_id},
3881 updated,
3882 unset=unset,
3883 )
lloretgallegedc5f332020-02-20 11:50:50 +01003884
lloretgalleg7c121132020-07-08 07:53:22 +00003885 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003886 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3887 vnfr_data["member-vnf-index-ref"],
3888 kdur["kdu-name"],
3889 k8s_cluster_id,
3890 )
3891 k8s_instance_info = {
3892 "kdu-instance": None,
3893 "k8scluster-uuid": cluster_uuid,
3894 "k8scluster-type": k8sclustertype,
3895 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3896 "kdu-name": kdur["kdu-name"],
3897 "kdu-model": kdumodel,
3898 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003899 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003900 }
tiernob9018152020-04-16 14:18:24 +00003901 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003902 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003903 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003904 vnfd_with_id = find_in_list(
3905 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3906 )
tiernoa2143262020-03-27 16:20:40 +00003907 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003908 self._install_kdu(
3909 nsr_id,
3910 db_path,
3911 vnfr_data,
3912 kdu_index,
3913 kdud,
3914 vnfd_with_id,
3915 k8s_instance_info,
3916 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003917 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003918 vca_id=vca_id,
3919 )
3920 )
3921 self.lcm_tasks.register(
3922 "ns",
3923 nsr_id,
3924 nslcmop_id,
3925 "instantiate_KDU-{}".format(index),
3926 task,
3927 )
3928 task_instantiation_info[task] = "Deploying KDU {}".format(
3929 kdur["kdu-name"]
3930 )
tiernoe876f672020-02-13 14:34:48 +00003931
tierno626e0152019-11-29 14:16:16 +00003932 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003933
tiernoe876f672020-02-13 14:34:48 +00003934 except (LcmException, asyncio.CancelledError):
3935 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003936 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003937 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3938 if isinstance(e, (N2VCException, DbException)):
3939 self.logger.error(logging_text + msg)
3940 else:
3941 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003942 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003943 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003944 if db_nsr_update:
3945 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003946
garciadeblas5697b8b2021-03-24 09:17:02 +01003947 def _deploy_n2vc(
3948 self,
3949 logging_text,
3950 db_nsr,
3951 db_vnfr,
3952 nslcmop_id,
3953 nsr_id,
3954 nsi_id,
3955 vnfd_id,
3956 vdu_id,
3957 kdu_name,
3958 member_vnf_index,
3959 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003960 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01003961 vdu_name,
3962 deploy_params,
3963 descriptor_config,
3964 base_folder,
3965 task_instantiation_info,
3966 stage,
3967 ):
quilesj7e13aeb2019-10-08 13:34:55 +02003968 # launch instantiate_N2VC in a asyncio task and register task object
3969 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
3970 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02003971 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00003972
garciadeblas5697b8b2021-03-24 09:17:02 +01003973 self.logger.debug(
3974 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
3975 )
aticig9bc63ac2022-07-27 09:32:06 +03003976
3977 charm_name = ""
3978 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03003979 if "execution-environment-list" in descriptor_config:
3980 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02003981 elif "juju" in descriptor_config:
3982 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03003983 if "execution-environment-list" not in descriptor_config:
3984 # charm name is only required for ns charms
3985 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00003986 else: # other types as script are not supported
3987 ee_list = []
3988
3989 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003990 self.logger.debug(
3991 logging_text
3992 + "_deploy_n2vc ee_item juju={}, helm={}".format(
3993 ee_item.get("juju"), ee_item.get("helm-chart")
3994 )
3995 )
tiernoa278b842020-07-08 15:33:55 +00003996 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05003997 vca_name, charm_name, vca_type = self.get_vca_info(
3998 ee_item, db_nsr, get_charm_name
3999 )
4000 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004001 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004002 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004003 )
quilesj7e13aeb2019-10-08 13:34:55 +02004004 continue
quilesj3655ae02019-12-12 16:08:35 +00004005
tierno588547c2020-07-01 15:30:20 +00004006 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004007 for vca_index, vca_deployed in enumerate(
4008 db_nsr["_admin"]["deployed"]["VCA"]
4009 ):
tierno588547c2020-07-01 15:30:20 +00004010 if not vca_deployed:
4011 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004012 if (
4013 vca_deployed.get("member-vnf-index") == member_vnf_index
4014 and vca_deployed.get("vdu_id") == vdu_id
4015 and vca_deployed.get("kdu_name") == kdu_name
4016 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4017 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4018 ):
tierno588547c2020-07-01 15:30:20 +00004019 break
4020 else:
4021 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004022 target = (
4023 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4024 )
tiernoa278b842020-07-08 15:33:55 +00004025 if vdu_id:
4026 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4027 elif kdu_name:
4028 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004029 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004030 "target_element": target,
4031 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004032 "member-vnf-index": member_vnf_index,
4033 "vdu_id": vdu_id,
4034 "kdu_name": kdu_name,
4035 "vdu_count_index": vdu_index,
4036 "operational-status": "init", # TODO revise
4037 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004038 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004039 "vnfd_id": vnfd_id,
4040 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004041 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004042 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004043 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004044 }
4045 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004046
tierno588547c2020-07-01 15:30:20 +00004047 # create VCA and configurationStatus in db
4048 db_dict = {
4049 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004050 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004051 }
4052 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004053
tierno588547c2020-07-01 15:30:20 +00004054 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4055
bravof922c4172020-11-24 21:21:43 -03004056 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4057 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4058 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4059
tierno588547c2020-07-01 15:30:20 +00004060 # Launch task
4061 task_n2vc = asyncio.ensure_future(
4062 self.instantiate_N2VC(
4063 logging_text=logging_text,
4064 vca_index=vca_index,
4065 nsi_id=nsi_id,
4066 db_nsr=db_nsr,
4067 db_vnfr=db_vnfr,
4068 vdu_id=vdu_id,
4069 kdu_name=kdu_name,
4070 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004071 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004072 deploy_params=deploy_params,
4073 config_descriptor=descriptor_config,
4074 base_folder=base_folder,
4075 nslcmop_id=nslcmop_id,
4076 stage=stage,
4077 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004078 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004079 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004080 )
quilesj7e13aeb2019-10-08 13:34:55 +02004081 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004082 self.lcm_tasks.register(
4083 "ns",
4084 nsr_id,
4085 nslcmop_id,
4086 "instantiate_N2VC-{}".format(vca_index),
4087 task_n2vc,
4088 )
4089 task_instantiation_info[
4090 task_n2vc
4091 ] = self.task_name_deploy_vca + " {}.{}".format(
4092 member_vnf_index or "", vdu_id or ""
4093 )
tiernobaa51102018-12-14 13:16:18 +00004094
calvinosanch9f9c6f22019-11-04 13:37:39 +01004095 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004096 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004097 for key, value in params.items():
4098 if str(value).startswith("!!yaml "):
4099 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004100 return params
4101
kuuse8b998e42019-07-30 15:22:16 +02004102 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004103 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004104 primitive_params = {}
4105 params = {
4106 "member_vnf_index": vnf_index,
4107 "primitive": primitive,
4108 "primitive_params": primitive_params,
4109 }
4110 desc_params = {}
4111 return self._map_primitive_params(seq, params, desc_params)
4112
kuuseac3a8882019-10-03 10:48:06 +02004113 # sub-operations
4114
tierno51183952020-04-03 15:48:18 +00004115 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004116 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4117 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004118 # b. Skip sub-operation
4119 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4120 return self.SUBOPERATION_STATUS_SKIP
4121 else:
tierno7c4e24c2020-05-13 08:41:35 +00004122 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004123 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004124 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004125 operationState = "PROCESSING"
4126 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004127 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004128 db_nslcmop, op_index, operationState, detailed_status
4129 )
kuuseac3a8882019-10-03 10:48:06 +02004130 # Return the sub-operation index
4131 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4132 # with arguments extracted from the sub-operation
4133 return op_index
4134
4135 # Find a sub-operation where all keys in a matching dictionary must match
4136 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4137 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004138 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004139 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004140 for i, op in enumerate(op_list):
4141 if all(op.get(k) == match[k] for k in match):
4142 return i
4143 return self.SUBOPERATION_STATUS_NOT_FOUND
4144
4145 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004146 def _update_suboperation_status(
4147 self, db_nslcmop, op_index, operationState, detailed_status
4148 ):
kuuseac3a8882019-10-03 10:48:06 +02004149 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004150 q_filter = {"_id": db_nslcmop["_id"]}
4151 update_dict = {
4152 "_admin.operations.{}.operationState".format(op_index): operationState,
4153 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4154 }
4155 self.db.set_one(
4156 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4157 )
kuuseac3a8882019-10-03 10:48:06 +02004158
4159 # Add sub-operation, return the index of the added sub-operation
4160 # Optionally, set operationState, detailed-status, and operationType
4161 # Status and type are currently set for 'scale' sub-operations:
4162 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4163 # 'detailed-status' : status message
4164 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4165 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004166 def _add_suboperation(
4167 self,
4168 db_nslcmop,
4169 vnf_index,
4170 vdu_id,
4171 vdu_count_index,
4172 vdu_name,
4173 primitive,
4174 mapped_primitive_params,
4175 operationState=None,
4176 detailed_status=None,
4177 operationType=None,
4178 RO_nsr_id=None,
4179 RO_scaling_info=None,
4180 ):
tiernoe876f672020-02-13 14:34:48 +00004181 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004182 return self.SUBOPERATION_STATUS_NOT_FOUND
4183 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004184 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4185 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004186 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004187 new_op = {
4188 "member_vnf_index": vnf_index,
4189 "vdu_id": vdu_id,
4190 "vdu_count_index": vdu_count_index,
4191 "primitive": primitive,
4192 "primitive_params": mapped_primitive_params,
4193 }
kuuseac3a8882019-10-03 10:48:06 +02004194 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004195 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004196 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004197 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004198 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004199 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004200 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004201 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004202 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004203 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004204 if not op_list:
4205 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004206 db_nslcmop_admin.update({"operations": [new_op]})
4207 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004208 else:
4209 # Existing operations, append operation to list
4210 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004211
garciadeblas5697b8b2021-03-24 09:17:02 +01004212 db_nslcmop_update = {"_admin.operations": op_list}
4213 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004214 op_index = len(op_list) - 1
4215 return op_index
4216
4217 # Helper methods for scale() sub-operations
4218
4219 # pre-scale/post-scale:
4220 # Check for 3 different cases:
4221 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4222 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004223 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004224 def _check_or_add_scale_suboperation(
4225 self,
4226 db_nslcmop,
4227 vnf_index,
4228 vnf_config_primitive,
4229 primitive_params,
4230 operationType,
4231 RO_nsr_id=None,
4232 RO_scaling_info=None,
4233 ):
kuuseac3a8882019-10-03 10:48:06 +02004234 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004235 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004236 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004237 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004238 "member_vnf_index": vnf_index,
4239 "RO_nsr_id": RO_nsr_id,
4240 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004241 }
4242 else:
4243 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004244 "member_vnf_index": vnf_index,
4245 "primitive": vnf_config_primitive,
4246 "primitive_params": primitive_params,
4247 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004248 }
4249 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004250 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004251 # a. New sub-operation
4252 # The sub-operation does not exist, add it.
4253 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4254 # The following parameters are set to None for all kind of scaling:
4255 vdu_id = None
4256 vdu_count_index = None
4257 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004258 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004259 vnf_config_primitive = None
4260 primitive_params = None
4261 else:
4262 RO_nsr_id = None
4263 RO_scaling_info = None
4264 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004265 operationState = "PROCESSING"
4266 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004267 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004268 self._add_suboperation(
4269 db_nslcmop,
4270 vnf_index,
4271 vdu_id,
4272 vdu_count_index,
4273 vdu_name,
4274 vnf_config_primitive,
4275 primitive_params,
4276 operationState,
4277 detailed_status,
4278 operationType,
4279 RO_nsr_id,
4280 RO_scaling_info,
4281 )
kuuseac3a8882019-10-03 10:48:06 +02004282 return self.SUBOPERATION_STATUS_NEW
4283 else:
4284 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4285 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004286 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004287
preethika.pdf7d8e02019-12-10 13:10:48 +00004288 # Function to return execution_environment id
4289
David Garciac1fe90a2021-03-31 19:12:02 +02004290 async def destroy_N2VC(
4291 self,
4292 logging_text,
4293 db_nslcmop,
4294 vca_deployed,
4295 config_descriptor,
4296 vca_index,
4297 destroy_ee=True,
4298 exec_primitives=True,
4299 scaling_in=False,
4300 vca_id: str = None,
4301 ):
tiernoe876f672020-02-13 14:34:48 +00004302 """
4303 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4304 :param logging_text:
4305 :param db_nslcmop:
4306 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4307 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4308 :param vca_index: index in the database _admin.deployed.VCA
4309 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004310 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4311 not executed properly
aktas13251562021-02-12 22:19:10 +03004312 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004313 :return: None or exception
4314 """
tiernoe876f672020-02-13 14:34:48 +00004315
tierno588547c2020-07-01 15:30:20 +00004316 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004317 logging_text
4318 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004319 vca_index, vca_deployed, config_descriptor, destroy_ee
4320 )
4321 )
4322
4323 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4324
4325 # execute terminate_primitives
4326 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004327 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004328 config_descriptor.get("terminate-config-primitive"),
4329 vca_deployed.get("ee_descriptor_id"),
4330 )
tierno588547c2020-07-01 15:30:20 +00004331 vdu_id = vca_deployed.get("vdu_id")
4332 vdu_count_index = vca_deployed.get("vdu_count_index")
4333 vdu_name = vca_deployed.get("vdu_name")
4334 vnf_index = vca_deployed.get("member-vnf-index")
4335 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004336 for seq in terminate_primitives:
4337 # For each sequence in list, get primitive and call _ns_execute_primitive()
4338 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004339 vnf_index, seq.get("name")
4340 )
tierno588547c2020-07-01 15:30:20 +00004341 self.logger.debug(logging_text + step)
4342 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004343 primitive = seq.get("name")
4344 mapped_primitive_params = self._get_terminate_primitive_params(
4345 seq, vnf_index
4346 )
tierno588547c2020-07-01 15:30:20 +00004347
4348 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004349 self._add_suboperation(
4350 db_nslcmop,
4351 vnf_index,
4352 vdu_id,
4353 vdu_count_index,
4354 vdu_name,
4355 primitive,
4356 mapped_primitive_params,
4357 )
tierno588547c2020-07-01 15:30:20 +00004358 # Sub-operations: Call _ns_execute_primitive() instead of action()
4359 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004360 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004361 vca_deployed["ee_id"],
4362 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004363 mapped_primitive_params,
4364 vca_type=vca_type,
4365 vca_id=vca_id,
4366 )
tierno588547c2020-07-01 15:30:20 +00004367 except LcmException:
4368 # this happens when VCA is not deployed. In this case it is not needed to terminate
4369 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004370 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004371 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004372 raise LcmException(
4373 "terminate_primitive {} for vnf_member_index={} fails with "
4374 "error {}".format(seq.get("name"), vnf_index, result_detail)
4375 )
tierno588547c2020-07-01 15:30:20 +00004376 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004377 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4378 vca_index
4379 )
4380 self.update_db_2(
4381 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4382 )
tiernoe876f672020-02-13 14:34:48 +00004383
bravof73bac502021-05-11 07:38:47 -04004384 # Delete Prometheus Jobs if any
4385 # This uses NSR_ID, so it will destroy any jobs under this index
4386 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004387
tiernoe876f672020-02-13 14:34:48 +00004388 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004389 await self.vca_map[vca_type].delete_execution_environment(
4390 vca_deployed["ee_id"],
4391 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004392 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004393 vca_id=vca_id,
4394 )
kuuse0ca67472019-05-13 15:59:27 +02004395
David Garciac1fe90a2021-03-31 19:12:02 +02004396 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004397 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004398 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004399 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004400 await self.n2vc.delete_namespace(
4401 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004402 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004403 vca_id=vca_id,
4404 )
tiernof59ad6c2020-04-08 12:50:52 +00004405 except N2VCNotFound: # already deleted. Skip
4406 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004407 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004408
tiernoe876f672020-02-13 14:34:48 +00004409 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004410 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004411 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004412 if not task_is_locked_by_me:
4413 return
4414
tierno59d22d22018-09-25 18:10:19 +02004415 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4416 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004417 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004418 db_nsr = None
4419 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004420 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004421 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004422 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004423 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004424 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004425 tasks_dict_info = {}
4426 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004427 stage = [
4428 "Stage 1/3: Preparing task.",
4429 "Waiting for previous operations to terminate.",
4430 "",
4431 ]
tiernoe876f672020-02-13 14:34:48 +00004432 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004433 try:
kuused124bfe2019-06-18 12:09:24 +02004434 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004435 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004436
tiernoe876f672020-02-13 14:34:48 +00004437 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4438 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4439 operation_params = db_nslcmop.get("operationParams") or {}
4440 if operation_params.get("timeout_ns_terminate"):
4441 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4442 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4443 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4444
4445 db_nsr_update["operational-status"] = "terminating"
4446 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004447 self._write_ns_status(
4448 nsr_id=nsr_id,
4449 ns_state="TERMINATING",
4450 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004451 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004452 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004453 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004454 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004455 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004456 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4457 return
tierno59d22d22018-09-25 18:10:19 +02004458
tiernoe876f672020-02-13 14:34:48 +00004459 stage[1] = "Getting vnf descriptors from db."
4460 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004461 db_vnfrs_dict = {
4462 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4463 }
tiernoe876f672020-02-13 14:34:48 +00004464 db_vnfds_from_id = {}
4465 db_vnfds_from_member_index = {}
4466 # Loop over VNFRs
4467 for vnfr in db_vnfrs_list:
4468 vnfd_id = vnfr["vnfd-id"]
4469 if vnfd_id not in db_vnfds_from_id:
4470 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4471 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004472 db_vnfds_from_member_index[
4473 vnfr["member-vnf-index-ref"]
4474 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004475
tiernoe876f672020-02-13 14:34:48 +00004476 # Destroy individual execution environments when there are terminating primitives.
4477 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004478 # TODO - check before calling _destroy_N2VC
4479 # if not operation_params.get("skip_terminate_primitives"):#
4480 # or not vca.get("needed_terminate"):
4481 stage[0] = "Stage 2/3 execute terminating primitives."
4482 self.logger.debug(logging_text + stage[0])
4483 stage[1] = "Looking execution environment that needs terminate."
4484 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004485
tierno588547c2020-07-01 15:30:20 +00004486 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004487 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004488 vca_member_vnf_index = vca.get("member-vnf-index")
4489 vca_id = self.get_vca_id(
4490 db_vnfrs_dict.get(vca_member_vnf_index)
4491 if vca_member_vnf_index
4492 else None,
4493 db_nsr,
4494 )
tierno588547c2020-07-01 15:30:20 +00004495 if not vca or not vca.get("ee_id"):
4496 continue
4497 if not vca.get("member-vnf-index"):
4498 # ns
4499 config_descriptor = db_nsr.get("ns-configuration")
4500 elif vca.get("vdu_id"):
4501 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004502 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004503 elif vca.get("kdu_name"):
4504 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004505 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004506 else:
bravofe5a31bc2021-02-17 19:09:12 -03004507 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004508 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004509 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004510 exec_terminate_primitives = not operation_params.get(
4511 "skip_terminate_primitives"
4512 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004513 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4514 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004515 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004516 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4517 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004518 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004519 self.destroy_N2VC(
4520 logging_text,
4521 db_nslcmop,
4522 vca,
4523 config_descriptor,
4524 vca_index,
4525 destroy_ee,
4526 exec_terminate_primitives,
4527 vca_id=vca_id,
4528 )
4529 )
tierno588547c2020-07-01 15:30:20 +00004530 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004531
tierno588547c2020-07-01 15:30:20 +00004532 # wait for pending tasks of terminate primitives
4533 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004534 self.logger.debug(
4535 logging_text
4536 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4537 )
4538 error_list = await self._wait_for_tasks(
4539 logging_text,
4540 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004541 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004542 stage,
4543 nslcmop_id,
4544 )
tierno86e33612020-09-16 14:13:06 +00004545 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004546 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004547 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004548
tiernoe876f672020-02-13 14:34:48 +00004549 # remove All execution environments at once
4550 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004551
tierno49676be2020-04-07 16:34:35 +00004552 if nsr_deployed.get("VCA"):
4553 stage[1] = "Deleting all execution environments."
4554 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004555 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4556 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004557 # Delete Namespace and Certificates
4558 await self.vca_map["helm-v3"].delete_tls_certificate(
4559 namespace=db_nslcmop["nsInstanceId"],
4560 certificate_name=self.EE_TLS_NAME,
4561 )
4562 await self.vca_map["helm-v3"].delete_namespace(
4563 namespace=db_nslcmop["nsInstanceId"],
4564 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004565 else:
4566 vca_id = self.get_vca_id({}, db_nsr)
4567 task_delete_ee = asyncio.ensure_future(
4568 asyncio.wait_for(
4569 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4570 timeout=self.timeout.charm_delete,
4571 )
4572 )
4573 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004574
tiernoe876f672020-02-13 14:34:48 +00004575 # Delete from k8scluster
4576 stage[1] = "Deleting KDUs."
4577 self.logger.debug(logging_text + stage[1])
4578 # print(nsr_deployed)
4579 for kdu in get_iterable(nsr_deployed, "K8s"):
4580 if not kdu or not kdu.get("kdu-instance"):
4581 continue
4582 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004583 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004584 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4585 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004586 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004587 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4588 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004589 kdu_instance=kdu_instance,
4590 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004591 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004592 )
4593 )
tiernoe876f672020-02-13 14:34:48 +00004594 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004595 self.logger.error(
4596 logging_text
4597 + "Unknown k8s deployment type {}".format(
4598 kdu.get("k8scluster-type")
4599 )
4600 )
tiernoe876f672020-02-13 14:34:48 +00004601 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004602 tasks_dict_info[
4603 task_delete_kdu_instance
4604 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004605
4606 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004607 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004608 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004609 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004610 self._terminate_ng_ro(
4611 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4612 )
4613 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004614 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004615
tiernoe876f672020-02-13 14:34:48 +00004616 # rest of staff will be done at finally
4617
garciadeblas5697b8b2021-03-24 09:17:02 +01004618 except (
4619 ROclient.ROClientException,
4620 DbException,
4621 LcmException,
4622 N2VCException,
4623 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004624 self.logger.error(logging_text + "Exit Exception {}".format(e))
4625 exc = e
4626 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004627 self.logger.error(
4628 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4629 )
tiernoe876f672020-02-13 14:34:48 +00004630 exc = "Operation was cancelled"
4631 except Exception as e:
4632 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004633 self.logger.critical(
4634 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4635 exc_info=True,
4636 )
tiernoe876f672020-02-13 14:34:48 +00004637 finally:
4638 if exc:
4639 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004640 try:
tiernoe876f672020-02-13 14:34:48 +00004641 # wait for pending tasks
4642 if tasks_dict_info:
4643 stage[1] = "Waiting for terminate pending tasks."
4644 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004645 error_list += await self._wait_for_tasks(
4646 logging_text,
4647 tasks_dict_info,
4648 timeout_ns_terminate,
4649 stage,
4650 nslcmop_id,
4651 )
tiernoe876f672020-02-13 14:34:48 +00004652 stage[1] = stage[2] = ""
4653 except asyncio.CancelledError:
4654 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004655 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4656 await self._wait_for_tasks(
4657 logging_text,
4658 tasks_dict_info,
4659 timeout_ns_terminate,
4660 stage,
4661 nslcmop_id,
4662 )
tiernoe876f672020-02-13 14:34:48 +00004663 except Exception as exc:
4664 error_list.append(str(exc))
4665 # update status at database
4666 if error_list:
4667 error_detail = "; ".join(error_list)
4668 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004669 error_description_nslcmop = "{} Detail: {}".format(
4670 stage[0], error_detail
4671 )
4672 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4673 nslcmop_id, stage[0]
4674 )
tierno59d22d22018-09-25 18:10:19 +02004675
tierno59d22d22018-09-25 18:10:19 +02004676 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004677 db_nsr_update["detailed-status"] = (
4678 error_description_nsr + " Detail: " + error_detail
4679 )
tiernoe876f672020-02-13 14:34:48 +00004680 db_nslcmop_update["detailed-status"] = error_detail
4681 nslcmop_operation_state = "FAILED"
4682 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004683 else:
tiernoa2143262020-03-27 16:20:40 +00004684 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004685 error_description_nsr = error_description_nslcmop = None
4686 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004687 db_nsr_update["operational-status"] = "terminated"
4688 db_nsr_update["detailed-status"] = "Done"
4689 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4690 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004691 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004692
tiernoe876f672020-02-13 14:34:48 +00004693 if db_nsr:
4694 self._write_ns_status(
4695 nsr_id=nsr_id,
4696 ns_state=ns_state,
4697 current_operation="IDLE",
4698 current_operation_id=None,
4699 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004700 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004701 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004702 )
tiernoa17d4f42020-04-28 09:59:23 +00004703 self._write_op_status(
4704 op_id=nslcmop_id,
4705 stage="",
4706 error_message=error_description_nslcmop,
4707 operation_state=nslcmop_operation_state,
4708 other_update=db_nslcmop_update,
4709 )
lloretgalleg6d488782020-07-22 10:13:46 +00004710 if ns_state == "NOT_INSTANTIATED":
4711 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004712 self.db.set_list(
4713 "vnfrs",
4714 {"nsr-id-ref": nsr_id},
4715 {"_admin.nsState": "NOT_INSTANTIATED"},
4716 )
lloretgalleg6d488782020-07-22 10:13:46 +00004717 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004718 self.logger.warn(
4719 logging_text
4720 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4721 nsr_id, e
4722 )
4723 )
tiernoa17d4f42020-04-28 09:59:23 +00004724 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004725 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004726 if nslcmop_operation_state:
4727 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004728 await self.msg.aiowrite(
4729 "ns",
4730 "terminated",
4731 {
4732 "nsr_id": nsr_id,
4733 "nslcmop_id": nslcmop_id,
4734 "operationState": nslcmop_operation_state,
4735 "autoremove": autoremove,
4736 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004737 )
tierno59d22d22018-09-25 18:10:19 +02004738 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004739 self.logger.error(
4740 logging_text + "kafka_write notification Exception {}".format(e)
4741 )
aguilard1ae3c562023-02-16 17:24:35 +00004742 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4743 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004744
tierno59d22d22018-09-25 18:10:19 +02004745 self.logger.debug(logging_text + "Exit")
4746 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4747
garciadeblas5697b8b2021-03-24 09:17:02 +01004748 async def _wait_for_tasks(
4749 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4750 ):
tiernoe876f672020-02-13 14:34:48 +00004751 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004752 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004753 error_list = []
4754 pending_tasks = list(created_tasks_info.keys())
4755 num_tasks = len(pending_tasks)
4756 num_done = 0
4757 stage[1] = "{}/{}.".format(num_done, num_tasks)
4758 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004759 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004760 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004761 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004762 done, pending_tasks = await asyncio.wait(
4763 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4764 )
tiernoe876f672020-02-13 14:34:48 +00004765 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004766 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004767 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004768 new_error = created_tasks_info[task] + ": Timeout"
4769 error_detail_list.append(new_error)
4770 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004771 break
4772 for task in done:
4773 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004774 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004775 else:
4776 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004777 if exc:
4778 if isinstance(exc, asyncio.TimeoutError):
4779 exc = "Timeout"
4780 new_error = created_tasks_info[task] + ": {}".format(exc)
4781 error_list.append(created_tasks_info[task])
4782 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004783 if isinstance(
4784 exc,
4785 (
4786 str,
4787 DbException,
4788 N2VCException,
4789 ROclient.ROClientException,
4790 LcmException,
4791 K8sException,
4792 NgRoException,
4793 ),
4794 ):
tierno067e04a2020-03-31 12:53:13 +00004795 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004796 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004797 exc_traceback = "".join(
4798 traceback.format_exception(None, exc, exc.__traceback__)
4799 )
4800 self.logger.error(
4801 logging_text
4802 + created_tasks_info[task]
4803 + " "
4804 + exc_traceback
4805 )
tierno067e04a2020-03-31 12:53:13 +00004806 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004807 self.logger.debug(
4808 logging_text + created_tasks_info[task] + ": Done"
4809 )
tiernoe876f672020-02-13 14:34:48 +00004810 stage[1] = "{}/{}.".format(num_done, num_tasks)
4811 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004812 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004813 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004814 self.update_db_2(
4815 "nsrs",
4816 nsr_id,
4817 {
4818 "errorDescription": "Error at: " + ", ".join(error_list),
4819 "errorDetail": ". ".join(error_detail_list),
4820 },
4821 )
tiernoe876f672020-02-13 14:34:48 +00004822 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004823 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004824
Gabriel Cubab6049d32023-10-30 13:44:49 -05004825 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4826 for task, name in created_tasks_info.items():
4827 self.logger.debug(logging_text + "Cancelling task: " + name)
4828 task.cancel()
4829
tiernoda1ff8c2020-10-22 14:12:46 +00004830 @staticmethod
4831 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004832 """
4833 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4834 The default-value is used. If it is between < > it look for a value at instantiation_params
4835 :param primitive_desc: portion of VNFD/NSD that describes primitive
4836 :param params: Params provided by user
4837 :param instantiation_params: Instantiation params provided by user
4838 :return: a dictionary with the calculated params
4839 """
4840 calculated_params = {}
4841 for parameter in primitive_desc.get("parameter", ()):
4842 param_name = parameter["name"]
4843 if param_name in params:
4844 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004845 elif "default-value" in parameter or "value" in parameter:
4846 if "value" in parameter:
4847 calculated_params[param_name] = parameter["value"]
4848 else:
4849 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004850 if (
4851 isinstance(calculated_params[param_name], str)
4852 and calculated_params[param_name].startswith("<")
4853 and calculated_params[param_name].endswith(">")
4854 ):
tierno98ad6ea2019-05-30 17:16:28 +00004855 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004856 calculated_params[param_name] = instantiation_params[
4857 calculated_params[param_name][1:-1]
4858 ]
tiernoda964822019-01-14 15:53:47 +00004859 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004860 raise LcmException(
4861 "Parameter {} needed to execute primitive {} not provided".format(
4862 calculated_params[param_name], primitive_desc["name"]
4863 )
4864 )
tiernoda964822019-01-14 15:53:47 +00004865 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004866 raise LcmException(
4867 "Parameter {} needed to execute primitive {} not provided".format(
4868 param_name, primitive_desc["name"]
4869 )
4870 )
tierno59d22d22018-09-25 18:10:19 +02004871
tiernoda964822019-01-14 15:53:47 +00004872 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004873 calculated_params[param_name] = yaml.safe_dump(
4874 calculated_params[param_name], default_flow_style=True, width=256
4875 )
4876 elif isinstance(calculated_params[param_name], str) and calculated_params[
4877 param_name
4878 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004879 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004880 if parameter.get("data-type") == "INTEGER":
4881 try:
4882 calculated_params[param_name] = int(calculated_params[param_name])
4883 except ValueError: # error converting string to int
4884 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004885 "Parameter {} of primitive {} must be integer".format(
4886 param_name, primitive_desc["name"]
4887 )
4888 )
tiernofa40e692020-10-14 14:59:36 +00004889 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004890 calculated_params[param_name] = not (
4891 (str(calculated_params[param_name])).lower() == "false"
4892 )
tiernoc3f2a822019-11-05 13:45:04 +00004893
4894 # add always ns_config_info if primitive name is config
4895 if primitive_desc["name"] == "config":
4896 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004897 calculated_params["ns_config_info"] = instantiation_params[
4898 "ns_config_info"
4899 ]
tiernoda964822019-01-14 15:53:47 +00004900 return calculated_params
4901
garciadeblas5697b8b2021-03-24 09:17:02 +01004902 def _look_for_deployed_vca(
4903 self,
4904 deployed_vca,
4905 member_vnf_index,
4906 vdu_id,
4907 vdu_count_index,
4908 kdu_name=None,
4909 ee_descriptor_id=None,
4910 ):
tiernoe876f672020-02-13 14:34:48 +00004911 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4912 for vca in deployed_vca:
4913 if not vca:
4914 continue
4915 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4916 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004917 if (
4918 vdu_count_index is not None
4919 and vdu_count_index != vca["vdu_count_index"]
4920 ):
tiernoe876f672020-02-13 14:34:48 +00004921 continue
4922 if kdu_name and kdu_name != vca["kdu_name"]:
4923 continue
tiernoa278b842020-07-08 15:33:55 +00004924 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4925 continue
tiernoe876f672020-02-13 14:34:48 +00004926 break
4927 else:
4928 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004929 raise LcmException(
4930 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4931 " is not deployed".format(
4932 member_vnf_index,
4933 vdu_id,
4934 vdu_count_index,
4935 kdu_name,
4936 ee_descriptor_id,
4937 )
4938 )
tiernoe876f672020-02-13 14:34:48 +00004939 # get ee_id
4940 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004941 vca_type = vca.get(
4942 "type", "lxc_proxy_charm"
4943 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004944 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004945 raise LcmException(
4946 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4947 "execution environment".format(
4948 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4949 )
4950 )
tierno588547c2020-07-01 15:30:20 +00004951 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004952
David Garciac1fe90a2021-03-31 19:12:02 +02004953 async def _ns_execute_primitive(
4954 self,
4955 ee_id,
4956 primitive,
4957 primitive_params,
4958 retries=0,
4959 retries_interval=30,
4960 timeout=None,
4961 vca_type=None,
4962 db_dict=None,
4963 vca_id: str = None,
4964 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00004965 try:
tierno98ad6ea2019-05-30 17:16:28 +00004966 if primitive == "config":
4967 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00004968
tierno588547c2020-07-01 15:30:20 +00004969 vca_type = vca_type or "lxc_proxy_charm"
4970
quilesj7e13aeb2019-10-08 13:34:55 +02004971 while retries >= 0:
4972 try:
tierno067e04a2020-03-31 12:53:13 +00004973 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00004974 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00004975 ee_id=ee_id,
4976 primitive_name=primitive,
4977 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00004978 progress_timeout=self.timeout.progress_primitive,
4979 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004980 db_dict=db_dict,
4981 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03004982 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004983 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00004984 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01004985 )
quilesj7e13aeb2019-10-08 13:34:55 +02004986 # execution was OK
4987 break
tierno067e04a2020-03-31 12:53:13 +00004988 except asyncio.CancelledError:
4989 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04004990 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02004991 retries -= 1
4992 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01004993 self.logger.debug(
4994 "Error executing action {} on {} -> {}".format(
4995 primitive, ee_id, e
4996 )
4997 )
quilesj7e13aeb2019-10-08 13:34:55 +02004998 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05004999 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005000 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005001 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005002 e = N2VCException(
5003 message="Timed out waiting for action to complete"
5004 )
5005 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005006
garciadeblas5697b8b2021-03-24 09:17:02 +01005007 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005008
tierno067e04a2020-03-31 12:53:13 +00005009 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005010 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005011 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005012 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005013
ksaikiranr3fde2c72021-03-15 10:39:06 +05305014 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5015 """
5016 Updating the vca_status with latest juju information in nsrs record
5017 :param: nsr_id: Id of the nsr
5018 :param: nslcmop_id: Id of the nslcmop
5019 :return: None
5020 """
5021
5022 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5023 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005024 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005025 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005026 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5027 cluster_uuid, kdu_instance, cluster_type = (
5028 k8s["k8scluster-uuid"],
5029 k8s["kdu-instance"],
5030 k8s["k8scluster-type"],
5031 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005032 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005033 cluster_uuid=cluster_uuid,
5034 kdu_instance=kdu_instance,
5035 filter={"_id": nsr_id},
5036 vca_id=vca_id,
5037 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005038 )
3697083243632024-06-07 05:44:08 +00005039 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005040 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305041 table, filter = "nsrs", {"_id": nsr_id}
5042 path = "_admin.deployed.VCA.{}.".format(vca_index)
5043 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305044
5045 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5046 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5047
tierno59d22d22018-09-25 18:10:19 +02005048 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005049 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005050 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005051 if not task_is_locked_by_me:
5052 return
5053
tierno59d22d22018-09-25 18:10:19 +02005054 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5055 self.logger.debug(logging_text + "Enter")
5056 # get all needed from database
5057 db_nsr = None
5058 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005059 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005060 db_nslcmop_update = {}
5061 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005062 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005063 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005064 step = ""
tierno59d22d22018-09-25 18:10:19 +02005065 try:
kuused124bfe2019-06-18 12:09:24 +02005066 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005067 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005068 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005069
quilesj4cda56b2019-12-05 10:02:20 +00005070 self._write_ns_status(
5071 nsr_id=nsr_id,
5072 ns_state=None,
5073 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005074 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005075 )
5076
tierno59d22d22018-09-25 18:10:19 +02005077 step = "Getting information from database"
5078 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5079 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005080 if db_nslcmop["operationParams"].get("primitive_params"):
5081 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5082 db_nslcmop["operationParams"]["primitive_params"]
5083 )
tiernoda964822019-01-14 15:53:47 +00005084
tiernoe4f7e6c2018-11-27 14:55:30 +00005085 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005086 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005087 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005088 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005089 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005090 primitive = db_nslcmop["operationParams"]["primitive"]
5091 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005092 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005093 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005094 )
tierno59d22d22018-09-25 18:10:19 +02005095
tierno1b633412019-02-25 16:48:23 +00005096 if vnf_index:
5097 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005098 db_vnfr = self.db.get_one(
5099 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5100 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005101 if db_vnfr.get("kdur"):
5102 kdur_list = []
5103 for kdur in db_vnfr["kdur"]:
5104 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005105 kdur["additionalParams"] = json.loads(
5106 kdur["additionalParams"]
5107 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005108 kdur_list.append(kdur)
5109 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005110 step = "Getting vnfd from database"
5111 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005112
5113 # Sync filesystem before running a primitive
5114 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005115 else:
tierno067e04a2020-03-31 12:53:13 +00005116 step = "Getting nsd from database"
5117 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005118
David Garciac1fe90a2021-03-31 19:12:02 +02005119 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005120 # for backward compatibility
5121 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5122 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5123 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5124 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5125
tiernoda964822019-01-14 15:53:47 +00005126 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005127 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005128 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005129 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005130 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005131 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005132 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005133 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005134 else:
tiernoa278b842020-07-08 15:33:55 +00005135 descriptor_configuration = db_nsd.get("ns-configuration")
5136
garciadeblas5697b8b2021-03-24 09:17:02 +01005137 if descriptor_configuration and descriptor_configuration.get(
5138 "config-primitive"
5139 ):
tiernoa278b842020-07-08 15:33:55 +00005140 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005141 if config_primitive["name"] == primitive:
5142 config_primitive_desc = config_primitive
5143 break
tiernoda964822019-01-14 15:53:47 +00005144
garciadeblas6bed6b32020-07-20 11:05:42 +00005145 if not config_primitive_desc:
5146 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005147 raise LcmException(
5148 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5149 primitive
5150 )
5151 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005152 primitive_name = primitive
5153 ee_descriptor_id = None
5154 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005155 primitive_name = config_primitive_desc.get(
5156 "execution-environment-primitive", primitive
5157 )
5158 ee_descriptor_id = config_primitive_desc.get(
5159 "execution-environment-ref"
5160 )
tierno1b633412019-02-25 16:48:23 +00005161
tierno1b633412019-02-25 16:48:23 +00005162 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005163 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005164 vdur = next(
5165 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5166 )
bravof922c4172020-11-24 21:21:43 -03005167 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005168 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005169 kdur = next(
5170 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5171 )
bravof922c4172020-11-24 21:21:43 -03005172 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005173 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005174 desc_params = parse_yaml_strings(
5175 db_vnfr.get("additionalParamsForVnf")
5176 )
tierno1b633412019-02-25 16:48:23 +00005177 else:
bravof922c4172020-11-24 21:21:43 -03005178 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005179 if kdu_name and get_configuration(db_vnfd, kdu_name):
5180 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005181 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005182 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005183 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005184 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005185 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005186 kdu = find_in_list(
5187 nsr_deployed["K8s"],
5188 lambda kdu: kdu_name == kdu["kdu-name"]
5189 and kdu["member-vnf-index"] == vnf_index,
5190 )
5191 kdu_action = (
5192 True
5193 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005194 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005195 else False
5196 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005197
tiernoda964822019-01-14 15:53:47 +00005198 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005199 if kdu_name and (
5200 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5201 ):
tierno067e04a2020-03-31 12:53:13 +00005202 # kdur and desc_params already set from before
5203 if primitive_params:
5204 desc_params.update(primitive_params)
5205 # TODO Check if we will need something at vnf level
5206 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005207 if (
5208 kdu_name == kdu["kdu-name"]
5209 and kdu["member-vnf-index"] == vnf_index
5210 ):
tierno067e04a2020-03-31 12:53:13 +00005211 break
5212 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005213 raise LcmException(
5214 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5215 )
quilesj7e13aeb2019-10-08 13:34:55 +02005216
tierno067e04a2020-03-31 12:53:13 +00005217 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005218 msg = "unknown k8scluster-type '{}'".format(
5219 kdu.get("k8scluster-type")
5220 )
tierno067e04a2020-03-31 12:53:13 +00005221 raise LcmException(msg)
5222
garciadeblas5697b8b2021-03-24 09:17:02 +01005223 db_dict = {
5224 "collection": "nsrs",
5225 "filter": {"_id": nsr_id},
5226 "path": "_admin.deployed.K8s.{}".format(index),
5227 }
5228 self.logger.debug(
5229 logging_text
5230 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5231 )
tiernoa278b842020-07-08 15:33:55 +00005232 step = "Executing kdu {}".format(primitive_name)
5233 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00005234 if desc_params.get("kdu_model"):
5235 kdu_model = desc_params.get("kdu_model")
5236 del desc_params["kdu_model"]
5237 else:
5238 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005239 if kdu_model.count("/") < 2: # helm chart is not embedded
5240 parts = kdu_model.split(sep=":")
5241 if len(parts) == 2:
5242 kdu_model = parts[0]
limondd8b0a62022-10-28 10:39:16 +02005243 if desc_params.get("kdu_atomic_upgrade"):
garciadeblasfb1e25f2022-11-18 14:36:22 +01005244 atomic_upgrade = desc_params.get(
5245 "kdu_atomic_upgrade"
5246 ).lower() in ("yes", "true", "1")
limondd8b0a62022-10-28 10:39:16 +02005247 del desc_params["kdu_atomic_upgrade"]
5248 else:
5249 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005250 # Type of upgrade: reset, reuse, reset_then_reuse
5251 reset_values = False
5252 reuse_values = False
5253 reset_then_reuse_values = False
5254 # If no option is specified, default behaviour is reuse_values
5255 # Otherwise, options will be parsed and used
5256 if (
5257 ("kdu_reset_values" not in desc_params)
5258 and ("kdu_reuse_values" not in desc_params)
5259 and ("kdu_reset_then_reuse_values" not in desc_params)
5260 ):
5261 reuse_values = True
5262 else:
5263 if desc_params.get("kdu_reset_values"):
5264 reset_values = desc_params.pop(
5265 "kdu_reset_values"
5266 ).lower() in ("yes", "true", "1")
5267 if desc_params.get("kdu_reuse_values"):
5268 reuse_values = desc_params.pop(
5269 "kdu_reuse_values"
5270 ).lower() in ("yes", "true", "1")
5271 if desc_params.get("kdu_reset_then_reuse_values"):
5272 reset_then_reuse_values = desc_params.get(
5273 "kdu_reset_then_reuse_values"
5274 ).lower() in ("yes", "true", "1")
5275 # Two true options are not possible
5276 if (
5277 sum([reset_values, reuse_values, reset_then_reuse_values])
5278 >= 2
5279 ):
5280 raise LcmException(
5281 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5282 )
tierno067e04a2020-03-31 12:53:13 +00005283
5284 detailed_status = await asyncio.wait_for(
5285 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5286 cluster_uuid=kdu.get("k8scluster-uuid"),
5287 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005288 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005289 reset_values=reset_values,
5290 reuse_values=reuse_values,
5291 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005292 kdu_model=kdu_model,
5293 params=desc_params,
5294 db_dict=db_dict,
5295 timeout=timeout_ns_action,
5296 ),
5297 timeout=timeout_ns_action + 10,
5298 )
5299 self.logger.debug(
5300 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5301 )
tiernoa278b842020-07-08 15:33:55 +00005302 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005303 detailed_status = await asyncio.wait_for(
5304 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5305 cluster_uuid=kdu.get("k8scluster-uuid"),
5306 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005307 db_dict=db_dict,
5308 ),
5309 timeout=timeout_ns_action,
5310 )
tiernoa278b842020-07-08 15:33:55 +00005311 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005312 detailed_status = await asyncio.wait_for(
5313 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5314 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005315 kdu_instance=kdu.get("kdu-instance"),
5316 vca_id=vca_id,
5317 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005318 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005319 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005320 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005321 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5322 kdu["kdu-name"], nsr_id
5323 )
5324 params = self._map_primitive_params(
5325 config_primitive_desc, primitive_params, desc_params
5326 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005327
5328 detailed_status = await asyncio.wait_for(
5329 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5330 cluster_uuid=kdu.get("k8scluster-uuid"),
5331 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005332 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005333 params=params,
5334 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005335 timeout=timeout_ns_action,
5336 vca_id=vca_id,
5337 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005338 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005339 )
tierno067e04a2020-03-31 12:53:13 +00005340
5341 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005342 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005343 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005344 detailed_status = ""
5345 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005346 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005347 ee_id, vca_type = self._look_for_deployed_vca(
5348 nsr_deployed["VCA"],
5349 member_vnf_index=vnf_index,
5350 vdu_id=vdu_id,
5351 vdu_count_index=vdu_count_index,
5352 ee_descriptor_id=ee_descriptor_id,
5353 )
5354 for vca_index, vca_deployed in enumerate(
5355 db_nsr["_admin"]["deployed"]["VCA"]
5356 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305357 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005358 db_dict = {
5359 "collection": "nsrs",
5360 "filter": {"_id": nsr_id},
5361 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5362 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305363 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005364 (
5365 nslcmop_operation_state,
5366 detailed_status,
5367 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005368 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005369 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005370 primitive_params=self._map_primitive_params(
5371 config_primitive_desc, primitive_params, desc_params
5372 ),
tierno588547c2020-07-01 15:30:20 +00005373 timeout=timeout_ns_action,
5374 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005375 db_dict=db_dict,
5376 vca_id=vca_id,
5377 )
tierno067e04a2020-03-31 12:53:13 +00005378
5379 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005380 error_description_nslcmop = (
5381 detailed_status if nslcmop_operation_state == "FAILED" else ""
5382 )
5383 self.logger.debug(
5384 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005385 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005386 nslcmop_operation_state, detailed_status
5387 )
5388 )
tierno59d22d22018-09-25 18:10:19 +02005389 return # database update is called inside finally
5390
tiernof59ad6c2020-04-08 12:50:52 +00005391 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005392 self.logger.error(logging_text + "Exit Exception {}".format(e))
5393 exc = e
5394 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005395 self.logger.error(
5396 logging_text + "Cancelled Exception while '{}'".format(step)
5397 )
tierno59d22d22018-09-25 18:10:19 +02005398 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005399 except asyncio.TimeoutError:
5400 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5401 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005402 except Exception as e:
5403 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005404 self.logger.critical(
5405 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5406 exc_info=True,
5407 )
tierno59d22d22018-09-25 18:10:19 +02005408 finally:
tierno067e04a2020-03-31 12:53:13 +00005409 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005410 db_nslcmop_update[
5411 "detailed-status"
5412 ] = (
5413 detailed_status
5414 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005415 nslcmop_operation_state = "FAILED"
5416 if db_nsr:
5417 self._write_ns_status(
5418 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005419 ns_state=db_nsr[
5420 "nsState"
5421 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005422 current_operation="IDLE",
5423 current_operation_id=None,
5424 # error_description=error_description_nsr,
5425 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005426 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005427 )
5428
garciadeblas5697b8b2021-03-24 09:17:02 +01005429 self._write_op_status(
5430 op_id=nslcmop_id,
5431 stage="",
5432 error_message=error_description_nslcmop,
5433 operation_state=nslcmop_operation_state,
5434 other_update=db_nslcmop_update,
5435 )
tierno067e04a2020-03-31 12:53:13 +00005436
tierno59d22d22018-09-25 18:10:19 +02005437 if nslcmop_operation_state:
5438 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005439 await self.msg.aiowrite(
5440 "ns",
5441 "actioned",
5442 {
5443 "nsr_id": nsr_id,
5444 "nslcmop_id": nslcmop_id,
5445 "operationState": nslcmop_operation_state,
5446 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005447 )
tierno59d22d22018-09-25 18:10:19 +02005448 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005449 self.logger.error(
5450 logging_text + "kafka_write notification Exception {}".format(e)
5451 )
tierno59d22d22018-09-25 18:10:19 +02005452 self.logger.debug(logging_text + "Exit")
5453 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005454 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005455
elumalaica7ece02022-04-12 12:47:32 +05305456 async def terminate_vdus(
5457 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5458 ):
5459 """This method terminates VDUs
5460
5461 Args:
5462 db_vnfr: VNF instance record
5463 member_vnf_index: VNF index to identify the VDUs to be removed
5464 db_nsr: NS instance record
5465 update_db_nslcmops: Nslcmop update record
5466 """
5467 vca_scaling_info = []
5468 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5469 scaling_info["scaling_direction"] = "IN"
5470 scaling_info["vdu-delete"] = {}
5471 scaling_info["kdu-delete"] = {}
5472 db_vdur = db_vnfr.get("vdur")
5473 vdur_list = copy(db_vdur)
5474 count_index = 0
5475 for index, vdu in enumerate(vdur_list):
5476 vca_scaling_info.append(
5477 {
5478 "osm_vdu_id": vdu["vdu-id-ref"],
5479 "member-vnf-index": member_vnf_index,
5480 "type": "delete",
5481 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005482 }
5483 )
elumalaica7ece02022-04-12 12:47:32 +05305484 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5485 scaling_info["vdu"].append(
5486 {
5487 "name": vdu.get("name") or vdu.get("vdu-name"),
5488 "vdu_id": vdu["vdu-id-ref"],
5489 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005490 }
5491 )
elumalaica7ece02022-04-12 12:47:32 +05305492 for interface in vdu["interfaces"]:
5493 scaling_info["vdu"][index]["interface"].append(
5494 {
5495 "name": interface["name"],
5496 "ip_address": interface["ip-address"],
5497 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005498 }
5499 )
elumalaica7ece02022-04-12 12:47:32 +05305500 self.logger.info("NS update scaling info{}".format(scaling_info))
5501 stage[2] = "Terminating VDUs"
5502 if scaling_info.get("vdu-delete"):
5503 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005504 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305505 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005506 logging_text,
5507 db_nsr,
5508 update_db_nslcmops,
5509 db_vnfr,
5510 scaling_info,
5511 stage,
elumalaica7ece02022-04-12 12:47:32 +05305512 )
5513
preethika.p28b0bf82022-09-23 07:36:28 +00005514 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305515 """This method is to Remove VNF instances from NS.
5516
5517 Args:
5518 nsr_id: NS instance id
5519 nslcmop_id: nslcmop id of update
5520 vnf_instance_id: id of the VNF instance to be removed
5521
5522 Returns:
5523 result: (str, str) COMPLETED/FAILED, details
5524 """
5525 try:
5526 db_nsr_update = {}
5527 logging_text = "Task ns={} update ".format(nsr_id)
5528 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5529 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5530 if check_vnfr_count > 1:
5531 stage = ["", "", ""]
5532 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005533 self.logger.debug(
5534 step + " after having waited for previous tasks to be completed"
5535 )
elumalaica7ece02022-04-12 12:47:32 +05305536 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5537 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5538 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5539 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5540 """ db_vnfr = self.db.get_one(
5541 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5542
5543 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005544 await self.terminate_vdus(
5545 db_vnfr,
5546 member_vnf_index,
5547 db_nsr,
5548 update_db_nslcmops,
5549 stage,
5550 logging_text,
5551 )
elumalaica7ece02022-04-12 12:47:32 +05305552
5553 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5554 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005555 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5556 "constituent-vnfr-ref"
5557 )
elumalaica7ece02022-04-12 12:47:32 +05305558 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5559 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5560 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5561 return "COMPLETED", "Done"
5562 else:
5563 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005564 raise LcmException(
5565 "{} Cannot terminate the last VNF in this NS.".format(
5566 vnf_instance_id
5567 )
5568 )
elumalaica7ece02022-04-12 12:47:32 +05305569 except (LcmException, asyncio.CancelledError):
5570 raise
5571 except Exception as e:
5572 self.logger.debug("Error removing VNF {}".format(e))
5573 return "FAILED", "Error removing VNF {}".format(e)
5574
elumalaib9e357c2022-04-27 09:58:38 +05305575 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005576 self,
5577 nsr_id,
5578 nslcmop_id,
5579 db_vnfd,
5580 db_vnfr,
5581 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305582 ):
5583 """This method updates and redeploys VNF instances
5584
5585 Args:
5586 nsr_id: NS instance id
5587 nslcmop_id: nslcmop id
5588 db_vnfd: VNF descriptor
5589 db_vnfr: VNF instance record
5590 db_nsr: NS instance record
5591
5592 Returns:
5593 result: (str, str) COMPLETED/FAILED, details
5594 """
5595 try:
5596 count_index = 0
5597 stage = ["", "", ""]
5598 logging_text = "Task ns={} update ".format(nsr_id)
5599 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5600 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5601
5602 # Terminate old VNF resources
5603 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005604 await self.terminate_vdus(
5605 db_vnfr,
5606 member_vnf_index,
5607 db_nsr,
5608 update_db_nslcmops,
5609 stage,
5610 logging_text,
5611 )
elumalaib9e357c2022-04-27 09:58:38 +05305612
5613 # old_vnfd_id = db_vnfr["vnfd-id"]
5614 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5615 new_db_vnfd = db_vnfd
5616 # new_vnfd_ref = new_db_vnfd["id"]
5617 # new_vnfd_id = vnfd_id
5618
5619 # Create VDUR
5620 new_vnfr_cp = []
5621 for cp in new_db_vnfd.get("ext-cpd", ()):
5622 vnf_cp = {
5623 "name": cp.get("id"),
5624 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5625 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5626 "id": cp.get("id"),
5627 }
5628 new_vnfr_cp.append(vnf_cp)
5629 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5630 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5631 # 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 +00005632 new_vnfr_update = {
5633 "revision": latest_vnfd_revision,
5634 "connection-point": new_vnfr_cp,
5635 "vdur": new_vdur,
5636 "ip-address": "",
5637 }
elumalaib9e357c2022-04-27 09:58:38 +05305638 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5639 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005640 "vnfrs",
5641 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305642 )
5643
5644 # Instantiate new VNF resources
5645 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5646 vca_scaling_info = []
5647 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5648 scaling_info["scaling_direction"] = "OUT"
5649 scaling_info["vdu-create"] = {}
5650 scaling_info["kdu-create"] = {}
5651 vdud_instantiate_list = db_vnfd["vdu"]
5652 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005653 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305654 if cloud_init_text:
5655 additional_params = (
5656 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5657 or {}
5658 )
5659 cloud_init_list = []
5660 if cloud_init_text:
5661 # TODO Information of its own ip is not available because db_vnfr is not updated.
5662 additional_params["OSM"] = get_osm_params(
5663 updated_db_vnfr, vdud["id"], 1
5664 )
5665 cloud_init_list.append(
5666 self._parse_cloud_init(
5667 cloud_init_text,
5668 additional_params,
5669 db_vnfd["id"],
5670 vdud["id"],
5671 )
5672 )
5673 vca_scaling_info.append(
5674 {
5675 "osm_vdu_id": vdud["id"],
5676 "member-vnf-index": member_vnf_index,
5677 "type": "create",
5678 "vdu_index": count_index,
5679 }
5680 )
5681 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005682 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305683 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005684 "New Resources to be deployed: {}".format(scaling_info)
5685 )
elumalaib9e357c2022-04-27 09:58:38 +05305686 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005687 logging_text,
5688 db_nsr,
5689 update_db_nslcmops,
5690 updated_db_vnfr,
5691 scaling_info,
5692 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305693 )
5694 return "COMPLETED", "Done"
5695 except (LcmException, asyncio.CancelledError):
5696 raise
5697 except Exception as e:
5698 self.logger.debug("Error updating VNF {}".format(e))
5699 return "FAILED", "Error updating VNF {}".format(e)
5700
aticigdffa6212022-04-12 15:27:53 +03005701 async def _ns_charm_upgrade(
5702 self,
5703 ee_id,
5704 charm_id,
5705 charm_type,
5706 path,
5707 timeout: float = None,
5708 ) -> (str, str):
5709 """This method upgrade charms in VNF instances
5710
5711 Args:
5712 ee_id: Execution environment id
5713 path: Local path to the charm
5714 charm_id: charm-id
5715 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5716 timeout: (Float) Timeout for the ns update operation
5717
5718 Returns:
5719 result: (str, str) COMPLETED/FAILED, details
5720 """
5721 try:
5722 charm_type = charm_type or "lxc_proxy_charm"
5723 output = await self.vca_map[charm_type].upgrade_charm(
5724 ee_id=ee_id,
5725 path=path,
5726 charm_id=charm_id,
5727 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005728 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005729 )
5730
5731 if output:
5732 return "COMPLETED", output
5733
5734 except (LcmException, asyncio.CancelledError):
5735 raise
5736
5737 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005738 self.logger.debug("Error upgrading charm {}".format(path))
5739
5740 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5741
5742 async def update(self, nsr_id, nslcmop_id):
5743 """Update NS according to different update types
5744
5745 This method performs upgrade of VNF instances then updates the revision
5746 number in VNF record
5747
5748 Args:
5749 nsr_id: Network service will be updated
5750 nslcmop_id: ns lcm operation id
5751
5752 Returns:
5753 It may raise DbException, LcmException, N2VCException, K8sException
5754
5755 """
5756 # Try to lock HA task here
5757 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5758 if not task_is_locked_by_me:
5759 return
5760
5761 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5762 self.logger.debug(logging_text + "Enter")
5763
5764 # Set the required variables to be filled up later
5765 db_nsr = None
5766 db_nslcmop_update = {}
5767 vnfr_update = {}
5768 nslcmop_operation_state = None
5769 db_nsr_update = {}
5770 error_description_nslcmop = ""
5771 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305772 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005773 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005774 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005775
5776 try:
5777 # wait for any previous tasks in process
5778 step = "Waiting for previous operations to terminate"
5779 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5780 self._write_ns_status(
5781 nsr_id=nsr_id,
5782 ns_state=None,
5783 current_operation="UPDATING",
5784 current_operation_id=nslcmop_id,
5785 )
5786
5787 step = "Getting nslcmop from database"
5788 db_nslcmop = self.db.get_one(
5789 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5790 )
5791 update_type = db_nslcmop["operationParams"]["updateType"]
5792
5793 step = "Getting nsr from database"
5794 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5795 old_operational_status = db_nsr["operational-status"]
5796 db_nsr_update["operational-status"] = "updating"
5797 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5798 nsr_deployed = db_nsr["_admin"].get("deployed")
5799
5800 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005801 # Get the input parameters given through update request
5802 vnf_instance_id = db_nslcmop["operationParams"][
5803 "changeVnfPackageData"
5804 ].get("vnfInstanceId")
5805
5806 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5807 "vnfdId"
5808 )
5809 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5810
5811 step = "Getting vnfr from database"
5812 db_vnfr = self.db.get_one(
5813 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5814 )
5815
5816 step = "Getting vnfds from database"
5817 # Latest VNFD
5818 latest_vnfd = self.db.get_one(
5819 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5820 )
5821 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5822
5823 # Current VNFD
5824 current_vnf_revision = db_vnfr.get("revision", 1)
5825 current_vnfd = self.db.get_one(
5826 "vnfds_revisions",
5827 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5828 fail_on_empty=False,
5829 )
5830 # Charm artifact paths will be filled up later
5831 (
5832 current_charm_artifact_path,
5833 target_charm_artifact_path,
5834 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005835 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005836 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005837
5838 step = "Checking if revision has changed in VNFD"
5839 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305840 change_type = "policy_updated"
5841
aticigdffa6212022-04-12 15:27:53 +03005842 # There is new revision of VNFD, update operation is required
5843 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005844 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005845
5846 step = "Removing the VNFD packages if they exist in the local path"
5847 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5848 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5849
5850 step = "Get the VNFD packages from FSMongo"
5851 self.fs.sync(from_path=latest_vnfd_path)
5852 self.fs.sync(from_path=current_vnfd_path)
5853
5854 step = (
5855 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5856 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005857 current_base_folder = current_vnfd["_admin"]["storage"]
5858 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005859
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005860 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005861 get_iterable(nsr_deployed, "VCA")
5862 ):
5863 vnf_index = db_vnfr.get("member-vnf-index-ref")
5864
5865 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005866 if vca_deployed.get("member-vnf-index") == vnf_index:
5867 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5868 vca_type = vca_deployed.get("type")
5869 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005870
5871 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005872 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005873
5874 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005875 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005876 search_key = "kdu_name"
5877 else:
5878 search_key = "vnfd_id"
5879
5880 entity_id = vca_deployed.get(search_key)
5881
aticigdffa6212022-04-12 15:27:53 +03005882 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005883 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005884 )
5885
5886 if "execution-environment-list" in descriptor_config:
5887 ee_list = descriptor_config.get(
5888 "execution-environment-list", []
5889 )
5890 else:
5891 ee_list = []
5892
5893 # There could be several charm used in the same VNF
5894 for ee_item in ee_list:
5895 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005896 step = "Getting charm name"
5897 charm_name = ee_item["juju"].get("charm")
5898
5899 step = "Setting Charm artifact paths"
5900 current_charm_artifact_path.append(
5901 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005902 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005903 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005904 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005905 current_vnf_revision,
5906 )
5907 )
5908 target_charm_artifact_path.append(
5909 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005910 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005911 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005912 vca_type,
aticigd7083542022-05-30 20:45:55 +03005913 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005914 )
5915 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005916 elif ee_item.get("helm-chart"):
5917 # add chart to list and all parameters
5918 step = "Getting helm chart name"
5919 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00005920 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005921 step = "Setting Helm chart artifact paths"
5922
garciadeblasfb1e25f2022-11-18 14:36:22 +01005923 helm_artifacts.append(
5924 {
5925 "current_artifact_path": get_charm_artifact_path(
5926 current_base_folder,
5927 chart_name,
5928 vca_type,
5929 current_vnf_revision,
5930 ),
5931 "target_artifact_path": get_charm_artifact_path(
5932 latest_base_folder,
5933 chart_name,
5934 vca_type,
5935 latest_vnfd_revision,
5936 ),
5937 "ee_id": ee_id,
5938 "vca_index": vca_index,
5939 "vdu_index": vdu_count_index,
5940 }
5941 )
aticigdffa6212022-04-12 15:27:53 +03005942
5943 charm_artifact_paths = zip(
5944 current_charm_artifact_path, target_charm_artifact_path
5945 )
5946
5947 step = "Checking if software version has changed in VNFD"
5948 if find_software_version(current_vnfd) != find_software_version(
5949 latest_vnfd
5950 ):
aticigdffa6212022-04-12 15:27:53 +03005951 step = "Checking if existing VNF has charm"
5952 for current_charm_path, target_charm_path in list(
5953 charm_artifact_paths
5954 ):
5955 if current_charm_path:
5956 raise LcmException(
5957 "Software version change is not supported as VNF instance {} has charm.".format(
5958 vnf_instance_id
5959 )
5960 )
5961
kayal20010cd8af32024-03-13 10:23:16 +05305962 step = "Checking whether the descriptor has SFC"
5963 if db_nsr.get("nsd", {}).get("vnffgd"):
5964 raise LcmException(
5965 "Ns update is not allowed for NS with SFC"
5966 )
5967
aticigdffa6212022-04-12 15:27:53 +03005968 # There is no change in the charm package, then redeploy the VNF
5969 # based on new descriptor
5970 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05305971 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00005972 (result, detailed_status) = await self._ns_redeploy_vnf(
5973 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05305974 )
5975 if result == "FAILED":
5976 nslcmop_operation_state = result
5977 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05305978 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05305979 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05305980 db_nsr_update["detailed-status"] = detailed_status
5981 scaling_aspect = get_scaling_aspect(latest_vnfd)
5982 scaling_group_desc = db_nsr.get("_admin").get(
5983 "scaling-group", None
5984 )
5985 if scaling_group_desc:
5986 for aspect in scaling_aspect:
5987 scaling_group_id = aspect.get("id")
5988 for scale_index, scaling_group in enumerate(
5989 scaling_group_desc
5990 ):
5991 if scaling_group.get("name") == scaling_group_id:
5992 db_nsr_update[
5993 "_admin.scaling-group.{}.nb-scale-op".format(
5994 scale_index
5995 )
5996 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05305997 self.logger.debug(
5998 logging_text
5999 + " step {} Done with result {} {}".format(
6000 step, nslcmop_operation_state, detailed_status
6001 )
6002 )
aticigdffa6212022-04-12 15:27:53 +03006003
6004 else:
6005 step = "Checking if any charm package has changed or not"
6006 for current_charm_path, target_charm_path in list(
6007 charm_artifact_paths
6008 ):
6009 if (
6010 current_charm_path
6011 and target_charm_path
6012 and self.check_charm_hash_changed(
6013 current_charm_path, target_charm_path
6014 )
6015 ):
aticigdffa6212022-04-12 15:27:53 +03006016 step = "Checking whether VNF uses juju bundle"
6017 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006018 raise LcmException(
6019 "Charm upgrade is not supported for the instance which"
6020 " uses juju-bundle: {}".format(
6021 check_juju_bundle_existence(current_vnfd)
6022 )
6023 )
6024
6025 step = "Upgrading Charm"
6026 (
6027 result,
6028 detailed_status,
6029 ) = await self._ns_charm_upgrade(
6030 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006031 charm_id=vca_id,
6032 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006033 path=self.fs.path + target_charm_path,
6034 timeout=timeout_seconds,
6035 )
6036
6037 if result == "FAILED":
6038 nslcmop_operation_state = result
6039 error_description_nslcmop = detailed_status
6040
6041 db_nslcmop_update["detailed-status"] = detailed_status
6042 self.logger.debug(
6043 logging_text
6044 + " step {} Done with result {} {}".format(
6045 step, nslcmop_operation_state, detailed_status
6046 )
6047 )
6048
6049 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306050 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6051 result = "COMPLETED"
6052 detailed_status = "Done"
6053 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006054
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006055 # helm base EE
6056 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006057 if not (
6058 item["current_artifact_path"]
6059 and item["target_artifact_path"]
6060 and self.check_charm_hash_changed(
6061 item["current_artifact_path"],
6062 item["target_artifact_path"],
6063 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006064 ):
6065 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006066 db_update_entry = "_admin.deployed.VCA.{}.".format(
6067 item["vca_index"]
6068 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006069 vnfr_id = db_vnfr["_id"]
6070 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6071 db_dict = {
6072 "collection": "nsrs",
6073 "filter": {"_id": nsr_id},
6074 "path": db_update_entry,
6075 }
6076 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006077 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006078 namespace=namespace,
6079 helm_id=helm_id,
6080 db_dict=db_dict,
6081 config=osm_config,
6082 artifact_path=item["target_artifact_path"],
6083 vca_type=vca_type,
6084 )
6085 vnf_id = db_vnfr.get("vnfd-ref")
6086 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6087 self.logger.debug("get ssh key block")
6088 rw_mgmt_ip = None
6089 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006090 config_descriptor,
6091 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006092 ):
6093 # Needed to inject a ssh key
6094 user = deep_get(
6095 config_descriptor,
6096 ("config-access", "ssh-access", "default-user"),
6097 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006098 step = (
6099 "Install configuration Software, getting public ssh key"
6100 )
6101 pub_key = await self.vca_map[
6102 vca_type
6103 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006104 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6105 )
6106
garciadeblasfb1e25f2022-11-18 14:36:22 +01006107 step = (
6108 "Insert public key into VM user={} ssh_key={}".format(
6109 user, pub_key
6110 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006111 )
6112 self.logger.debug(logging_text + step)
6113
6114 # wait for RO (ip-address) Insert pub_key into VM
6115 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6116 logging_text,
6117 nsr_id,
6118 vnfr_id,
6119 None,
6120 item["vdu_index"],
6121 user=user,
6122 pub_key=pub_key,
6123 )
6124
6125 initial_config_primitive_list = config_descriptor.get(
6126 "initial-config-primitive"
6127 )
6128 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006129 (
6130 p
6131 for p in initial_config_primitive_list
6132 if p["name"] == "config"
6133 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006134 None,
6135 )
6136 if not config_primitive:
6137 continue
6138
6139 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6140 if rw_mgmt_ip:
6141 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6142 if db_vnfr.get("additionalParamsForVnf"):
6143 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006144 parse_yaml_strings(
6145 db_vnfr["additionalParamsForVnf"].copy()
6146 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006147 )
6148 primitive_params_ = self._map_primitive_params(
6149 config_primitive, {}, deploy_params
6150 )
6151
6152 step = "execute primitive '{}' params '{}'".format(
6153 config_primitive["name"], primitive_params_
6154 )
6155 self.logger.debug(logging_text + step)
6156 await self.vca_map[vca_type].exec_primitive(
6157 ee_id=ee_id,
6158 primitive_name=config_primitive["name"],
6159 params_dict=primitive_params_,
6160 db_dict=db_dict,
6161 vca_id=vca_id,
6162 vca_type=vca_type,
6163 )
6164
6165 step = "Updating policies"
6166 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6167 detailed_status = "Done"
6168 db_nslcmop_update["detailed-status"] = "Done"
6169
aticigdffa6212022-04-12 15:27:53 +03006170 # If nslcmop_operation_state is None, so any operation is not failed.
6171 if not nslcmop_operation_state:
6172 nslcmop_operation_state = "COMPLETED"
6173
6174 # If update CHANGE_VNFPKG nslcmop_operation is successful
6175 # vnf revision need to be updated
6176 vnfr_update["revision"] = latest_vnfd_revision
6177 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6178
6179 self.logger.debug(
6180 logging_text
6181 + " task Done with result {} {}".format(
6182 nslcmop_operation_state, detailed_status
6183 )
6184 )
6185 elif update_type == "REMOVE_VNF":
6186 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306187 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6188 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6189 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6190 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006191 (result, detailed_status) = await self.remove_vnf(
6192 nsr_id, nslcmop_id, vnf_instance_id
6193 )
elumalaica7ece02022-04-12 12:47:32 +05306194 if result == "FAILED":
6195 nslcmop_operation_state = result
6196 error_description_nslcmop = detailed_status
6197 db_nslcmop_update["detailed-status"] = detailed_status
6198 change_type = "vnf_terminated"
6199 if not nslcmop_operation_state:
6200 nslcmop_operation_state = "COMPLETED"
6201 self.logger.debug(
6202 logging_text
6203 + " task Done with result {} {}".format(
6204 nslcmop_operation_state, detailed_status
6205 )
6206 )
aticigdffa6212022-04-12 15:27:53 +03006207
k4.rahulb827de92022-05-02 16:35:02 +00006208 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006209 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6210 "vnfInstanceId"
6211 ]
6212 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6213 "changeStateTo"
6214 ]
6215 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6216 "additionalParam"
6217 ]
k4.rahulb827de92022-05-02 16:35:02 +00006218 (result, detailed_status) = await self.rebuild_start_stop(
6219 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006220 )
k4.rahulb827de92022-05-02 16:35:02 +00006221 if result == "FAILED":
6222 nslcmop_operation_state = result
6223 error_description_nslcmop = detailed_status
6224 db_nslcmop_update["detailed-status"] = detailed_status
6225 if not nslcmop_operation_state:
6226 nslcmop_operation_state = "COMPLETED"
6227 self.logger.debug(
6228 logging_text
6229 + " task Done with result {} {}".format(
6230 nslcmop_operation_state, detailed_status
6231 )
6232 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306233 elif update_type == "VERTICAL_SCALE":
6234 self.logger.debug(
6235 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6236 )
6237 # Get the input parameters given through update request
6238 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6239 "vnfInstanceId"
6240 )
6241
6242 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6243 "vnfdId"
6244 )
6245 step = "Getting vnfr from database"
6246 db_vnfr = self.db.get_one(
6247 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6248 )
6249 self.logger.debug(step)
6250 step = "Getting vnfds from database"
6251 self.logger.debug("Start" + step)
6252 # Latest VNFD
6253 latest_vnfd = self.db.get_one(
6254 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6255 )
6256 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6257 # Current VNFD
6258 current_vnf_revision = db_vnfr.get("revision", 1)
6259 current_vnfd = self.db.get_one(
6260 "vnfds_revisions",
6261 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6262 fail_on_empty=False,
6263 )
6264 self.logger.debug("End" + step)
6265 # verify flavor changes
6266 step = "Checking for flavor change"
6267 if find_software_version(current_vnfd) != find_software_version(
6268 latest_vnfd
6269 ):
6270 self.logger.debug("Start" + step)
6271 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6272 "virtual-compute-desc"
6273 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6274 "virtual-storage-desc"
6275 ):
6276 raise LcmException(
6277 "No change in flavor check vnfd {}".format(vnfd_id)
6278 )
6279 else:
6280 raise LcmException(
6281 "No change in software_version of vnfd {}".format(vnfd_id)
6282 )
6283
6284 self.logger.debug("End" + step)
6285
6286 (result, detailed_status) = await self.vertical_scale(
6287 nsr_id, nslcmop_id
6288 )
6289 self.logger.debug(
6290 "vertical_scale result: {} detailed_status :{}".format(
6291 result, detailed_status
6292 )
6293 )
6294 if result == "FAILED":
6295 nslcmop_operation_state = result
6296 error_description_nslcmop = detailed_status
6297 db_nslcmop_update["detailed-status"] = detailed_status
6298 if not nslcmop_operation_state:
6299 nslcmop_operation_state = "COMPLETED"
6300 self.logger.debug(
6301 logging_text
6302 + " task Done with result {} {}".format(
6303 nslcmop_operation_state, detailed_status
6304 )
6305 )
k4.rahulb827de92022-05-02 16:35:02 +00006306
aticigdffa6212022-04-12 15:27:53 +03006307 # If nslcmop_operation_state is None, so any operation is not failed.
6308 # All operations are executed in overall.
6309 if not nslcmop_operation_state:
6310 nslcmop_operation_state = "COMPLETED"
6311 db_nsr_update["operational-status"] = old_operational_status
6312
6313 except (DbException, LcmException, N2VCException, K8sException) as e:
6314 self.logger.error(logging_text + "Exit Exception {}".format(e))
6315 exc = e
6316 except asyncio.CancelledError:
6317 self.logger.error(
6318 logging_text + "Cancelled Exception while '{}'".format(step)
6319 )
6320 exc = "Operation was cancelled"
6321 except asyncio.TimeoutError:
6322 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6323 exc = "Timeout"
6324 except Exception as e:
6325 exc = traceback.format_exc()
6326 self.logger.critical(
6327 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6328 exc_info=True,
6329 )
6330 finally:
6331 if exc:
6332 db_nslcmop_update[
6333 "detailed-status"
6334 ] = (
6335 detailed_status
6336 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6337 nslcmop_operation_state = "FAILED"
6338 db_nsr_update["operational-status"] = old_operational_status
6339 if db_nsr:
6340 self._write_ns_status(
6341 nsr_id=nsr_id,
6342 ns_state=db_nsr["nsState"],
6343 current_operation="IDLE",
6344 current_operation_id=None,
6345 other_update=db_nsr_update,
6346 )
6347
6348 self._write_op_status(
6349 op_id=nslcmop_id,
6350 stage="",
6351 error_message=error_description_nslcmop,
6352 operation_state=nslcmop_operation_state,
6353 other_update=db_nslcmop_update,
6354 )
6355
6356 if nslcmop_operation_state:
6357 try:
elumalaica7ece02022-04-12 12:47:32 +05306358 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306359 "nsr_id": nsr_id,
6360 "nslcmop_id": nslcmop_id,
6361 "operationState": nslcmop_operation_state,
6362 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006363 if (
6364 change_type in ("vnf_terminated", "policy_updated")
6365 and member_vnf_index
6366 ):
elumalaica7ece02022-04-12 12:47:32 +05306367 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006368 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006369 except Exception as e:
6370 self.logger.error(
6371 logging_text + "kafka_write notification Exception {}".format(e)
6372 )
6373 self.logger.debug(logging_text + "Exit")
6374 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6375 return nslcmop_operation_state, detailed_status
6376
tierno59d22d22018-09-25 18:10:19 +02006377 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006378 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006379 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006380 if not task_is_locked_by_me:
6381 return
6382
tierno59d22d22018-09-25 18:10:19 +02006383 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006384 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006385 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006386 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006387 self.logger.debug(logging_text + "Enter")
6388 # get all needed from database
6389 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006390 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006391 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006392 exc = None
tierno9ab95942018-10-10 16:44:22 +02006393 # in case of error, indicates what part of scale was failed to put nsr at error status
6394 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006395 old_operational_status = ""
6396 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006397 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006398 prom_job_name = ""
tierno59d22d22018-09-25 18:10:19 +02006399 try:
kuused124bfe2019-06-18 12:09:24 +02006400 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006401 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006402 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6403 self._write_ns_status(
6404 nsr_id=nsr_id,
6405 ns_state=None,
6406 current_operation="SCALING",
6407 current_operation_id=nslcmop_id,
6408 )
quilesj4cda56b2019-12-05 10:02:20 +00006409
ikalyvas02d9e7b2019-05-27 18:16:01 +03006410 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006411 self.logger.debug(
6412 step + " after having waited for previous tasks to be completed"
6413 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006414 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006415
ikalyvas02d9e7b2019-05-27 18:16:01 +03006416 step = "Getting nsr from database"
6417 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006418 old_operational_status = db_nsr["operational-status"]
6419 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006420
kayal20010cd8af32024-03-13 10:23:16 +05306421 step = "Checking whether the descriptor has SFC"
6422 if db_nsr.get("nsd", {}).get("vnffgd"):
6423 raise LcmException("Scaling is not allowed for NS with SFC")
6424
tierno59d22d22018-09-25 18:10:19 +02006425 step = "Parsing scaling parameters"
6426 db_nsr_update["operational-status"] = "scaling"
6427 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006428 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006429
garciadeblas5697b8b2021-03-24 09:17:02 +01006430 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6431 "scaleByStepData"
6432 ]["member-vnf-index"]
6433 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6434 "scaleByStepData"
6435 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006436 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006437 # for backward compatibility
6438 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6439 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6440 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6441 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6442
tierno59d22d22018-09-25 18:10:19 +02006443 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006444 db_vnfr = self.db.get_one(
6445 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6446 )
bravof922c4172020-11-24 21:21:43 -03006447
David Garciac1fe90a2021-03-31 19:12:02 +02006448 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6449
tierno59d22d22018-09-25 18:10:19 +02006450 step = "Getting vnfd from database"
6451 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006452
aktas13251562021-02-12 22:19:10 +03006453 base_folder = db_vnfd["_admin"]["storage"]
6454
tierno59d22d22018-09-25 18:10:19 +02006455 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006456 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006457 get_scaling_aspect(db_vnfd),
6458 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006459 )
6460 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006461 raise LcmException(
6462 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6463 "at vnfd:scaling-group-descriptor".format(scaling_group)
6464 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006465
tierno15b1cf12019-08-29 13:21:40 +00006466 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006467 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006468 nb_scale_op = 0
6469 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006470 self.update_db_2(
6471 "nsrs",
6472 nsr_id,
6473 {
6474 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006475 {
6476 "name": scaling_group,
6477 "vnf_index": vnf_index,
6478 "nb-scale-op": 0,
6479 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006480 ]
6481 },
6482 )
tierno59d22d22018-09-25 18:10:19 +02006483 admin_scale_index = 0
6484 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006485 for admin_scale_index, admin_scale_info in enumerate(
6486 db_nsr["_admin"]["scaling-group"]
6487 ):
36970ef037852024-04-01 15:41:31 +00006488 if (
6489 admin_scale_info["name"] == scaling_group
6490 and admin_scale_info["vnf_index"] == vnf_index
6491 ):
tierno59d22d22018-09-25 18:10:19 +02006492 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6493 break
tierno9ab95942018-10-10 16:44:22 +02006494 else: # not found, set index one plus last element and add new entry with the name
6495 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006496 db_nsr_update[
6497 "_admin.scaling-group.{}.name".format(admin_scale_index)
6498 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006499 db_nsr_update[
6500 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6501 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006502
6503 vca_scaling_info = []
6504 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006505 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006506 if "aspect-delta-details" not in scaling_descriptor:
6507 raise LcmException(
6508 "Aspect delta details not fount in scaling descriptor {}".format(
6509 scaling_descriptor["name"]
6510 )
6511 )
tierno59d22d22018-09-25 18:10:19 +02006512 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006513 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006514
aktas5f75f102021-03-15 11:26:10 +03006515 scaling_info["scaling_direction"] = "OUT"
6516 scaling_info["vdu-create"] = {}
6517 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006518 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006519 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006520 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006521 # vdu_index also provides the number of instance of the targeted vdu
6522 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006523 if vdu_index <= len(db_vnfr["vdur"]):
6524 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6525 prom_job_name = (
6526 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6527 )
6528 prom_job_name = prom_job_name.replace("_", "")
6529 prom_job_name = prom_job_name.replace("-", "")
6530 else:
6531 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006532 cloud_init_text = self._get_vdu_cloud_init_content(
6533 vdud, db_vnfd
6534 )
tierno72ef84f2020-10-06 08:22:07 +00006535 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006536 additional_params = (
6537 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6538 or {}
6539 )
bravof832f8992020-12-07 12:57:31 -03006540 cloud_init_list = []
6541
6542 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6543 max_instance_count = 10
6544 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006545 max_instance_count = vdu_profile.get(
6546 "max-number-of-instances", 10
6547 )
6548
6549 default_instance_num = get_number_of_instances(
6550 db_vnfd, vdud["id"]
6551 )
aktas5f75f102021-03-15 11:26:10 +03006552 instances_number = vdu_delta.get("number-of-instances", 1)
6553 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006554
aktas5f75f102021-03-15 11:26:10 +03006555 new_instance_count = nb_scale_op + default_instance_num
6556 # Control if new count is over max and vdu count is less than max.
6557 # Then assign new instance count
6558 if new_instance_count > max_instance_count > vdu_count:
6559 instances_number = new_instance_count - max_instance_count
6560 else:
6561 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006562
aktas5f75f102021-03-15 11:26:10 +03006563 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006564 raise LcmException(
6565 "reached the limit of {} (max-instance-count) "
6566 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006567 "scaling-group-descriptor '{}'".format(
6568 nb_scale_op, scaling_group
6569 )
bravof922c4172020-11-24 21:21:43 -03006570 )
bravof832f8992020-12-07 12:57:31 -03006571 for x in range(vdu_delta.get("number-of-instances", 1)):
6572 if cloud_init_text:
6573 # TODO Information of its own ip is not available because db_vnfr is not updated.
6574 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006575 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006576 )
bravof832f8992020-12-07 12:57:31 -03006577 cloud_init_list.append(
6578 self._parse_cloud_init(
6579 cloud_init_text,
6580 additional_params,
6581 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006582 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006583 )
6584 )
aktas5f75f102021-03-15 11:26:10 +03006585 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006586 {
6587 "osm_vdu_id": vdu_delta["id"],
6588 "member-vnf-index": vnf_index,
6589 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006590 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006591 }
6592 )
aktas5f75f102021-03-15 11:26:10 +03006593 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6594 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006595 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006596 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006597 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006598
6599 # Might have different kdus in the same delta
6600 # Should have list for each kdu
6601 if not scaling_info["kdu-create"].get(kdu_name, None):
6602 scaling_info["kdu-create"][kdu_name] = []
6603
6604 kdur = get_kdur(db_vnfr, kdu_name)
6605 if kdur.get("helm-chart"):
6606 k8s_cluster_type = "helm-chart-v3"
6607 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006608 elif kdur.get("juju-bundle"):
6609 k8s_cluster_type = "juju-bundle"
6610 else:
6611 raise LcmException(
6612 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6613 "juju-bundle. Maybe an old NBI version is running".format(
6614 db_vnfr["member-vnf-index-ref"], kdu_name
6615 )
6616 )
6617
6618 max_instance_count = 10
6619 if kdu_profile and "max-number-of-instances" in kdu_profile:
6620 max_instance_count = kdu_profile.get(
6621 "max-number-of-instances", 10
6622 )
6623
6624 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6625 deployed_kdu, _ = get_deployed_kdu(
6626 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006627 )
aktas5f75f102021-03-15 11:26:10 +03006628 if deployed_kdu is None:
6629 raise LcmException(
6630 "KDU '{}' for vnf '{}' not deployed".format(
6631 kdu_name, vnf_index
6632 )
6633 )
6634 kdu_instance = deployed_kdu.get("kdu-instance")
6635 instance_num = await self.k8scluster_map[
6636 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006637 ].get_scale_count(
6638 resource_name,
6639 kdu_instance,
6640 vca_id=vca_id,
6641 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6642 kdu_model=deployed_kdu.get("kdu-model"),
6643 )
aktas5f75f102021-03-15 11:26:10 +03006644 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006645 "number-of-instances", 1
6646 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006647
aktas5f75f102021-03-15 11:26:10 +03006648 # Control if new count is over max and instance_num is less than max.
6649 # Then assign max instance number to kdu replica count
6650 if kdu_replica_count > max_instance_count > instance_num:
6651 kdu_replica_count = max_instance_count
6652 if kdu_replica_count > max_instance_count:
6653 raise LcmException(
6654 "reached the limit of {} (max-instance-count) "
6655 "scaling-out operations for the "
6656 "scaling-group-descriptor '{}'".format(
6657 instance_num, scaling_group
6658 )
6659 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006660
aktas5f75f102021-03-15 11:26:10 +03006661 for x in range(kdu_delta.get("number-of-instances", 1)):
6662 vca_scaling_info.append(
6663 {
6664 "osm_kdu_id": kdu_name,
6665 "member-vnf-index": vnf_index,
6666 "type": "create",
6667 "kdu_index": instance_num + x - 1,
6668 }
6669 )
6670 scaling_info["kdu-create"][kdu_name].append(
6671 {
6672 "member-vnf-index": vnf_index,
6673 "type": "create",
6674 "k8s-cluster-type": k8s_cluster_type,
6675 "resource-name": resource_name,
6676 "scale": kdu_replica_count,
6677 }
6678 )
6679 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006680 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006681
6682 scaling_info["scaling_direction"] = "IN"
6683 scaling_info["vdu-delete"] = {}
6684 scaling_info["kdu-delete"] = {}
6685
bravof832f8992020-12-07 12:57:31 -03006686 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006687 for vdu_delta in delta.get("vdu-delta", {}):
6688 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006689 min_instance_count = 0
6690 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6691 if vdu_profile and "min-number-of-instances" in vdu_profile:
6692 min_instance_count = vdu_profile["min-number-of-instances"]
6693
garciadeblas5697b8b2021-03-24 09:17:02 +01006694 default_instance_num = get_number_of_instances(
6695 db_vnfd, vdu_delta["id"]
6696 )
aktas5f75f102021-03-15 11:26:10 +03006697 instance_num = vdu_delta.get("number-of-instances", 1)
6698 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006699
aktas5f75f102021-03-15 11:26:10 +03006700 new_instance_count = nb_scale_op + default_instance_num
6701
6702 if new_instance_count < min_instance_count < vdu_count:
6703 instances_number = min_instance_count - new_instance_count
6704 else:
6705 instances_number = instance_num
6706
6707 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006708 raise LcmException(
6709 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006710 "scaling-group-descriptor '{}'".format(
6711 nb_scale_op, scaling_group
6712 )
bravof832f8992020-12-07 12:57:31 -03006713 )
aktas13251562021-02-12 22:19:10 +03006714 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006715 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006716 {
6717 "osm_vdu_id": vdu_delta["id"],
6718 "member-vnf-index": vnf_index,
6719 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006720 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006721 }
6722 )
aktas5f75f102021-03-15 11:26:10 +03006723 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6724 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006725 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006726 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006727 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006728
6729 if not scaling_info["kdu-delete"].get(kdu_name, None):
6730 scaling_info["kdu-delete"][kdu_name] = []
6731
6732 kdur = get_kdur(db_vnfr, kdu_name)
6733 if kdur.get("helm-chart"):
6734 k8s_cluster_type = "helm-chart-v3"
6735 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006736 elif kdur.get("juju-bundle"):
6737 k8s_cluster_type = "juju-bundle"
6738 else:
6739 raise LcmException(
6740 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6741 "juju-bundle. Maybe an old NBI version is running".format(
6742 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6743 )
6744 )
6745
6746 min_instance_count = 0
6747 if kdu_profile and "min-number-of-instances" in kdu_profile:
6748 min_instance_count = kdu_profile["min-number-of-instances"]
6749
6750 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6751 deployed_kdu, _ = get_deployed_kdu(
6752 nsr_deployed, kdu_name, vnf_index
6753 )
6754 if deployed_kdu is None:
6755 raise LcmException(
6756 "KDU '{}' for vnf '{}' not deployed".format(
6757 kdu_name, vnf_index
6758 )
6759 )
6760 kdu_instance = deployed_kdu.get("kdu-instance")
6761 instance_num = await self.k8scluster_map[
6762 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006763 ].get_scale_count(
6764 resource_name,
6765 kdu_instance,
6766 vca_id=vca_id,
6767 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6768 kdu_model=deployed_kdu.get("kdu-model"),
6769 )
aktas5f75f102021-03-15 11:26:10 +03006770 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006771 "number-of-instances", 1
6772 )
tierno59d22d22018-09-25 18:10:19 +02006773
aktas5f75f102021-03-15 11:26:10 +03006774 if kdu_replica_count < min_instance_count < instance_num:
6775 kdu_replica_count = min_instance_count
6776 if kdu_replica_count < min_instance_count:
6777 raise LcmException(
6778 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6779 "scaling-group-descriptor '{}'".format(
6780 instance_num, scaling_group
6781 )
6782 )
6783
6784 for x in range(kdu_delta.get("number-of-instances", 1)):
6785 vca_scaling_info.append(
6786 {
6787 "osm_kdu_id": kdu_name,
6788 "member-vnf-index": vnf_index,
6789 "type": "delete",
6790 "kdu_index": instance_num - x - 1,
6791 }
6792 )
6793 scaling_info["kdu-delete"][kdu_name].append(
6794 {
6795 "member-vnf-index": vnf_index,
6796 "type": "delete",
6797 "k8s-cluster-type": k8s_cluster_type,
6798 "resource-name": resource_name,
6799 "scale": kdu_replica_count,
6800 }
6801 )
6802
tierno59d22d22018-09-25 18:10:19 +02006803 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006804 vdu_delete = copy(scaling_info.get("vdu-delete"))
6805 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006806 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006807 if vdu_delete.get(vdur["vdu-id-ref"]):
6808 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006809 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006810 {
6811 "name": vdur.get("name") or vdur.get("vdu-name"),
6812 "vdu_id": vdur["vdu-id-ref"],
6813 "interface": [],
6814 }
6815 )
tierno59d22d22018-09-25 18:10:19 +02006816 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006817 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006818 {
6819 "name": interface["name"],
6820 "ip_address": interface["ip-address"],
6821 "mac_address": interface.get("mac-address"),
6822 }
6823 )
tierno2357f4e2020-10-19 16:38:59 +00006824 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006825
kuuseac3a8882019-10-03 10:48:06 +02006826 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006827 step = "Executing pre-scale vnf-config-primitive"
6828 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006829 for scaling_config_action in scaling_descriptor[
6830 "scaling-config-action"
6831 ]:
6832 if (
6833 scaling_config_action.get("trigger") == "pre-scale-in"
6834 and scaling_type == "SCALE_IN"
6835 ) or (
6836 scaling_config_action.get("trigger") == "pre-scale-out"
6837 and scaling_type == "SCALE_OUT"
6838 ):
6839 vnf_config_primitive = scaling_config_action[
6840 "vnf-config-primitive-name-ref"
6841 ]
6842 step = db_nslcmop_update[
6843 "detailed-status"
6844 ] = "executing pre-scale scaling-config-action '{}'".format(
6845 vnf_config_primitive
6846 )
tiernoda964822019-01-14 15:53:47 +00006847
tierno59d22d22018-09-25 18:10:19 +02006848 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006849 for config_primitive in (
6850 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6851 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006852 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006853 break
6854 else:
6855 raise LcmException(
6856 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006857 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006858 "primitive".format(scaling_group, vnf_config_primitive)
6859 )
tiernoda964822019-01-14 15:53:47 +00006860
aktas5f75f102021-03-15 11:26:10 +03006861 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006862 if db_vnfr.get("additionalParamsForVnf"):
6863 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006864
tierno9ab95942018-10-10 16:44:22 +02006865 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006866 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006867 primitive_params = self._map_primitive_params(
6868 config_primitive, {}, vnfr_params
6869 )
kuuseac3a8882019-10-03 10:48:06 +02006870
tierno7c4e24c2020-05-13 08:41:35 +00006871 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006872 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006873 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006874 vnf_index,
6875 vnf_config_primitive,
6876 primitive_params,
6877 "PRE-SCALE",
6878 )
tierno7c4e24c2020-05-13 08:41:35 +00006879 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006880 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006881 result = "COMPLETED"
6882 result_detail = "Done"
6883 self.logger.debug(
6884 logging_text
6885 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6886 vnf_config_primitive, result, result_detail
6887 )
6888 )
kuuseac3a8882019-10-03 10:48:06 +02006889 else:
tierno7c4e24c2020-05-13 08:41:35 +00006890 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006891 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006892 op_index = (
6893 len(db_nslcmop.get("_admin", {}).get("operations"))
6894 - 1
6895 )
6896 self.logger.debug(
6897 logging_text
6898 + "vnf_config_primitive={} New sub-operation".format(
6899 vnf_config_primitive
6900 )
6901 )
kuuseac3a8882019-10-03 10:48:06 +02006902 else:
tierno7c4e24c2020-05-13 08:41:35 +00006903 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006904 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6905 op_index
6906 ]
6907 vnf_index = op.get("member_vnf_index")
6908 vnf_config_primitive = op.get("primitive")
6909 primitive_params = op.get("primitive_params")
6910 self.logger.debug(
6911 logging_text
6912 + "vnf_config_primitive={} Sub-operation retry".format(
6913 vnf_config_primitive
6914 )
6915 )
tierno588547c2020-07-01 15:30:20 +00006916 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006917 ee_descriptor_id = config_primitive.get(
6918 "execution-environment-ref"
6919 )
6920 primitive_name = config_primitive.get(
6921 "execution-environment-primitive", vnf_config_primitive
6922 )
6923 ee_id, vca_type = self._look_for_deployed_vca(
6924 nsr_deployed["VCA"],
6925 member_vnf_index=vnf_index,
6926 vdu_id=None,
6927 vdu_count_index=None,
6928 ee_descriptor_id=ee_descriptor_id,
6929 )
kuuseac3a8882019-10-03 10:48:06 +02006930 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006931 ee_id,
6932 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006933 primitive_params,
6934 vca_type=vca_type,
6935 vca_id=vca_id,
6936 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006937 self.logger.debug(
6938 logging_text
6939 + "vnf_config_primitive={} Done with result {} {}".format(
6940 vnf_config_primitive, result, result_detail
6941 )
6942 )
kuuseac3a8882019-10-03 10:48:06 +02006943 # Update operationState = COMPLETED | FAILED
6944 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006945 db_nslcmop, op_index, result, result_detail
6946 )
kuuseac3a8882019-10-03 10:48:06 +02006947
tierno59d22d22018-09-25 18:10:19 +02006948 if result == "FAILED":
6949 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006950 db_nsr_update["config-status"] = old_config_status
6951 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006952 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006953
garciadeblas5697b8b2021-03-24 09:17:02 +01006954 db_nsr_update[
6955 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6956 ] = nb_scale_op
6957 db_nsr_update[
6958 "_admin.scaling-group.{}.time".format(admin_scale_index)
6959 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006960
aktas13251562021-02-12 22:19:10 +03006961 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006962 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006963 step = db_nslcmop_update[
6964 "detailed-status"
6965 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03006966 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006967 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006968 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006969 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01006970 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03006971 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01006972 )
aktas5f75f102021-03-15 11:26:10 +03006973 if vca_info.get("osm_vdu_id"):
6974 vdu_id = vca_info["osm_vdu_id"]
6975 vdu_index = int(vca_info["vdu_index"])
6976 stage[
6977 1
6978 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
6979 member_vnf_index, vdu_id, vdu_index
6980 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006981 stage[2] = step = "Scaling in VCA"
6982 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03006983 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
6984 config_update = db_nsr["configurationStatus"]
6985 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01006986 if (
6987 (vca or vca.get("ee_id"))
6988 and vca["member-vnf-index"] == member_vnf_index
6989 and vca["vdu_count_index"] == vdu_index
6990 ):
aktas13251562021-02-12 22:19:10 +03006991 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006992 config_descriptor = get_configuration(
6993 db_vnfd, vca.get("vdu_id")
6994 )
aktas13251562021-02-12 22:19:10 +03006995 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006996 config_descriptor = get_configuration(
6997 db_vnfd, vca.get("kdu_name")
6998 )
aktas13251562021-02-12 22:19:10 +03006999 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007000 config_descriptor = get_configuration(
7001 db_vnfd, db_vnfd["id"]
7002 )
7003 operation_params = (
7004 db_nslcmop.get("operationParams") or {}
7005 )
7006 exec_terminate_primitives = not operation_params.get(
7007 "skip_terminate_primitives"
7008 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007009 task = asyncio.ensure_future(
7010 asyncio.wait_for(
7011 self.destroy_N2VC(
7012 logging_text,
7013 db_nslcmop,
7014 vca,
7015 config_descriptor,
7016 vca_index,
7017 destroy_ee=True,
7018 exec_primitives=exec_terminate_primitives,
7019 scaling_in=True,
7020 vca_id=vca_id,
7021 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007022 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007023 )
7024 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007025 tasks_dict_info[task] = "Terminating VCA {}".format(
7026 vca.get("ee_id")
7027 )
aktas13251562021-02-12 22:19:10 +03007028 del vca_update[vca_index]
7029 del config_update[vca_index]
7030 # wait for pending tasks of terminate primitives
7031 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007032 self.logger.debug(
7033 logging_text
7034 + "Waiting for tasks {}".format(
7035 list(tasks_dict_info.keys())
7036 )
7037 )
7038 error_list = await self._wait_for_tasks(
7039 logging_text,
7040 tasks_dict_info,
7041 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007042 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007043 ),
7044 stage,
7045 nslcmop_id,
7046 )
aktas13251562021-02-12 22:19:10 +03007047 tasks_dict_info.clear()
7048 if error_list:
7049 raise LcmException("; ".join(error_list))
7050
7051 db_vca_and_config_update = {
7052 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007053 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007054 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007055 self.update_db_2(
7056 "nsrs", db_nsr["_id"], db_vca_and_config_update
7057 )
aktas13251562021-02-12 22:19:10 +03007058 scale_process = None
7059 # SCALE-IN VCA - END
7060
kuuseac3a8882019-10-03 10:48:06 +02007061 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007062 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007063 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007064 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007065 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007066 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007067 )
aktas5f75f102021-03-15 11:26:10 +03007068 scaling_info.pop("vdu-create", None)
7069 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007070
tierno9ab95942018-10-10 16:44:22 +02007071 scale_process = None
aktas13251562021-02-12 22:19:10 +03007072 # SCALE RO - END
7073
aktas5f75f102021-03-15 11:26:10 +03007074 # SCALE KDU - BEGIN
7075 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7076 scale_process = "KDU"
7077 await self._scale_kdu(
7078 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7079 )
7080 scaling_info.pop("kdu-create", None)
7081 scaling_info.pop("kdu-delete", None)
7082
7083 scale_process = None
7084 # SCALE KDU - END
7085
7086 if db_nsr_update:
7087 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7088
aktas13251562021-02-12 22:19:10 +03007089 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007090 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007091 step = db_nslcmop_update[
7092 "detailed-status"
7093 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007094 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007095 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007096 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007097 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007098 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007099 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007100 )
aktas13251562021-02-12 22:19:10 +03007101 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007102 if vca_info.get("osm_vdu_id"):
7103 vdu_index = int(vca_info["vdu_index"])
7104 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7105 if db_vnfr.get("additionalParamsForVnf"):
7106 deploy_params.update(
7107 parse_yaml_strings(
7108 db_vnfr["additionalParamsForVnf"].copy()
7109 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007110 )
aktas5f75f102021-03-15 11:26:10 +03007111 descriptor_config = get_configuration(
7112 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007113 )
aktas5f75f102021-03-15 11:26:10 +03007114 if descriptor_config:
7115 vdu_id = None
7116 vdu_name = None
7117 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007118 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007119 self._deploy_n2vc(
7120 logging_text=logging_text
7121 + "member_vnf_index={} ".format(member_vnf_index),
7122 db_nsr=db_nsr,
7123 db_vnfr=db_vnfr,
7124 nslcmop_id=nslcmop_id,
7125 nsr_id=nsr_id,
7126 nsi_id=nsi_id,
7127 vnfd_id=vnfd_id,
7128 vdu_id=vdu_id,
7129 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007130 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007131 member_vnf_index=member_vnf_index,
7132 vdu_index=vdu_index,
7133 vdu_name=vdu_name,
7134 deploy_params=deploy_params,
7135 descriptor_config=descriptor_config,
7136 base_folder=base_folder,
7137 task_instantiation_info=tasks_dict_info,
7138 stage=stage,
7139 )
7140 vdu_id = vca_info["osm_vdu_id"]
7141 vdur = find_in_list(
7142 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007143 )
aktas5f75f102021-03-15 11:26:10 +03007144 descriptor_config = get_configuration(db_vnfd, vdu_id)
7145 if vdur.get("additionalParams"):
7146 deploy_params_vdu = parse_yaml_strings(
7147 vdur["additionalParams"]
7148 )
7149 else:
7150 deploy_params_vdu = deploy_params
7151 deploy_params_vdu["OSM"] = get_osm_params(
7152 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007153 )
aktas5f75f102021-03-15 11:26:10 +03007154 if descriptor_config:
7155 vdu_name = None
7156 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007157 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007158 stage[
7159 1
7160 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007161 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007162 )
7163 stage[2] = step = "Scaling out VCA"
7164 self._write_op_status(op_id=nslcmop_id, stage=stage)
7165 self._deploy_n2vc(
7166 logging_text=logging_text
7167 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7168 member_vnf_index, vdu_id, vdu_index
7169 ),
7170 db_nsr=db_nsr,
7171 db_vnfr=db_vnfr,
7172 nslcmop_id=nslcmop_id,
7173 nsr_id=nsr_id,
7174 nsi_id=nsi_id,
7175 vnfd_id=vnfd_id,
7176 vdu_id=vdu_id,
7177 kdu_name=kdu_name,
7178 member_vnf_index=member_vnf_index,
7179 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007180 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007181 vdu_name=vdu_name,
7182 deploy_params=deploy_params_vdu,
7183 descriptor_config=descriptor_config,
7184 base_folder=base_folder,
7185 task_instantiation_info=tasks_dict_info,
7186 stage=stage,
7187 )
aktas13251562021-02-12 22:19:10 +03007188 # SCALE-UP VCA - END
7189 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007190
kuuseac3a8882019-10-03 10:48:06 +02007191 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007192 # execute primitive service POST-SCALING
7193 step = "Executing post-scale vnf-config-primitive"
7194 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007195 for scaling_config_action in scaling_descriptor[
7196 "scaling-config-action"
7197 ]:
7198 if (
7199 scaling_config_action.get("trigger") == "post-scale-in"
7200 and scaling_type == "SCALE_IN"
7201 ) or (
7202 scaling_config_action.get("trigger") == "post-scale-out"
7203 and scaling_type == "SCALE_OUT"
7204 ):
7205 vnf_config_primitive = scaling_config_action[
7206 "vnf-config-primitive-name-ref"
7207 ]
7208 step = db_nslcmop_update[
7209 "detailed-status"
7210 ] = "executing post-scale scaling-config-action '{}'".format(
7211 vnf_config_primitive
7212 )
tiernoda964822019-01-14 15:53:47 +00007213
aktas5f75f102021-03-15 11:26:10 +03007214 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007215 if db_vnfr.get("additionalParamsForVnf"):
7216 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7217
tierno59d22d22018-09-25 18:10:19 +02007218 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007219 for config_primitive in (
7220 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7221 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007222 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007223 break
7224 else:
tiernoa278b842020-07-08 15:33:55 +00007225 raise LcmException(
7226 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7227 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007228 "config-primitive".format(
7229 scaling_group, vnf_config_primitive
7230 )
7231 )
tierno9ab95942018-10-10 16:44:22 +02007232 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007233 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007234 primitive_params = self._map_primitive_params(
7235 config_primitive, {}, vnfr_params
7236 )
tiernod6de1992018-10-11 13:05:52 +02007237
tierno7c4e24c2020-05-13 08:41:35 +00007238 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007239 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007240 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007241 vnf_index,
7242 vnf_config_primitive,
7243 primitive_params,
7244 "POST-SCALE",
7245 )
quilesj4cda56b2019-12-05 10:02:20 +00007246 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007247 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007248 result = "COMPLETED"
7249 result_detail = "Done"
7250 self.logger.debug(
7251 logging_text
7252 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7253 vnf_config_primitive, result, result_detail
7254 )
7255 )
kuuseac3a8882019-10-03 10:48:06 +02007256 else:
quilesj4cda56b2019-12-05 10:02:20 +00007257 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007258 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007259 op_index = (
7260 len(db_nslcmop.get("_admin", {}).get("operations"))
7261 - 1
7262 )
7263 self.logger.debug(
7264 logging_text
7265 + "vnf_config_primitive={} New sub-operation".format(
7266 vnf_config_primitive
7267 )
7268 )
kuuseac3a8882019-10-03 10:48:06 +02007269 else:
tierno7c4e24c2020-05-13 08:41:35 +00007270 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007271 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7272 op_index
7273 ]
7274 vnf_index = op.get("member_vnf_index")
7275 vnf_config_primitive = op.get("primitive")
7276 primitive_params = op.get("primitive_params")
7277 self.logger.debug(
7278 logging_text
7279 + "vnf_config_primitive={} Sub-operation retry".format(
7280 vnf_config_primitive
7281 )
7282 )
tierno588547c2020-07-01 15:30:20 +00007283 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007284 ee_descriptor_id = config_primitive.get(
7285 "execution-environment-ref"
7286 )
7287 primitive_name = config_primitive.get(
7288 "execution-environment-primitive", vnf_config_primitive
7289 )
7290 ee_id, vca_type = self._look_for_deployed_vca(
7291 nsr_deployed["VCA"],
7292 member_vnf_index=vnf_index,
7293 vdu_id=None,
7294 vdu_count_index=None,
7295 ee_descriptor_id=ee_descriptor_id,
7296 )
kuuseac3a8882019-10-03 10:48:06 +02007297 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007298 ee_id,
7299 primitive_name,
7300 primitive_params,
7301 vca_type=vca_type,
7302 vca_id=vca_id,
7303 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007304 self.logger.debug(
7305 logging_text
7306 + "vnf_config_primitive={} Done with result {} {}".format(
7307 vnf_config_primitive, result, result_detail
7308 )
7309 )
kuuseac3a8882019-10-03 10:48:06 +02007310 # Update operationState = COMPLETED | FAILED
7311 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007312 db_nslcmop, op_index, result, result_detail
7313 )
kuuseac3a8882019-10-03 10:48:06 +02007314
tierno59d22d22018-09-25 18:10:19 +02007315 if result == "FAILED":
7316 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007317 db_nsr_update["config-status"] = old_config_status
7318 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007319 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007320 # Check if each vnf has exporter for metric collection if so update prometheus job records
7321 if scaling_type == "SCALE_OUT":
7322 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7323 vnfr_id = db_vnfr["id"]
7324 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7325 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7326 self.logger.debug("exporter config :{}".format(exporter_config))
7327 artifact_path = "{}/{}/{}".format(
7328 base_folder["folder"],
7329 base_folder["pkg-dir"],
7330 "exporter-endpoint",
7331 )
7332 ee_id = None
7333 ee_config_descriptor = exporter_config
7334 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7335 logging_text,
7336 nsr_id,
7337 vnfr_id,
7338 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7339 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7340 user=None,
7341 pub_key=None,
7342 )
7343 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7344 self.logger.debug("Artifact_path:{}".format(artifact_path))
7345 vdu_id_for_prom = None
7346 vdu_index_for_prom = None
7347 for x in get_iterable(db_vnfr, "vdur"):
7348 vdu_id_for_prom = x.get("vdu-id-ref")
7349 vdu_index_for_prom = x.get("count-index")
7350 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7351 vnfr_id = vnfr_id.replace("_", "")
7352 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7353 ee_id=ee_id,
7354 artifact_path=artifact_path,
7355 ee_config_descriptor=ee_config_descriptor,
7356 vnfr_id=vnfr_id,
7357 nsr_id=nsr_id,
7358 target_ip=rw_mgmt_ip,
7359 element_type="VDU",
7360 vdu_id=vdu_id_for_prom,
7361 vdu_index=vdu_index_for_prom,
7362 )
tierno59d22d22018-09-25 18:10:19 +02007363
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007364 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7365 if prometheus_jobs:
7366 db_nsr_update[
7367 "_admin.deployed.prometheus_jobs"
7368 ] = prometheus_jobs
7369 self.update_db_2(
7370 "nsrs",
7371 nsr_id,
7372 db_nsr_update,
7373 )
7374
7375 for job in prometheus_jobs:
7376 self.db.set_one(
7377 "prometheus_jobs",
7378 {"job_name": ""},
7379 job,
7380 upsert=True,
7381 fail_on_empty=False,
7382 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007383 db_nsr_update[
7384 "detailed-status"
7385 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7386 db_nsr_update["operational-status"] = (
7387 "running"
7388 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007389 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007390 )
tiernod6de1992018-10-11 13:05:52 +02007391 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007392 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007393 except (
7394 ROclient.ROClientException,
7395 DbException,
7396 LcmException,
7397 NgRoException,
7398 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007399 self.logger.error(logging_text + "Exit Exception {}".format(e))
7400 exc = e
7401 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007402 self.logger.error(
7403 logging_text + "Cancelled Exception while '{}'".format(step)
7404 )
tierno59d22d22018-09-25 18:10:19 +02007405 exc = "Operation was cancelled"
7406 except Exception as e:
7407 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007408 self.logger.critical(
7409 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7410 exc_info=True,
7411 )
tierno59d22d22018-09-25 18:10:19 +02007412 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007413 error_list = list()
7414 if exc:
7415 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007416 self._write_ns_status(
7417 nsr_id=nsr_id,
7418 ns_state=None,
7419 current_operation="IDLE",
7420 current_operation_id=None,
7421 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007422 try:
7423 if tasks_dict_info:
7424 stage[1] = "Waiting for instantiate pending tasks."
7425 self.logger.debug(logging_text + stage[1])
7426 exc = await self._wait_for_tasks(
7427 logging_text,
7428 tasks_dict_info,
7429 self.timeout.ns_deploy,
7430 stage,
7431 nslcmop_id,
7432 nsr_id=nsr_id,
7433 )
7434 except asyncio.CancelledError:
7435 error_list.append("Cancelled")
7436 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7437 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007438 logging_text,
7439 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007440 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007441 stage,
7442 nslcmop_id,
7443 nsr_id=nsr_id,
7444 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007445 if error_list:
7446 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007447 db_nslcmop_update[
7448 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007449 ] = error_description_nslcmop = "FAILED {}: {}".format(
7450 step, error_detail
7451 )
tiernoa17d4f42020-04-28 09:59:23 +00007452 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007453 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007454 db_nsr_update["operational-status"] = old_operational_status
7455 db_nsr_update["config-status"] = old_config_status
7456 db_nsr_update["detailed-status"] = ""
7457 if scale_process:
7458 if "VCA" in scale_process:
7459 db_nsr_update["config-status"] = "failed"
7460 if "RO" in scale_process:
7461 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007462 db_nsr_update[
7463 "detailed-status"
7464 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007465 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007466 )
tiernoa17d4f42020-04-28 09:59:23 +00007467 else:
7468 error_description_nslcmop = None
7469 nslcmop_operation_state = "COMPLETED"
7470 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007471 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7472 self.db.del_one(
7473 "prometheus_jobs",
7474 {"job_name": prom_job_name},
7475 fail_on_empty=False,
7476 )
quilesj4cda56b2019-12-05 10:02:20 +00007477
garciadeblas5697b8b2021-03-24 09:17:02 +01007478 self._write_op_status(
7479 op_id=nslcmop_id,
7480 stage="",
7481 error_message=error_description_nslcmop,
7482 operation_state=nslcmop_operation_state,
7483 other_update=db_nslcmop_update,
7484 )
tiernoa17d4f42020-04-28 09:59:23 +00007485 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007486 self._write_ns_status(
7487 nsr_id=nsr_id,
7488 ns_state=None,
7489 current_operation="IDLE",
7490 current_operation_id=None,
7491 other_update=db_nsr_update,
7492 )
tiernoa17d4f42020-04-28 09:59:23 +00007493
tierno59d22d22018-09-25 18:10:19 +02007494 if nslcmop_operation_state:
7495 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007496 msg = {
7497 "nsr_id": nsr_id,
7498 "nslcmop_id": nslcmop_id,
7499 "operationState": nslcmop_operation_state,
7500 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007501 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007502 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007503 self.logger.error(
7504 logging_text + "kafka_write notification Exception {}".format(e)
7505 )
tierno59d22d22018-09-25 18:10:19 +02007506 self.logger.debug(logging_text + "Exit")
7507 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007508
aktas5f75f102021-03-15 11:26:10 +03007509 async def _scale_kdu(
7510 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7511 ):
7512 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7513 for kdu_name in _scaling_info:
7514 for kdu_scaling_info in _scaling_info[kdu_name]:
7515 deployed_kdu, index = get_deployed_kdu(
7516 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7517 )
7518 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7519 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007520 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007521 scale = int(kdu_scaling_info["scale"])
7522 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7523
7524 db_dict = {
7525 "collection": "nsrs",
7526 "filter": {"_id": nsr_id},
7527 "path": "_admin.deployed.K8s.{}".format(index),
7528 }
7529
7530 step = "scaling application {}".format(
7531 kdu_scaling_info["resource-name"]
7532 )
7533 self.logger.debug(logging_text + step)
7534
7535 if kdu_scaling_info["type"] == "delete":
7536 kdu_config = get_configuration(db_vnfd, kdu_name)
7537 if (
7538 kdu_config
7539 and kdu_config.get("terminate-config-primitive")
7540 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7541 ):
7542 terminate_config_primitive_list = kdu_config.get(
7543 "terminate-config-primitive"
7544 )
7545 terminate_config_primitive_list.sort(
7546 key=lambda val: int(val["seq"])
7547 )
7548
7549 for (
7550 terminate_config_primitive
7551 ) in terminate_config_primitive_list:
7552 primitive_params_ = self._map_primitive_params(
7553 terminate_config_primitive, {}, {}
7554 )
7555 step = "execute terminate config primitive"
7556 self.logger.debug(logging_text + step)
7557 await asyncio.wait_for(
7558 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7559 cluster_uuid=cluster_uuid,
7560 kdu_instance=kdu_instance,
7561 primitive_name=terminate_config_primitive["name"],
7562 params=primitive_params_,
7563 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007564 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007565 vca_id=vca_id,
7566 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007567 timeout=self.timeout.primitive
7568 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007569 )
7570
7571 await asyncio.wait_for(
7572 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007573 kdu_instance=kdu_instance,
7574 scale=scale,
7575 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007576 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007577 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007578 cluster_uuid=cluster_uuid,
7579 kdu_model=kdu_model,
7580 atomic=True,
7581 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007582 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007583 timeout=self.timeout.scale_on_error
7584 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007585 )
7586
7587 if kdu_scaling_info["type"] == "create":
7588 kdu_config = get_configuration(db_vnfd, kdu_name)
7589 if (
7590 kdu_config
7591 and kdu_config.get("initial-config-primitive")
7592 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7593 ):
7594 initial_config_primitive_list = kdu_config.get(
7595 "initial-config-primitive"
7596 )
7597 initial_config_primitive_list.sort(
7598 key=lambda val: int(val["seq"])
7599 )
7600
7601 for initial_config_primitive in initial_config_primitive_list:
7602 primitive_params_ = self._map_primitive_params(
7603 initial_config_primitive, {}, {}
7604 )
7605 step = "execute initial config primitive"
7606 self.logger.debug(logging_text + step)
7607 await asyncio.wait_for(
7608 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7609 cluster_uuid=cluster_uuid,
7610 kdu_instance=kdu_instance,
7611 primitive_name=initial_config_primitive["name"],
7612 params=primitive_params_,
7613 db_dict=db_dict,
7614 vca_id=vca_id,
7615 ),
7616 timeout=600,
7617 )
7618
garciadeblas5697b8b2021-03-24 09:17:02 +01007619 async def _scale_ng_ro(
7620 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7621 ):
tierno2357f4e2020-10-19 16:38:59 +00007622 nsr_id = db_nslcmop["nsInstanceId"]
7623 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7624 db_vnfrs = {}
7625
7626 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007627 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007628
7629 # for each vnf in ns, read vnfd
7630 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7631 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7632 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007633 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007634 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007635 # read from db
7636 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007637 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007638 n2vc_key = self.n2vc.get_public_key()
7639 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007640 self.scale_vnfr(
7641 db_vnfr,
7642 vdu_scaling_info.get("vdu-create"),
7643 vdu_scaling_info.get("vdu-delete"),
7644 mark_delete=True,
7645 )
tierno2357f4e2020-10-19 16:38:59 +00007646 # db_vnfr has been updated, update db_vnfrs to use it
7647 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007648 await self._instantiate_ng_ro(
7649 logging_text,
7650 nsr_id,
7651 db_nsd,
7652 db_nsr,
7653 db_nslcmop,
7654 db_vnfrs,
7655 db_vnfds,
7656 n2vc_key_list,
7657 stage=stage,
7658 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007659 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007660 )
tierno2357f4e2020-10-19 16:38:59 +00007661 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007662 self.scale_vnfr(
7663 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7664 )
tierno2357f4e2020-10-19 16:38:59 +00007665
bravof73bac502021-05-11 07:38:47 -04007666 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007667 self,
7668 ee_id: str,
7669 artifact_path: str,
7670 ee_config_descriptor: dict,
7671 vnfr_id: str,
7672 nsr_id: str,
7673 target_ip: str,
7674 element_type: str,
7675 vnf_member_index: str = "",
7676 vdu_id: str = "",
7677 vdu_index: int = None,
7678 kdu_name: str = "",
7679 kdu_index: int = None,
7680 ) -> dict:
7681 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7682 This method will wait until the corresponding VDU or KDU is fully instantiated
7683
7684 Args:
7685 ee_id (str): Execution Environment ID
7686 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7687 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7688 vnfr_id (str): VNFR ID where this EE applies
7689 nsr_id (str): NSR ID where this EE applies
7690 target_ip (str): VDU/KDU instance IP address
7691 element_type (str): NS or VNF or VDU or KDU
7692 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7693 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7694 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7695 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7696 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7697
7698 Raises:
7699 LcmException: When the VDU or KDU instance was not found in an hour
7700
7701 Returns:
7702 _type_: Prometheus jobs
7703 """
7704 # default the vdur and kdur names to an empty string, to avoid any later
7705 # problem with Prometheus when the element type is not VDU or KDU
7706 vdur_name = ""
7707 kdur_name = ""
7708
tiernob996d942020-07-03 14:52:28 +00007709 # look if exist a file called 'prometheus*.j2' and
7710 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007711 job_file = next(
7712 (
7713 f
7714 for f in artifact_content
7715 if f.startswith("prometheus") and f.endswith(".j2")
7716 ),
7717 None,
7718 )
tiernob996d942020-07-03 14:52:28 +00007719 if not job_file:
7720 return
k4.rahul74944982023-04-19 17:00:52 +05307721 self.logger.debug("Artifact path{}".format(artifact_path))
7722 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007723 with self.fs.file_open((artifact_path, job_file), "r") as f:
7724 job_data = f.read()
7725
Pedro Escaleira120695e2022-06-11 21:17:26 +01007726 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7727 if element_type in ("VDU", "KDU"):
7728 for _ in range(360):
7729 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7730 if vdu_id and vdu_index is not None:
7731 vdur = next(
7732 (
7733 x
7734 for x in get_iterable(db_vnfr, "vdur")
7735 if (
7736 x.get("vdu-id-ref") == vdu_id
7737 and x.get("count-index") == vdu_index
7738 )
7739 ),
7740 {},
7741 )
7742 if vdur.get("name"):
7743 vdur_name = vdur.get("name")
7744 break
7745 if kdu_name and kdu_index is not None:
7746 kdur = next(
7747 (
7748 x
7749 for x in get_iterable(db_vnfr, "kdur")
7750 if (
7751 x.get("kdu-name") == kdu_name
7752 and x.get("count-index") == kdu_index
7753 )
7754 ),
7755 {},
7756 )
7757 if kdur.get("name"):
7758 kdur_name = kdur.get("name")
7759 break
7760
Gabriel Cubae7898982023-05-11 01:57:21 -05007761 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007762 else:
7763 if vdu_id and vdu_index is not None:
7764 raise LcmException(
7765 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7766 )
7767 if kdu_name and kdu_index is not None:
7768 raise LcmException(
7769 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7770 )
7771
k4.rahul74944982023-04-19 17:00:52 +05307772 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007773 _, namespace, helm_id = get_ee_id_parts(
7774 ee_id
7775 ) # get namespace and EE gRPC service name
7776 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307777 host_port = "80"
7778 vnfr_id = vnfr_id.replace("-", "")
7779 variables = {
7780 "JOB_NAME": vnfr_id,
7781 "TARGET_IP": target_ip,
7782 "EXPORTER_POD_IP": host_name,
7783 "EXPORTER_POD_PORT": host_port,
7784 "NSR_ID": nsr_id,
7785 "VNF_MEMBER_INDEX": vnf_member_index,
7786 "VDUR_NAME": vdur_name,
7787 "KDUR_NAME": kdur_name,
7788 "ELEMENT_TYPE": element_type,
7789 }
7790 else:
7791 metric_path = ee_config_descriptor["metric-path"]
7792 target_port = ee_config_descriptor["metric-port"]
7793 vnfr_id = vnfr_id.replace("-", "")
7794 variables = {
7795 "JOB_NAME": vnfr_id,
7796 "TARGET_IP": target_ip,
7797 "TARGET_PORT": target_port,
7798 "METRIC_PATH": metric_path,
7799 }
7800
bravof73bac502021-05-11 07:38:47 -04007801 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007802 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7803 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007804 if (
7805 not isinstance(job.get("job_name"), str)
7806 or vnfr_id not in job["job_name"]
7807 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307808 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007809 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007810 job["vnfr_id"] = vnfr_id
7811 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007812
preethika.p28b0bf82022-09-23 07:36:28 +00007813 async def rebuild_start_stop(
7814 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7815 ):
k4.rahulb827de92022-05-02 16:35:02 +00007816 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7817 self.logger.info(logging_text + "Enter")
7818 stage = ["Preparing the environment", ""]
7819 # database nsrs record
7820 db_nsr_update = {}
7821 vdu_vim_name = None
7822 vim_vm_id = None
7823 # in case of error, indicates what part of scale was failed to put nsr at error status
7824 start_deploy = time()
7825 try:
7826 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7827 vim_account_id = db_vnfr.get("vim-account-id")
7828 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007829 vdu_id = additional_param["vdu_id"]
7830 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007831 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007832 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007833 )
k4.rahulb827de92022-05-02 16:35:02 +00007834 if vdur:
7835 vdu_vim_name = vdur["name"]
7836 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7837 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007838 else:
7839 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007840 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7841 # wait for any previous tasks in process
7842 stage[1] = "Waiting for previous operations to terminate"
7843 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007844 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007845
7846 stage[1] = "Reading from database."
7847 self.logger.info(stage[1])
7848 self._write_ns_status(
7849 nsr_id=nsr_id,
7850 ns_state=None,
7851 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007852 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007853 )
7854 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7855
7856 # read from db: ns
7857 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7858 db_nsr_update["operational-status"] = operation_type
7859 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7860 # Payload for RO
7861 desc = {
7862 operation_type: {
7863 "vim_vm_id": vim_vm_id,
7864 "vnf_id": vnf_id,
7865 "vdu_index": additional_param["count-index"],
7866 "vdu_id": vdur["id"],
7867 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007868 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007869 }
7870 }
7871 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7872 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7873 self.logger.info("ro nsr id: {}".format(nsr_id))
7874 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7875 self.logger.info("response from RO: {}".format(result_dict))
7876 action_id = result_dict["action_id"]
7877 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007878 nsr_id,
7879 action_id,
7880 nslcmop_id,
7881 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007882 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007883 None,
7884 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007885 )
7886 return "COMPLETED", "Done"
7887 except (ROclient.ROClientException, DbException, LcmException) as e:
7888 self.logger.error("Exit Exception {}".format(e))
7889 exc = e
7890 except asyncio.CancelledError:
7891 self.logger.error("Cancelled Exception while '{}'".format(stage))
7892 exc = "Operation was cancelled"
7893 except Exception as e:
7894 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007895 self.logger.critical(
7896 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7897 )
k4.rahulb827de92022-05-02 16:35:02 +00007898 return "FAILED", "Error in operate VNF {}".format(exc)
7899
elumalai80bcf1c2022-04-28 18:05:01 +05307900 async def migrate(self, nsr_id, nslcmop_id):
7901 """
7902 Migrate VNFs and VDUs instances in a NS
7903
7904 :param: nsr_id: NS Instance ID
7905 :param: nslcmop_id: nslcmop ID of migrate
7906
7907 """
7908 # Try to lock HA task here
7909 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7910 if not task_is_locked_by_me:
7911 return
7912 logging_text = "Task ns={} migrate ".format(nsr_id)
7913 self.logger.debug(logging_text + "Enter")
7914 # get all needed from database
7915 db_nslcmop = None
7916 db_nslcmop_update = {}
7917 nslcmop_operation_state = None
7918 db_nsr_update = {}
7919 target = {}
7920 exc = None
7921 # in case of error, indicates what part of scale was failed to put nsr at error status
7922 start_deploy = time()
7923
7924 try:
7925 # wait for any previous tasks in process
7926 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007927 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307928
7929 self._write_ns_status(
7930 nsr_id=nsr_id,
7931 ns_state=None,
7932 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007933 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307934 )
7935 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007936 self.logger.debug(
7937 step + " after having waited for previous tasks to be completed"
7938 )
elumalai80bcf1c2022-04-28 18:05:01 +05307939 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7940 migrate_params = db_nslcmop.get("operationParams")
7941
7942 target = {}
7943 target.update(migrate_params)
7944 desc = await self.RO.migrate(nsr_id, target)
7945 self.logger.debug("RO return > {}".format(desc))
7946 action_id = desc["action_id"]
7947 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007948 nsr_id,
7949 action_id,
7950 nslcmop_id,
7951 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007952 self.timeout.migrate,
preethika.p28b0bf82022-09-23 07:36:28 +00007953 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307954 )
7955 except (ROclient.ROClientException, DbException, LcmException) as e:
7956 self.logger.error("Exit Exception {}".format(e))
7957 exc = e
7958 except asyncio.CancelledError:
7959 self.logger.error("Cancelled Exception while '{}'".format(step))
7960 exc = "Operation was cancelled"
7961 except Exception as e:
7962 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007963 self.logger.critical(
7964 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7965 )
elumalai80bcf1c2022-04-28 18:05:01 +05307966 finally:
7967 self._write_ns_status(
7968 nsr_id=nsr_id,
7969 ns_state=None,
7970 current_operation="IDLE",
7971 current_operation_id=None,
7972 )
7973 if exc:
aticig349aa462022-05-19 12:29:35 +03007974 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05307975 nslcmop_operation_state = "FAILED"
7976 else:
7977 nslcmop_operation_state = "COMPLETED"
7978 db_nslcmop_update["detailed-status"] = "Done"
7979 db_nsr_update["detailed-status"] = "Done"
7980
7981 self._write_op_status(
7982 op_id=nslcmop_id,
7983 stage="",
7984 error_message="",
7985 operation_state=nslcmop_operation_state,
7986 other_update=db_nslcmop_update,
7987 )
7988 if nslcmop_operation_state:
7989 try:
7990 msg = {
7991 "nsr_id": nsr_id,
7992 "nslcmop_id": nslcmop_id,
7993 "operationState": nslcmop_operation_state,
7994 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007995 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05307996 except Exception as e:
7997 self.logger.error(
7998 logging_text + "kafka_write notification Exception {}".format(e)
7999 )
8000 self.logger.debug(logging_text + "Exit")
8001 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008002
garciadeblas07f4e4c2022-06-09 09:42:58 +02008003 async def heal(self, nsr_id, nslcmop_id):
8004 """
8005 Heal NS
8006
8007 :param nsr_id: ns instance to heal
8008 :param nslcmop_id: operation to run
8009 :return:
8010 """
8011
8012 # Try to lock HA task here
8013 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8014 if not task_is_locked_by_me:
8015 return
8016
8017 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8018 stage = ["", "", ""]
8019 tasks_dict_info = {}
8020 # ^ stage, step, VIM progress
8021 self.logger.debug(logging_text + "Enter")
8022 # get all needed from database
8023 db_nsr = None
8024 db_nslcmop_update = {}
8025 db_nsr_update = {}
8026 db_vnfrs = {} # vnf's info indexed by _id
8027 exc = None
8028 old_operational_status = ""
8029 old_config_status = ""
8030 nsi_id = None
8031 try:
8032 # wait for any previous tasks in process
8033 step = "Waiting for previous operations to terminate"
8034 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8035 self._write_ns_status(
8036 nsr_id=nsr_id,
8037 ns_state=None,
8038 current_operation="HEALING",
8039 current_operation_id=nslcmop_id,
8040 )
8041
8042 step = "Getting nslcmop from database"
8043 self.logger.debug(
8044 step + " after having waited for previous tasks to be completed"
8045 )
8046 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8047
8048 step = "Getting nsr from database"
8049 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8050 old_operational_status = db_nsr["operational-status"]
8051 old_config_status = db_nsr["config-status"]
8052
8053 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008054 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008055 "_admin.deployed.RO.operational-status": "healing",
8056 }
8057 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8058
8059 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008060 await self.heal_RO(
8061 logging_text=logging_text,
8062 nsr_id=nsr_id,
8063 db_nslcmop=db_nslcmop,
8064 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008065 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008066 # VCA tasks
8067 # read from db: nsd
8068 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8069 self.logger.debug(logging_text + stage[1])
8070 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8071 self.fs.sync(db_nsr["nsd-id"])
8072 db_nsr["nsd"] = nsd
8073 # read from db: vnfr's of this ns
8074 step = "Getting vnfrs from db"
8075 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8076 for vnfr in db_vnfrs_list:
8077 db_vnfrs[vnfr["_id"]] = vnfr
8078 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8079
8080 # Check for each target VNF
8081 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8082 for target_vnf in target_list:
8083 # Find this VNF in the list from DB
8084 vnfr_id = target_vnf.get("vnfInstanceId", None)
8085 if vnfr_id:
8086 db_vnfr = db_vnfrs[vnfr_id]
8087 vnfd_id = db_vnfr.get("vnfd-id")
8088 vnfd_ref = db_vnfr.get("vnfd-ref")
8089 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8090 base_folder = vnfd["_admin"]["storage"]
8091 vdu_id = None
8092 vdu_index = 0
8093 vdu_name = None
8094 kdu_name = None
8095 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8096 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8097
8098 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008099 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8100 "vdu", []
8101 )
garciadeblas50639832022-09-01 13:09:47 +02008102 if not target_vdu_list:
8103 # Codigo nuevo para crear diccionario
8104 target_vdu_list = []
8105 for existing_vdu in db_vnfr.get("vdur"):
8106 vdu_name = existing_vdu.get("vdu-name", None)
8107 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008108 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8109 "run-day1", False
8110 )
8111 vdu_to_be_healed = {
8112 "vdu-id": vdu_name,
8113 "count-index": vdu_index,
8114 "run-day1": vdu_run_day1,
8115 }
garciadeblas50639832022-09-01 13:09:47 +02008116 target_vdu_list.append(vdu_to_be_healed)
8117 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008118 deploy_params_vdu = target_vdu
8119 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008120 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8121 "additionalParams", {}
8122 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008123 deploy_params_vdu["run-day1"] = target_vnf[
8124 "additionalParams"
8125 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008126 vdu_name = target_vdu.get("vdu-id", None)
8127 # TODO: Get vdu_id from vdud.
8128 vdu_id = vdu_name
8129 # For multi instance VDU count-index is mandatory
8130 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008131 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008132
8133 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8134 stage[1] = "Deploying Execution Environments."
8135 self.logger.debug(logging_text + stage[1])
8136
8137 # VNF Level charm. Normal case when proxy charms.
8138 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8139 descriptor_config = get_configuration(vnfd, vnfd_ref)
8140 if descriptor_config:
8141 # Continue if healed machine is management machine
8142 vnf_ip_address = db_vnfr.get("ip-address")
8143 target_instance = None
8144 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008145 if (
8146 instance["vdu-name"] == vdu_name
8147 and instance["count-index"] == vdu_index
8148 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008149 target_instance = instance
8150 break
8151 if vnf_ip_address == target_instance.get("ip-address"):
8152 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008153 logging_text=logging_text
8154 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8155 member_vnf_index, vdu_name, vdu_index
8156 ),
8157 db_nsr=db_nsr,
8158 db_vnfr=db_vnfr,
8159 nslcmop_id=nslcmop_id,
8160 nsr_id=nsr_id,
8161 nsi_id=nsi_id,
8162 vnfd_id=vnfd_ref,
8163 vdu_id=None,
8164 kdu_name=None,
8165 member_vnf_index=member_vnf_index,
8166 vdu_index=0,
8167 vdu_name=None,
8168 deploy_params=deploy_params_vdu,
8169 descriptor_config=descriptor_config,
8170 base_folder=base_folder,
8171 task_instantiation_info=tasks_dict_info,
8172 stage=stage,
8173 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008174
8175 # VDU Level charm. Normal case with native charms.
8176 descriptor_config = get_configuration(vnfd, vdu_name)
8177 if descriptor_config:
8178 self._heal_n2vc(
8179 logging_text=logging_text
8180 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8181 member_vnf_index, vdu_name, vdu_index
8182 ),
8183 db_nsr=db_nsr,
8184 db_vnfr=db_vnfr,
8185 nslcmop_id=nslcmop_id,
8186 nsr_id=nsr_id,
8187 nsi_id=nsi_id,
8188 vnfd_id=vnfd_ref,
8189 vdu_id=vdu_id,
8190 kdu_name=kdu_name,
8191 member_vnf_index=member_vnf_index,
8192 vdu_index=vdu_index,
8193 vdu_name=vdu_name,
8194 deploy_params=deploy_params_vdu,
8195 descriptor_config=descriptor_config,
8196 base_folder=base_folder,
8197 task_instantiation_info=tasks_dict_info,
8198 stage=stage,
8199 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008200 except (
8201 ROclient.ROClientException,
8202 DbException,
8203 LcmException,
8204 NgRoException,
8205 ) as e:
8206 self.logger.error(logging_text + "Exit Exception {}".format(e))
8207 exc = e
8208 except asyncio.CancelledError:
8209 self.logger.error(
8210 logging_text + "Cancelled Exception while '{}'".format(step)
8211 )
8212 exc = "Operation was cancelled"
8213 except Exception as e:
8214 exc = traceback.format_exc()
8215 self.logger.critical(
8216 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8217 exc_info=True,
8218 )
8219 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008220 error_list = list()
36970544ef442024-04-01 10:58:42 +00008221 if db_vnfrs_list and target_list:
8222 for vnfrs in db_vnfrs_list:
8223 for vnf_instance in target_list:
8224 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8225 self.db.set_list(
8226 "vnfrs",
8227 {"_id": vnfrs["_id"]},
8228 {"_admin.modified": time()},
8229 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008230 if exc:
8231 error_list.append(str(exc))
8232 try:
8233 if tasks_dict_info:
8234 stage[1] = "Waiting for healing pending tasks."
8235 self.logger.debug(logging_text + stage[1])
8236 exc = await self._wait_for_tasks(
8237 logging_text,
8238 tasks_dict_info,
8239 self.timeout.ns_deploy,
8240 stage,
8241 nslcmop_id,
8242 nsr_id=nsr_id,
8243 )
8244 except asyncio.CancelledError:
8245 error_list.append("Cancelled")
8246 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8247 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008248 logging_text,
8249 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008250 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008251 stage,
8252 nslcmop_id,
8253 nsr_id=nsr_id,
8254 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008255 if error_list:
8256 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008257 db_nslcmop_update[
8258 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008259 ] = error_description_nslcmop = "FAILED {}: {}".format(
8260 step, error_detail
8261 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008262 nslcmop_operation_state = "FAILED"
8263 if db_nsr:
8264 db_nsr_update["operational-status"] = old_operational_status
8265 db_nsr_update["config-status"] = old_config_status
8266 db_nsr_update[
8267 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008268 ] = "FAILED healing nslcmop={} {}: {}".format(
8269 nslcmop_id, step, error_detail
8270 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008271 for task, task_name in tasks_dict_info.items():
8272 if not task.done() or task.cancelled() or task.exception():
8273 if task_name.startswith(self.task_name_deploy_vca):
8274 # A N2VC task is pending
8275 db_nsr_update["config-status"] = "failed"
8276 else:
8277 # RO task is pending
8278 db_nsr_update["operational-status"] = "failed"
8279 else:
8280 error_description_nslcmop = None
8281 nslcmop_operation_state = "COMPLETED"
8282 db_nslcmop_update["detailed-status"] = "Done"
8283 db_nsr_update["detailed-status"] = "Done"
8284 db_nsr_update["operational-status"] = "running"
8285 db_nsr_update["config-status"] = "configured"
8286
8287 self._write_op_status(
8288 op_id=nslcmop_id,
8289 stage="",
8290 error_message=error_description_nslcmop,
8291 operation_state=nslcmop_operation_state,
8292 other_update=db_nslcmop_update,
8293 )
8294 if db_nsr:
8295 self._write_ns_status(
8296 nsr_id=nsr_id,
8297 ns_state=None,
8298 current_operation="IDLE",
8299 current_operation_id=None,
8300 other_update=db_nsr_update,
8301 )
8302
8303 if nslcmop_operation_state:
8304 try:
8305 msg = {
8306 "nsr_id": nsr_id,
8307 "nslcmop_id": nslcmop_id,
8308 "operationState": nslcmop_operation_state,
8309 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008310 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008311 except Exception as e:
8312 self.logger.error(
8313 logging_text + "kafka_write notification Exception {}".format(e)
8314 )
8315 self.logger.debug(logging_text + "Exit")
8316 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8317
8318 async def heal_RO(
8319 self,
8320 logging_text,
8321 nsr_id,
8322 db_nslcmop,
8323 stage,
8324 ):
8325 """
8326 Heal at RO
8327 :param logging_text: preffix text to use at logging
8328 :param nsr_id: nsr identity
8329 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8330 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8331 :return: None or exception
8332 """
preethika.p28b0bf82022-09-23 07:36:28 +00008333
garciadeblas07f4e4c2022-06-09 09:42:58 +02008334 def get_vim_account(vim_account_id):
8335 nonlocal db_vims
8336 if vim_account_id in db_vims:
8337 return db_vims[vim_account_id]
8338 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8339 db_vims[vim_account_id] = db_vim
8340 return db_vim
8341
8342 try:
8343 start_heal = time()
8344 ns_params = db_nslcmop.get("operationParams")
8345 if ns_params and ns_params.get("timeout_ns_heal"):
8346 timeout_ns_heal = ns_params["timeout_ns_heal"]
8347 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008348 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008349
8350 db_vims = {}
8351
8352 nslcmop_id = db_nslcmop["_id"]
8353 target = {
8354 "action_id": nslcmop_id,
8355 }
preethika.p28b0bf82022-09-23 07:36:28 +00008356 self.logger.warning(
8357 "db_nslcmop={} and timeout_ns_heal={}".format(
8358 db_nslcmop, timeout_ns_heal
8359 )
8360 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008361 target.update(db_nslcmop.get("operationParams", {}))
8362
8363 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8364 desc = await self.RO.recreate(nsr_id, target)
8365 self.logger.debug("RO return > {}".format(desc))
8366 action_id = desc["action_id"]
8367 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8368 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008369 nsr_id,
8370 action_id,
8371 nslcmop_id,
8372 start_heal,
8373 timeout_ns_heal,
8374 stage,
8375 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008376 )
8377
8378 # Updating NSR
8379 db_nsr_update = {
8380 "_admin.deployed.RO.operational-status": "running",
8381 "detailed-status": " ".join(stage),
8382 }
8383 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8384 self._write_op_status(nslcmop_id, stage)
8385 self.logger.debug(
8386 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8387 )
8388
8389 except Exception as e:
8390 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008391 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008392 self.logger.error(
8393 "Error healing at VIM {}".format(e),
8394 exc_info=not isinstance(
8395 e,
8396 (
8397 ROclient.ROClientException,
8398 LcmException,
8399 DbException,
8400 NgRoException,
8401 ),
8402 ),
8403 )
8404 raise
8405
8406 def _heal_n2vc(
8407 self,
8408 logging_text,
8409 db_nsr,
8410 db_vnfr,
8411 nslcmop_id,
8412 nsr_id,
8413 nsi_id,
8414 vnfd_id,
8415 vdu_id,
8416 kdu_name,
8417 member_vnf_index,
8418 vdu_index,
8419 vdu_name,
8420 deploy_params,
8421 descriptor_config,
8422 base_folder,
8423 task_instantiation_info,
8424 stage,
8425 ):
8426 # launch instantiate_N2VC in a asyncio task and register task object
8427 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8428 # if not found, create one entry and update database
8429 # fill db_nsr._admin.deployed.VCA.<index>
8430
8431 self.logger.debug(
8432 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8433 )
aticig9bc63ac2022-07-27 09:32:06 +03008434
8435 charm_name = ""
8436 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008437 if "execution-environment-list" in descriptor_config:
8438 ee_list = descriptor_config.get("execution-environment-list", [])
8439 elif "juju" in descriptor_config:
8440 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008441 if "execution-environment-list" not in descriptor_config:
8442 # charm name is only required for ns charms
8443 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008444 else: # other types as script are not supported
8445 ee_list = []
8446
8447 for ee_item in ee_list:
8448 self.logger.debug(
8449 logging_text
8450 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8451 ee_item.get("juju"), ee_item.get("helm-chart")
8452 )
8453 )
8454 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008455 vca_name, charm_name, vca_type = self.get_vca_info(
8456 ee_item, db_nsr, get_charm_name
8457 )
8458 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008459 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008460 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008461 )
8462 continue
8463
8464 vca_index = -1
8465 for vca_index, vca_deployed in enumerate(
8466 db_nsr["_admin"]["deployed"]["VCA"]
8467 ):
8468 if not vca_deployed:
8469 continue
8470 if (
8471 vca_deployed.get("member-vnf-index") == member_vnf_index
8472 and vca_deployed.get("vdu_id") == vdu_id
8473 and vca_deployed.get("kdu_name") == kdu_name
8474 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8475 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8476 ):
8477 break
8478 else:
8479 # not found, create one.
8480 target = (
8481 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8482 )
8483 if vdu_id:
8484 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8485 elif kdu_name:
8486 target += "/kdu/{}".format(kdu_name)
8487 vca_deployed = {
8488 "target_element": target,
8489 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8490 "member-vnf-index": member_vnf_index,
8491 "vdu_id": vdu_id,
8492 "kdu_name": kdu_name,
8493 "vdu_count_index": vdu_index,
8494 "operational-status": "init", # TODO revise
8495 "detailed-status": "", # TODO revise
8496 "step": "initial-deploy", # TODO revise
8497 "vnfd_id": vnfd_id,
8498 "vdu_name": vdu_name,
8499 "type": vca_type,
8500 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008501 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008502 }
8503 vca_index += 1
8504
8505 # create VCA and configurationStatus in db
8506 db_dict = {
8507 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8508 "configurationStatus.{}".format(vca_index): dict(),
8509 }
8510 self.update_db_2("nsrs", nsr_id, db_dict)
8511
8512 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8513
8514 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8515 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8516 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8517
8518 # Launch task
8519 task_n2vc = asyncio.ensure_future(
8520 self.heal_N2VC(
8521 logging_text=logging_text,
8522 vca_index=vca_index,
8523 nsi_id=nsi_id,
8524 db_nsr=db_nsr,
8525 db_vnfr=db_vnfr,
8526 vdu_id=vdu_id,
8527 kdu_name=kdu_name,
8528 vdu_index=vdu_index,
8529 deploy_params=deploy_params,
8530 config_descriptor=descriptor_config,
8531 base_folder=base_folder,
8532 nslcmop_id=nslcmop_id,
8533 stage=stage,
8534 vca_type=vca_type,
8535 vca_name=vca_name,
8536 ee_config_descriptor=ee_item,
8537 )
8538 )
8539 self.lcm_tasks.register(
8540 "ns",
8541 nsr_id,
8542 nslcmop_id,
8543 "instantiate_N2VC-{}".format(vca_index),
8544 task_n2vc,
8545 )
8546 task_instantiation_info[
8547 task_n2vc
8548 ] = self.task_name_deploy_vca + " {}.{}".format(
8549 member_vnf_index or "", vdu_id or ""
8550 )
8551
8552 async def heal_N2VC(
8553 self,
8554 logging_text,
8555 vca_index,
8556 nsi_id,
8557 db_nsr,
8558 db_vnfr,
8559 vdu_id,
8560 kdu_name,
8561 vdu_index,
8562 config_descriptor,
8563 deploy_params,
8564 base_folder,
8565 nslcmop_id,
8566 stage,
8567 vca_type,
8568 vca_name,
8569 ee_config_descriptor,
8570 ):
8571 nsr_id = db_nsr["_id"]
8572 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8573 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8574 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8575 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8576 db_dict = {
8577 "collection": "nsrs",
8578 "filter": {"_id": nsr_id},
8579 "path": db_update_entry,
8580 }
8581 step = ""
8582 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008583 element_type = "NS"
8584 element_under_configuration = nsr_id
8585
8586 vnfr_id = None
8587 if db_vnfr:
8588 vnfr_id = db_vnfr["_id"]
8589 osm_config["osm"]["vnf_id"] = vnfr_id
8590
8591 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8592
8593 if vca_type == "native_charm":
8594 index_number = 0
8595 else:
8596 index_number = vdu_index or 0
8597
8598 if vnfr_id:
8599 element_type = "VNF"
8600 element_under_configuration = vnfr_id
8601 namespace += ".{}-{}".format(vnfr_id, index_number)
8602 if vdu_id:
8603 namespace += ".{}-{}".format(vdu_id, index_number)
8604 element_type = "VDU"
8605 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8606 osm_config["osm"]["vdu_id"] = vdu_id
8607 elif kdu_name:
8608 namespace += ".{}".format(kdu_name)
8609 element_type = "KDU"
8610 element_under_configuration = kdu_name
8611 osm_config["osm"]["kdu_name"] = kdu_name
8612
8613 # Get artifact path
8614 if base_folder["pkg-dir"]:
8615 artifact_path = "{}/{}/{}/{}".format(
8616 base_folder["folder"],
8617 base_folder["pkg-dir"],
8618 "charms"
8619 if vca_type
8620 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8621 else "helm-charts",
8622 vca_name,
8623 )
8624 else:
8625 artifact_path = "{}/Scripts/{}/{}/".format(
8626 base_folder["folder"],
8627 "charms"
8628 if vca_type
8629 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8630 else "helm-charts",
8631 vca_name,
8632 )
8633
8634 self.logger.debug("Artifact path > {}".format(artifact_path))
8635
8636 # get initial_config_primitive_list that applies to this element
8637 initial_config_primitive_list = config_descriptor.get(
8638 "initial-config-primitive"
8639 )
8640
8641 self.logger.debug(
8642 "Initial config primitive list > {}".format(
8643 initial_config_primitive_list
8644 )
8645 )
8646
8647 # add config if not present for NS charm
8648 ee_descriptor_id = ee_config_descriptor.get("id")
8649 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8650 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8651 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8652 )
8653
8654 self.logger.debug(
8655 "Initial config primitive list #2 > {}".format(
8656 initial_config_primitive_list
8657 )
8658 )
8659 # n2vc_redesign STEP 3.1
8660 # find old ee_id if exists
8661 ee_id = vca_deployed.get("ee_id")
8662
8663 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8664 # create or register execution environment in VCA. Only for native charms when healing
8665 if vca_type == "native_charm":
8666 step = "Waiting to VM being up and getting IP address"
8667 self.logger.debug(logging_text + step)
8668 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8669 logging_text,
8670 nsr_id,
8671 vnfr_id,
8672 vdu_id,
8673 vdu_index,
8674 user=None,
8675 pub_key=None,
8676 )
8677 credentials = {"hostname": rw_mgmt_ip}
8678 # get username
8679 username = deep_get(
8680 config_descriptor, ("config-access", "ssh-access", "default-user")
8681 )
8682 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8683 # merged. Meanwhile let's get username from initial-config-primitive
8684 if not username and initial_config_primitive_list:
8685 for config_primitive in initial_config_primitive_list:
8686 for param in config_primitive.get("parameter", ()):
8687 if param["name"] == "ssh-username":
8688 username = param["value"]
8689 break
8690 if not username:
8691 raise LcmException(
8692 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8693 "'config-access.ssh-access.default-user'"
8694 )
8695 credentials["username"] = username
8696
8697 # n2vc_redesign STEP 3.2
8698 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8699 self._write_configuration_status(
8700 nsr_id=nsr_id,
8701 vca_index=vca_index,
8702 status="REGISTERING",
8703 element_under_configuration=element_under_configuration,
8704 element_type=element_type,
8705 )
8706
8707 step = "register execution environment {}".format(credentials)
8708 self.logger.debug(logging_text + step)
8709 ee_id = await self.vca_map[vca_type].register_execution_environment(
8710 credentials=credentials,
8711 namespace=namespace,
8712 db_dict=db_dict,
8713 vca_id=vca_id,
8714 )
8715
8716 # update ee_id en db
8717 db_dict_ee_id = {
8718 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8719 }
8720 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8721
8722 # for compatibility with MON/POL modules, the need model and application name at database
8723 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8724 # Not sure if this need to be done when healing
8725 """
8726 ee_id_parts = ee_id.split(".")
8727 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8728 if len(ee_id_parts) >= 2:
8729 model_name = ee_id_parts[0]
8730 application_name = ee_id_parts[1]
8731 db_nsr_update[db_update_entry + "model"] = model_name
8732 db_nsr_update[db_update_entry + "application"] = application_name
8733 """
8734
8735 # n2vc_redesign STEP 3.3
8736 # Install configuration software. Only for native charms.
8737 step = "Install configuration Software"
8738
8739 self._write_configuration_status(
8740 nsr_id=nsr_id,
8741 vca_index=vca_index,
8742 status="INSTALLING SW",
8743 element_under_configuration=element_under_configuration,
8744 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008745 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008746 other_update=None,
8747 )
8748
8749 # TODO check if already done
8750 self.logger.debug(logging_text + step)
8751 config = None
8752 if vca_type == "native_charm":
8753 config_primitive = next(
8754 (p for p in initial_config_primitive_list if p["name"] == "config"),
8755 None,
8756 )
8757 if config_primitive:
8758 config = self._map_primitive_params(
8759 config_primitive, {}, deploy_params
8760 )
8761 await self.vca_map[vca_type].install_configuration_sw(
8762 ee_id=ee_id,
8763 artifact_path=artifact_path,
8764 db_dict=db_dict,
8765 config=config,
8766 num_units=1,
8767 vca_id=vca_id,
8768 vca_type=vca_type,
8769 )
8770
8771 # write in db flag of configuration_sw already installed
8772 self.update_db_2(
8773 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8774 )
8775
8776 # Not sure if this need to be done when healing
8777 """
8778 # add relations for this VCA (wait for other peers related with this VCA)
8779 await self._add_vca_relations(
8780 logging_text=logging_text,
8781 nsr_id=nsr_id,
8782 vca_type=vca_type,
8783 vca_index=vca_index,
8784 )
8785 """
8786
8787 # if SSH access is required, then get execution environment SSH public
8788 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00008789 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008790 pub_key = None
8791 user = None
8792 # self.logger.debug("get ssh key block")
8793 if deep_get(
8794 config_descriptor, ("config-access", "ssh-access", "required")
8795 ):
8796 # self.logger.debug("ssh key needed")
8797 # Needed to inject a ssh key
8798 user = deep_get(
8799 config_descriptor,
8800 ("config-access", "ssh-access", "default-user"),
8801 )
8802 step = "Install configuration Software, getting public ssh key"
8803 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8804 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8805 )
8806
8807 step = "Insert public key into VM user={} ssh_key={}".format(
8808 user, pub_key
8809 )
8810 else:
8811 # self.logger.debug("no need to get ssh key")
8812 step = "Waiting to VM being up and getting IP address"
8813 self.logger.debug(logging_text + step)
8814
8815 # n2vc_redesign STEP 5.1
8816 # wait for RO (ip-address) Insert pub_key into VM
8817 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008818 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008819 if vnfr_id:
8820 if kdu_name:
8821 rw_mgmt_ip = await self.wait_kdu_up(
8822 logging_text, nsr_id, vnfr_id, kdu_name
8823 )
8824 else:
8825 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8826 logging_text,
8827 nsr_id,
8828 vnfr_id,
8829 vdu_id,
8830 vdu_index,
8831 user=user,
8832 pub_key=pub_key,
8833 )
8834 else:
8835 rw_mgmt_ip = None # This is for a NS configuration
8836
8837 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8838
8839 # store rw_mgmt_ip in deploy params for later replacement
8840 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8841
8842 # Day1 operations.
8843 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008844 runDay1 = deploy_params.get("run-day1", False)
8845 self.logger.debug(
8846 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8847 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008848 if runDay1:
8849 # n2vc_redesign STEP 6 Execute initial config primitive
8850 step = "execute initial config primitive"
8851
8852 # wait for dependent primitives execution (NS -> VNF -> VDU)
8853 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008854 await self._wait_dependent_n2vc(
8855 nsr_id, vca_deployed_list, vca_index
8856 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008857
8858 # stage, in function of element type: vdu, kdu, vnf or ns
8859 my_vca = vca_deployed_list[vca_index]
8860 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8861 # VDU or KDU
8862 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8863 elif my_vca.get("member-vnf-index"):
8864 # VNF
8865 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8866 else:
8867 # NS
8868 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8869
8870 self._write_configuration_status(
8871 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8872 )
8873
8874 self._write_op_status(op_id=nslcmop_id, stage=stage)
8875
8876 check_if_terminated_needed = True
8877 for initial_config_primitive in initial_config_primitive_list:
8878 # adding information on the vca_deployed if it is a NS execution environment
8879 if not vca_deployed["member-vnf-index"]:
8880 deploy_params["ns_config_info"] = json.dumps(
8881 self._get_ns_config_info(nsr_id)
8882 )
8883 # TODO check if already done
8884 primitive_params_ = self._map_primitive_params(
8885 initial_config_primitive, {}, deploy_params
8886 )
8887
8888 step = "execute primitive '{}' params '{}'".format(
8889 initial_config_primitive["name"], primitive_params_
8890 )
8891 self.logger.debug(logging_text + step)
8892 await self.vca_map[vca_type].exec_primitive(
8893 ee_id=ee_id,
8894 primitive_name=initial_config_primitive["name"],
8895 params_dict=primitive_params_,
8896 db_dict=db_dict,
8897 vca_id=vca_id,
8898 vca_type=vca_type,
8899 )
8900 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8901 if check_if_terminated_needed:
8902 if config_descriptor.get("terminate-config-primitive"):
8903 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008904 "nsrs",
8905 nsr_id,
8906 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008907 )
8908 check_if_terminated_needed = False
8909
8910 # TODO register in database that primitive is done
8911
8912 # STEP 7 Configure metrics
8913 # Not sure if this need to be done when healing
8914 """
8915 if vca_type == "helm" or vca_type == "helm-v3":
8916 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8917 ee_id=ee_id,
8918 artifact_path=artifact_path,
8919 ee_config_descriptor=ee_config_descriptor,
8920 vnfr_id=vnfr_id,
8921 nsr_id=nsr_id,
8922 target_ip=rw_mgmt_ip,
8923 )
8924 if prometheus_jobs:
8925 self.update_db_2(
8926 "nsrs",
8927 nsr_id,
8928 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8929 )
8930
8931 for job in prometheus_jobs:
8932 self.db.set_one(
8933 "prometheus_jobs",
8934 {"job_name": job["job_name"]},
8935 job,
8936 upsert=True,
8937 fail_on_empty=False,
8938 )
8939
8940 """
8941 step = "instantiated at VCA"
8942 self.logger.debug(logging_text + step)
8943
8944 self._write_configuration_status(
8945 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8946 )
8947
8948 except Exception as e: # TODO not use Exception but N2VC exception
8949 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8950 if not isinstance(
8951 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8952 ):
8953 self.logger.error(
8954 "Exception while {} : {}".format(step, e), exc_info=True
8955 )
8956 self._write_configuration_status(
8957 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8958 )
8959 raise LcmException("{} {}".format(step, e)) from e
8960
8961 async def _wait_heal_ro(
8962 self,
8963 nsr_id,
8964 timeout=600,
8965 ):
8966 start_time = time()
8967 while time() <= start_time + timeout:
8968 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00008969 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
8970 "operational-status"
8971 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02008972 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
8973 if operational_status_ro != "healing":
8974 break
Gabriel Cubae7898982023-05-11 01:57:21 -05008975 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008976 else: # timeout_ns_deploy
8977 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05308978
8979 async def vertical_scale(self, nsr_id, nslcmop_id):
8980 """
8981 Vertical Scale the VDUs in a NS
8982
8983 :param: nsr_id: NS Instance ID
8984 :param: nslcmop_id: nslcmop ID of migrate
8985
8986 """
govindarajul4ff4b512022-05-02 20:02:41 +05308987 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05308988 self.logger.info(logging_text + "Enter")
8989 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05308990 # get all needed from database
8991 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05308992 db_nsr_update = {}
8993 target = {}
8994 exc = None
8995 # in case of error, indicates what part of scale was failed to put nsr at error status
8996 start_deploy = time()
8997
8998 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05308999 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9000 operationParams = db_nslcmop.get("operationParams")
9001 vertical_scale_data = operationParams["verticalScaleVnf"]
9002 vnfd_id = vertical_scale_data["vnfdId"]
9003 count_index = vertical_scale_data["countIndex"]
9004 vdu_id_ref = vertical_scale_data["vduId"]
9005 vnfr_id = vertical_scale_data["vnfInstanceId"]
9006 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9007 db_flavor = db_nsr.get("flavor")
9008 db_flavor_index = str(len(db_flavor))
9009
9010 def set_flavor_refrence_to_vdur(diff=0):
9011 """
9012 Utility function to add and remove the
9013 ref to new ns-flavor-id to vdurs
9014 :param: diff: default 0
9015 """
9016 q_filter = {}
9017 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9018 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9019 if (
9020 vdur.get("count-index") == count_index
9021 and vdur.get("vdu-id-ref") == vdu_id_ref
9022 ):
9023 filter_text = {
9024 "_id": vnfr_id,
9025 "vdur.count-index": count_index,
9026 "vdur.vdu-id-ref": vdu_id_ref,
9027 }
9028 q_filter.update(filter_text)
9029 db_update = {}
9030 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9031 int(db_flavor_index) - diff
9032 )
9033 self.db.set_one(
9034 "vnfrs",
9035 q_filter=q_filter,
9036 update_dict=db_update,
9037 fail_on_empty=True,
9038 )
9039
govindarajul4ff4b512022-05-02 20:02:41 +05309040 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309041 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009042 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309043
9044 self._write_ns_status(
9045 nsr_id=nsr_id,
9046 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309047 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009048 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309049 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309050 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009051 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309052 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009053 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309054 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9055 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9056 virtual_compute = vnfd["virtual-compute-desc"][0]
9057 virtual_memory = round(
9058 float(virtual_compute["virtual-memory"]["size"]) * 1024
9059 )
9060 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9061 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009062 flavor_dict_update = {
9063 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309064 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009065 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309066 "storage-gb": str(virtual_storage),
9067 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009068 }
9069 db_flavor.append(flavor_dict_update)
9070 db_update = {}
9071 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309072 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009073 "_id": nsr_id,
9074 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309075 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009076 self.db.set_one(
9077 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309078 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009079 update_dict=db_update,
9080 fail_on_empty=True,
9081 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309082 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309083 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309084 new_operationParams = {
9085 "lcmOperationType": "verticalscale",
9086 "verticalScale": "CHANGE_VNFFLAVOR",
9087 "nsInstanceId": nsr_id,
9088 "changeVnfFlavorData": {
9089 "vnfInstanceId": vnfr_id,
9090 "additionalParams": {
9091 "vduid": vdu_id_ref,
9092 "vduCountIndex": count_index,
9093 "virtualMemory": virtual_memory,
9094 "numVirtualCpu": int(virtual_cpu),
9095 "sizeOfStorage": int(virtual_storage),
9096 },
9097 },
9098 }
9099 target.update(new_operationParams)
9100
9101 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9102 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9103 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309104 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309105 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309106 action_id = desc["action_id"]
9107 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009108 nsr_id,
9109 action_id,
9110 nslcmop_id,
9111 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009112 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009113 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309114 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009115 except (
9116 NgRoException,
9117 ROclient.ROClientException,
9118 DbException,
9119 LcmException,
9120 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309121 self.logger.error("Exit Exception {}".format(e))
9122 exc = e
9123 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309124 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309125 exc = "Operation was cancelled"
9126 except Exception as e:
9127 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009128 self.logger.critical(
9129 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9130 )
govindarajul4ff4b512022-05-02 20:02:41 +05309131 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309132 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009133 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309134 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009135 )
9136 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309137 "nsrs",
9138 {"_id": nsr_id},
9139 None,
9140 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009141 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309142 set_flavor_refrence_to_vdur(diff=1)
9143 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9144 else:
9145 return "COMPLETED", "Done"