blob: 9427fa05e131179cf80877fdad57c819db8ad7eb [file] [log] [blame]
tierno59d22d22018-09-25 18:10:19 +02001# -*- coding: utf-8 -*-
2
tierno2e215512018-11-28 09:37:52 +00003##
4# Copyright 2018 Telefonica S.A.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17##
18
tierno59d22d22018-09-25 18:10:19 +020019import asyncio
aticigdffa6212022-04-12 15:27:53 +030020import shutil
David Garcia444bf962021-11-11 16:35:26 +010021from typing import Any, Dict, List
tierno59d22d22018-09-25 18:10:19 +020022import yaml
23import logging
24import logging.handlers
tierno59d22d22018-09-25 18:10:19 +020025import traceback
rahul72d90d92023-08-30 14:48:01 +053026import ipaddress
David Garciad4816682019-12-09 14:57:43 +010027import json
garciadeblas5697b8b2021-03-24 09:17:02 +010028from jinja2 import (
29 Environment,
30 TemplateError,
31 TemplateNotFound,
32 StrictUndefined,
33 UndefinedError,
garciadeblasef91e082022-08-02 15:12:18 +020034 select_autoescape,
garciadeblas5697b8b2021-03-24 09:17:02 +010035)
tierno59d22d22018-09-25 18:10:19 +020036
tierno77677d92019-08-22 13:46:35 +000037from osm_lcm import ROclient
Luis Vegaa27dc532022-11-11 20:10:49 +000038from osm_lcm.data_utils.lcm_config import LcmCfg
David Garciab4ebcd02021-10-28 02:00:43 +020039from osm_lcm.data_utils.nsr import (
40 get_deployed_kdu,
41 get_deployed_vca,
42 get_deployed_vca_list,
43 get_nsd,
44)
45from osm_lcm.data_utils.vca import (
46 DeployedComponent,
47 DeployedK8sResource,
48 DeployedVCA,
49 EELevel,
50 Relation,
51 EERelation,
52 safe_get_ee_relation,
53)
tierno69f0d382020-05-07 13:08:09 +000054from osm_lcm.ng_ro import NgRoClient, NgRoException
garciadeblas5697b8b2021-03-24 09:17:02 +010055from osm_lcm.lcm_utils import (
56 LcmException,
garciadeblas5697b8b2021-03-24 09:17:02 +010057 LcmBase,
58 deep_get,
59 get_iterable,
60 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030061 check_juju_bundle_existence,
62 get_charm_artifact_path,
Gabriel Cubae539a8d2022-10-10 11:34:51 -050063 get_ee_id_parts,
Gabriel Cubac7737442023-02-14 13:09:18 -050064 vld_to_ro_ip_profile,
garciadeblas5697b8b2021-03-24 09:17:02 +010065)
David Garciab4ebcd02021-10-28 02:00:43 +020066from osm_lcm.data_utils.nsd import (
67 get_ns_configuration_relation_list,
68 get_vnf_profile,
69 get_vnf_profiles,
70)
garciadeblas5697b8b2021-03-24 09:17:02 +010071from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020072 get_kdu,
73 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020074 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010075 get_vdu_list,
76 get_vdu_profile,
77 get_ee_sorted_initial_config_primitive_list,
78 get_ee_sorted_terminate_config_primitive_list,
79 get_kdu_list,
80 get_virtual_link_profiles,
81 get_vdu,
82 get_configuration,
83 get_vdu_index,
84 get_scaling_aspect,
85 get_number_of_instances,
86 get_juju_ee_ref,
jegan99448902024-12-06 07:19:34 +000087 get_helm_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020088 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030089 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050090 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010091)
bravof922c4172020-11-24 21:21:43 -030092from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030093from osm_lcm.data_utils.vnfr import (
94 get_osm_params,
95 get_vdur_index,
96 get_kdur,
97 get_volumes_from_instantiation_params,
98)
bravof922c4172020-11-24 21:21:43 -030099from osm_lcm.data_utils.dict_utils import parse_yaml_strings
100from osm_lcm.data_utils.database.vim_account import VimAccountDB
almagiacdd20ae2024-12-13 09:45:45 +0100101from osm_lcm.n2vc.definitions import RelationEndpoint
102from osm_lcm.n2vc.k8s_helm3_conn import K8sHelm3Connector
103from osm_lcm.n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200104
tierno27246d82018-09-27 15:59:09 +0200105from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200106from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200107
bravof922c4172020-11-24 21:21:43 -0300108from osm_lcm.data_utils.database.database import Database
109from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000110from osm_lcm.data_utils.wim import (
111 get_sdn_ports,
112 get_target_wim_attrs,
113 select_feasible_wim_account,
114)
bravof922c4172020-11-24 21:21:43 -0300115
almagiacdd20ae2024-12-13 09:45:45 +0100116from osm_lcm.n2vc.n2vc_juju_conn import N2VCJujuConnector
117from osm_lcm.n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200118
tierno588547c2020-07-01 15:30:20 +0000119from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200120from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400121from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000122
tierno27246d82018-09-27 15:59:09 +0200123from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200124from time import time
tierno27246d82018-09-27 15:59:09 +0200125from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000126
k4.rahulcf47a3b2023-04-27 12:08:48 +0530127from random import SystemRandom
tierno59d22d22018-09-25 18:10:19 +0200128
tierno69f0d382020-05-07 13:08:09 +0000129__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200130
131
132class NsLcm(LcmBase):
kuuseac3a8882019-10-03 10:48:06 +0200133 SUBOPERATION_STATUS_NOT_FOUND = -1
134 SUBOPERATION_STATUS_NEW = -2
135 SUBOPERATION_STATUS_SKIP = -3
Gabriel Cubaeb585dd2023-04-25 16:48:41 -0500136 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000137 task_name_deploy_vca = "Deploying VCA"
garciadeblas9148fa82023-05-30 12:51:14 +0200138 rel_operation_types = {
139 "GE": ">=",
140 "LE": "<=",
141 "GT": ">",
142 "LT": "<",
143 "EQ": "==",
144 "NE": "!=",
145 }
kuuseac3a8882019-10-03 10:48:06 +0200146
Gabriel Cubae7898982023-05-11 01:57:21 -0500147 def __init__(self, msg, lcm_tasks, config: LcmCfg):
tierno59d22d22018-09-25 18:10:19 +0200148 """
149 Init, Connect to database, filesystem storage, and messaging
150 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
151 :return: None
152 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100153 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200154
bravof922c4172020-11-24 21:21:43 -0300155 self.db = Database().instance.db
156 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200157 self.lcm_tasks = lcm_tasks
Luis Vegaa27dc532022-11-11 20:10:49 +0000158 self.timeout = config.timeout
159 self.ro_config = config.RO
160 self.vca_config = config.VCA
Rahul Kumar54671c52024-05-09 15:34:01 +0530161 self.service_kpi = config.servicekpi
tierno59d22d22018-09-25 18:10:19 +0200162
quilesj7e13aeb2019-10-08 13:34:55 +0200163 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100164 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200165 log=self.logger,
bravof922c4172020-11-24 21:21:43 -0300166 on_update_db=self._on_update_n2vc_db,
167 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100168 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200169 )
quilesj7e13aeb2019-10-08 13:34:55 +0200170
tierno588547c2020-07-01 15:30:20 +0000171 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000172 log=self.logger,
tierno588547c2020-07-01 15:30:20 +0000173 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100174 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000175 )
176
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000177 self.k8sclusterhelm3 = K8sHelm3Connector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000178 kubectl_command=self.vca_config.kubectlpath,
179 helm_command=self.vca_config.helm3path,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000180 fs=self.fs,
181 log=self.logger,
182 db=self.db,
183 on_update_db=None,
184 )
185
Adam Israelbaacc302019-12-01 12:41:39 -0500186 self.k8sclusterjuju = K8sJujuConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000187 kubectl_command=self.vca_config.kubectlpath,
188 juju_command=self.vca_config.jujupath,
Adam Israelbaacc302019-12-01 12:41:39 -0500189 log=self.logger,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530190 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300191 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100192 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500193 )
194
tiernoa2143262020-03-27 16:20:40 +0000195 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000196 "helm-chart-v3": self.k8sclusterhelm3,
197 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000198 "juju-bundle": self.k8sclusterjuju,
199 "juju": self.k8sclusterjuju,
200 }
tierno588547c2020-07-01 15:30:20 +0000201
202 self.vca_map = {
203 "lxc_proxy_charm": self.n2vc,
204 "native_charm": self.n2vc,
205 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000206 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100207 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000208 }
209
quilesj7e13aeb2019-10-08 13:34:55 +0200210 # create RO client
Gabriel Cubae7898982023-05-11 01:57:21 -0500211 self.RO = NgRoClient(**self.ro_config.to_dict())
tierno59d22d22018-09-25 18:10:19 +0200212
garciadeblas07f4e4c2022-06-09 09:42:58 +0200213 self.op_status_map = {
214 "instantiation": self.RO.status,
215 "termination": self.RO.status,
216 "migrate": self.RO.status,
217 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000218 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000219 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200220 }
221
tierno2357f4e2020-10-19 16:38:59 +0000222 @staticmethod
223 def increment_ip_mac(ip_mac, vm_index=1):
224 if not isinstance(ip_mac, str):
225 return ip_mac
226 try:
rahul72d90d92023-08-30 14:48:01 +0530227 next_ipv6 = None
228 next_ipv4 = None
229 dual_ip = ip_mac.split(";")
230 if len(dual_ip) == 2:
231 for ip in dual_ip:
232 if ipaddress.ip_address(ip).version == 6:
233 ipv6 = ipaddress.IPv6Address(ip)
234 next_ipv6 = str(ipaddress.IPv6Address(int(ipv6) + 1))
235 elif ipaddress.ip_address(ip).version == 4:
236 ipv4 = ipaddress.IPv4Address(ip)
237 next_ipv4 = str(ipaddress.IPv4Address(int(ipv4) + 1))
238 return [next_ipv4, next_ipv6]
tierno2357f4e2020-10-19 16:38:59 +0000239 # try with ipv4 look for last dot
240 i = ip_mac.rfind(".")
241 if i > 0:
242 i += 1
243 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
244 # try with ipv6 or mac look for last colon. Operate in hex
245 i = ip_mac.rfind(":")
246 if i > 0:
247 i += 1
248 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100249 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
250 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
251 )
tierno2357f4e2020-10-19 16:38:59 +0000252 except Exception:
253 pass
254 return None
255
David Garciac1fe90a2021-03-31 19:12:02 +0200256 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000257 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100258 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000259 path = path[:-1]
260
quilesj3655ae02019-12-12 16:08:35 +0000261 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
262 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000263 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100264 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000265
266 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100267 nsr = self.db.get_one(table="nsrs", q_filter=filter)
268 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000269
3697083243632024-06-07 05:44:08 +0000270 # First, we need to verify if the current vcaStatus is null, because if that is the case,
271 # MongoDB will not be able to create the fields used within the update key in the database
272 if not nsr.get("vcaStatus"):
273 # Write an empty dictionary to the vcaStatus field, it its value is null
274 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
275
276 # Get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100277 status_dict = await self.n2vc.get_status(
278 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
279 )
quilesj3655ae02019-12-12 16:08:35 +0000280
3697083243632024-06-07 05:44:08 +0000281 # Update the vcaStatus
282 db_key = f"vcaStatus.{nsr_id}.VNF"
quilesj3655ae02019-12-12 16:08:35 +0000283 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000284
285 db_dict[db_key] = status_dict[nsr_id]
286 await self.n2vc.update_vca_status(db_dict[db_key], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000287
288 # update configurationStatus for this VCA
289 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100290 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000291
garciadeblas5697b8b2021-03-24 09:17:02 +0100292 vca_list = deep_get(
293 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
294 )
295 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000296
garciadeblas5697b8b2021-03-24 09:17:02 +0100297 configuration_status_list = nsr.get("configurationStatus")
298 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000299
garciadeblas5697b8b2021-03-24 09:17:02 +0100300 if config_status == "BROKEN" and vca_status != "failed":
301 db_dict["configurationStatus"][vca_index] = "READY"
302 elif config_status != "BROKEN" and vca_status == "failed":
303 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000304 except Exception as e:
305 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100306 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000307
308 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
309 # if nsState = 'DEGRADED' check if all is OK
310 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100311 if current_ns_status in ("READY", "DEGRADED"):
312 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000313 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100314 if status_dict.get("machines"):
315 for machine_id in status_dict.get("machines"):
316 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000317 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100318 if machine.get("agent-status"):
319 s = machine.get("agent-status").get("status")
320 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000321 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100322 error_description += (
323 "machine {} agent-status={} ; ".format(
324 machine_id, s
325 )
326 )
quilesj3655ae02019-12-12 16:08:35 +0000327 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100328 if machine.get("instance-status"):
329 s = machine.get("instance-status").get("status")
330 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000331 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100332 error_description += (
333 "machine {} instance-status={} ; ".format(
334 machine_id, s
335 )
336 )
quilesj3655ae02019-12-12 16:08:35 +0000337 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100338 if status_dict.get("applications"):
339 for app_id in status_dict.get("applications"):
340 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000341 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100342 if app.get("status"):
343 s = app.get("status").get("status")
344 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000345 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100346 error_description += (
347 "application {} status={} ; ".format(app_id, s)
348 )
quilesj3655ae02019-12-12 16:08:35 +0000349
350 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100351 db_dict["errorDescription"] = error_description
352 if current_ns_status == "READY" and is_degraded:
353 db_dict["nsState"] = "DEGRADED"
354 if current_ns_status == "DEGRADED" and not is_degraded:
355 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000356
357 # write to database
358 self.update_db_2("nsrs", nsr_id, db_dict)
359
tierno51183952020-04-03 15:48:18 +0000360 except (asyncio.CancelledError, asyncio.TimeoutError):
361 raise
quilesj3655ae02019-12-12 16:08:35 +0000362 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100363 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200364
garciadeblas5697b8b2021-03-24 09:17:02 +0100365 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100366 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100367 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530368 """
369 Updating vca status in NSR record
370 :param cluster_uuid: UUID of a k8s cluster
371 :param kdu_instance: The unique name of the KDU instance
372 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100373 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530374 :return: none
375 """
376
377 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
378 # .format(cluster_uuid, kdu_instance, filter))
379
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100380 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530381 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100382 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
383 cluster_uuid=cluster_uuid,
384 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200385 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100386 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200387 vca_id=vca_id,
388 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100389
3697083243632024-06-07 05:44:08 +0000390 # First, we need to verify if the current vcaStatus is null, because if that is the case,
391 # MongoDB will not be able to create the fields used within the update key in the database
392 nsr = self.db.get_one(table="nsrs", q_filter=filter)
393 if not nsr.get("vcaStatus"):
394 # Write an empty dictionary to the vcaStatus field, it its value is null
395 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
396
397 # Update the vcaStatus
398 db_key = f"vcaStatus.{nsr_id}.KNF"
ksaikiranr656b6dd2021-02-19 10:25:18 +0530399 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000400
401 db_dict[db_key] = vca_status
402
403 if cluster_type in ("juju-bundle", "juju"):
404 # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA
405 # status in a similar way between Juju Bundles and Helm Charts on this side
406 await self.k8sclusterjuju.update_vca_status(
407 db_dict[db_key],
408 kdu_instance,
409 vca_id=vca_id,
410 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530411
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100412 self.logger.debug(
413 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200414 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530415
416 # write to database
417 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530418 except (asyncio.CancelledError, asyncio.TimeoutError):
419 raise
420 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100421 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530422
tierno72ef84f2020-10-06 08:22:07 +0000423 @staticmethod
424 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
425 try:
garciadeblasef91e082022-08-02 15:12:18 +0200426 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000427 undefined=StrictUndefined,
428 autoescape=select_autoescape(default_for_string=True, default=True),
429 )
tierno72ef84f2020-10-06 08:22:07 +0000430 template = env.from_string(cloud_init_text)
431 return template.render(additional_params or {})
432 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100433 raise LcmException(
434 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
435 "file, must be provided in the instantiation parameters inside the "
436 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
437 )
tierno72ef84f2020-10-06 08:22:07 +0000438 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100439 raise LcmException(
440 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
441 vnfd_id, vdu_id, e
442 )
443 )
tierno72ef84f2020-10-06 08:22:07 +0000444
bravof922c4172020-11-24 21:21:43 -0300445 def _get_vdu_cloud_init_content(self, vdu, vnfd):
446 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000447 try:
tierno72ef84f2020-10-06 08:22:07 +0000448 if vdu.get("cloud-init-file"):
449 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300450 if base_folder["pkg-dir"]:
451 cloud_init_file = "{}/{}/cloud_init/{}".format(
452 base_folder["folder"],
453 base_folder["pkg-dir"],
454 vdu["cloud-init-file"],
455 )
456 else:
457 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
458 base_folder["folder"],
459 vdu["cloud-init-file"],
460 )
tierno72ef84f2020-10-06 08:22:07 +0000461 with self.fs.file_open(cloud_init_file, "r") as ci_file:
462 cloud_init_content = ci_file.read()
463 elif vdu.get("cloud-init"):
464 cloud_init_content = vdu["cloud-init"]
465
466 return cloud_init_content
467 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100468 raise LcmException(
469 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
470 vnfd["id"], vdu["id"], cloud_init_file, e
471 )
472 )
tierno72ef84f2020-10-06 08:22:07 +0000473
tierno72ef84f2020-10-06 08:22:07 +0000474 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100475 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300476 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100477 )
tierno72ef84f2020-10-06 08:22:07 +0000478 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300479 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000480
tierno2357f4e2020-10-19 16:38:59 +0000481 @staticmethod
482 def ip_profile_2_RO(ip_profile):
483 RO_ip_profile = deepcopy(ip_profile)
484 if "dns-server" in RO_ip_profile:
485 if isinstance(RO_ip_profile["dns-server"], list):
486 RO_ip_profile["dns-address"] = []
487 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100488 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000489 else:
490 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
491 if RO_ip_profile.get("ip-version") == "ipv4":
492 RO_ip_profile["ip-version"] = "IPv4"
493 if RO_ip_profile.get("ip-version") == "ipv6":
494 RO_ip_profile["ip-version"] = "IPv6"
495 if "dhcp-params" in RO_ip_profile:
496 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
497 return RO_ip_profile
498
tierno2357f4e2020-10-19 16:38:59 +0000499 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000500 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000501 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000502 db_update = {"_admin.modified": time()}
503 if vdu_create:
504 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100505 vdur = next(
506 (
507 vdur
508 for vdur in reversed(db_vnfr["vdur"])
509 if vdur["vdu-id-ref"] == vdu_id
510 ),
511 None,
512 )
tierno2357f4e2020-10-19 16:38:59 +0000513 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000514 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300515 self.logger.debug(
516 "No vdur in the database. Using the vdur-template to scale"
517 )
vegall8d625f12022-03-22 16:23:30 +0000518 vdur_template = db_vnfr.get("vdur-template")
519 if not vdur_template:
520 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300521 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
522 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000523 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100524 )
vegall8d625f12022-03-22 16:23:30 +0000525 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300526 # Delete a template from the database after using it
527 self.db.set_one(
528 "vnfrs",
529 {"_id": db_vnfr["_id"]},
530 None,
531 pull={"vdur-template": {"_id": vdur["_id"]}},
532 )
tierno2357f4e2020-10-19 16:38:59 +0000533 for count in range(vdu_count):
534 vdur_copy = deepcopy(vdur)
535 vdur_copy["status"] = "BUILD"
536 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100537 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000538 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000539 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100540 vdur_copy["id"] = "{}-{}".format(
541 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
542 )
tierno2357f4e2020-10-19 16:38:59 +0000543 vdur_copy.pop("vim_info", None)
544 for iface in vdur_copy["interfaces"]:
545 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100546 iface["ip-address"] = self.increment_ip_mac(
547 iface["ip-address"], count + 1
548 )
tierno2357f4e2020-10-19 16:38:59 +0000549 else:
550 iface.pop("ip-address", None)
551 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100552 iface["mac-address"] = self.increment_ip_mac(
553 iface["mac-address"], count + 1
554 )
tierno2357f4e2020-10-19 16:38:59 +0000555 else:
556 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000557 if db_vnfr["vdur"]:
558 iface.pop(
559 "mgmt_vnf", None
560 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000561 db_vdu_push_list.append(vdur_copy)
562 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200563 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000564 if len(db_vnfr["vdur"]) == 1:
565 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300566 self.logger.debug(
567 "Scaling to 0 !, creating the template with the last vdur"
568 )
vegall8d625f12022-03-22 16:23:30 +0000569 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000570 for vdu_id, vdu_count in vdu_delete.items():
571 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100572 indexes_to_delete = [
573 iv[0]
574 for iv in enumerate(db_vnfr["vdur"])
575 if iv[1]["vdu-id-ref"] == vdu_id
576 ]
577 db_update.update(
578 {
579 "vdur.{}.status".format(i): "DELETING"
580 for i in indexes_to_delete[-vdu_count:]
581 }
582 )
tierno2357f4e2020-10-19 16:38:59 +0000583 else:
584 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100585 vdus_to_delete = [
586 v
587 for v in reversed(db_vnfr["vdur"])
588 if v["vdu-id-ref"] == vdu_id
589 ]
tierno2357f4e2020-10-19 16:38:59 +0000590 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100591 self.db.set_one(
592 "vnfrs",
593 {"_id": db_vnfr["_id"]},
594 None,
595 pull={"vdur": {"_id": vdu["_id"]}},
596 )
vegall8d625f12022-03-22 16:23:30 +0000597 db_push = {}
598 if db_vdu_push_list:
599 db_push["vdur"] = db_vdu_push_list
600 if template_vdur:
601 db_push["vdur-template"] = template_vdur
602 if not db_push:
603 db_push = None
604 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000605 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
606 # modify passed dictionary db_vnfr
607 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
608 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200609
tiernof578e552018-11-08 19:07:20 +0100610 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
611 """
612 Updates database nsr with the RO info for the created vld
613 :param ns_update_nsr: dictionary to be filled with the updated info
614 :param db_nsr: content of db_nsr. This is also modified
615 :param nsr_desc_RO: nsr descriptor from RO
616 :return: Nothing, LcmException is raised on errors
617 """
618
619 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
620 for net_RO in get_iterable(nsr_desc_RO, "nets"):
621 if vld["id"] != net_RO.get("ns_net_osm_id"):
622 continue
623 vld["vim-id"] = net_RO.get("vim_net_id")
624 vld["name"] = net_RO.get("vim_name")
625 vld["status"] = net_RO.get("status")
626 vld["status-detailed"] = net_RO.get("error_msg")
627 ns_update_nsr["vld.{}".format(vld_index)] = vld
628 break
629 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100630 raise LcmException(
631 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
632 )
tiernof578e552018-11-08 19:07:20 +0100633
tiernoe876f672020-02-13 14:34:48 +0000634 def set_vnfr_at_error(self, db_vnfrs, error_text):
635 try:
636 for db_vnfr in db_vnfrs.values():
637 vnfr_update = {"status": "ERROR"}
638 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
639 if "status" not in vdur:
640 vdur["status"] = "ERROR"
641 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
642 if error_text:
643 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100644 vnfr_update[
645 "vdur.{}.status-detailed".format(vdu_index)
646 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000647 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
648 except DbException as e:
649 self.logger.error("Cannot update vnf. {}".format(e))
650
tierno5ee02052019-12-05 19:55:02 +0000651 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000652 """
653 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000654 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000655 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
656 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
657 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
658 """
tierno5ee02052019-12-05 19:55:02 +0000659 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
660 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000661 mapping = {}
662 ns_config_info = {"osm-config-mapping": mapping}
663 for vca in vca_deployed_list:
664 if not vca["member-vnf-index"]:
665 continue
666 if not vca["vdu_id"]:
667 mapping[vca["member-vnf-index"]] = vca["application"]
668 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100669 mapping[
670 "{}.{}.{}".format(
671 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
672 )
673 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000674 return ns_config_info
675
garciadeblas5697b8b2021-03-24 09:17:02 +0100676 async def _instantiate_ng_ro(
677 self,
678 logging_text,
679 nsr_id,
680 nsd,
681 db_nsr,
682 db_nslcmop,
683 db_vnfrs,
684 db_vnfds,
685 n2vc_key_list,
686 stage,
687 start_deploy,
688 timeout_ns_deploy,
689 ):
tierno2357f4e2020-10-19 16:38:59 +0000690 db_vims = {}
691
692 def get_vim_account(vim_account_id):
693 nonlocal db_vims
694 if vim_account_id in db_vims:
695 return db_vims[vim_account_id]
696 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
697 db_vims[vim_account_id] = db_vim
698 return db_vim
699
700 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100701 def parse_vld_instantiation_params(
702 target_vim, target_vld, vld_params, target_sdn
703 ):
tierno2357f4e2020-10-19 16:38:59 +0000704 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500705 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
706 vld_params["ip-profile"]
707 )
tierno2357f4e2020-10-19 16:38:59 +0000708 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100709 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
710 "provider-network"
711 ]
tierno2357f4e2020-10-19 16:38:59 +0000712 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100713 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
714 "provider-network"
715 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000716
717 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
718 # if wim_account_id is specified in vld_params, validate if it is feasible.
719 wim_account_id, db_wim = select_feasible_wim_account(
720 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
721 )
722
723 if wim_account_id:
724 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
725 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
726 # update vld_params with correct WIM account Id
727 vld_params["wimAccountId"] = wim_account_id
728
729 target_wim = "wim:{}".format(wim_account_id)
730 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
731 sdn_ports = get_sdn_ports(vld_params, db_wim)
732 if len(sdn_ports) > 0:
733 target_vld["vim_info"][target_wim] = target_wim_attrs
734 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
735
736 self.logger.debug(
737 "Target VLD with WIM data: {:s}".format(str(target_vld))
738 )
739
tierno2357f4e2020-10-19 16:38:59 +0000740 for param in ("vim-network-name", "vim-network-id"):
741 if vld_params.get(param):
742 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300743 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300744 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100745 populate_dict(
746 target_vld["vim_info"],
747 (other_target_vim, param.replace("-", "_")),
748 vim_net,
749 )
tierno2357f4e2020-10-19 16:38:59 +0000750 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100751 target_vld["vim_info"][target_vim][
752 param.replace("-", "_")
753 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300754 if vld_params.get("common_id"):
755 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000756
aticig15db6142022-01-24 12:51:26 +0300757 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
758 def update_ns_vld_target(target, ns_params):
759 for vnf_params in ns_params.get("vnf", ()):
760 if vnf_params.get("vimAccountId"):
761 target_vnf = next(
762 (
763 vnfr
764 for vnfr in db_vnfrs.values()
765 if vnf_params["member-vnf-index"]
766 == vnfr["member-vnf-index-ref"]
767 ),
768 None,
769 )
770 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100771 if not vdur:
Pedro Escaleira556f5c72023-04-20 15:22:16 +0100772 continue
aticig15db6142022-01-24 12:51:26 +0300773 for a_index, a_vld in enumerate(target["ns"]["vld"]):
774 target_vld = find_in_list(
775 get_iterable(vdur, "interfaces"),
776 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
777 )
aticig84bd9a72022-06-14 03:01:36 +0300778
779 vld_params = find_in_list(
780 get_iterable(ns_params, "vld"),
781 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
782 )
aticig15db6142022-01-24 12:51:26 +0300783 if target_vld:
784 if vnf_params.get("vimAccountId") not in a_vld.get(
785 "vim_info", {}
786 ):
aticig84bd9a72022-06-14 03:01:36 +0300787 target_vim_network_list = [
788 v for _, v in a_vld.get("vim_info").items()
789 ]
790 target_vim_network_name = next(
791 (
792 item.get("vim_network_name", "")
793 for item in target_vim_network_list
794 ),
795 "",
796 )
797
aticig15db6142022-01-24 12:51:26 +0300798 target["ns"]["vld"][a_index].get("vim_info").update(
799 {
800 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300801 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300802 }
803 }
804 )
805
aticig84bd9a72022-06-14 03:01:36 +0300806 if vld_params:
807 for param in ("vim-network-name", "vim-network-id"):
808 if vld_params.get(param) and isinstance(
809 vld_params[param], dict
810 ):
811 for vim, vim_net in vld_params[
812 param
813 ].items():
814 other_target_vim = "vim:" + vim
815 populate_dict(
816 target["ns"]["vld"][a_index].get(
817 "vim_info"
818 ),
819 (
820 other_target_vim,
821 param.replace("-", "_"),
822 ),
823 vim_net,
824 )
825
tierno69f0d382020-05-07 13:08:09 +0000826 nslcmop_id = db_nslcmop["_id"]
827 target = {
828 "name": db_nsr["name"],
829 "ns": {"vld": []},
830 "vnf": [],
831 "image": deepcopy(db_nsr["image"]),
832 "flavor": deepcopy(db_nsr["flavor"]),
833 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000834 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000835 }
836 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000837 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000838 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000839 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000840 if db_nsr.get("shared-volumes"):
841 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
842 for shared_volumes in target["shared-volumes"]:
843 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100844 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100845 target["affinity-or-anti-affinity-group"] = deepcopy(
846 db_nsr["affinity-or-anti-affinity-group"]
847 )
848 for affinity_or_anti_affinity_group in target[
849 "affinity-or-anti-affinity-group"
850 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100851 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000852
tierno2357f4e2020-10-19 16:38:59 +0000853 if db_nslcmop.get("lcmOperationType") != "instantiate":
854 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100855 db_nslcmop_instantiate = self.db.get_list(
856 "nslcmops",
857 {
858 "nsInstanceId": db_nslcmop["nsInstanceId"],
859 "lcmOperationType": "instantiate",
860 },
861 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000862 ns_params = db_nslcmop_instantiate.get("operationParams")
863 else:
864 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300865 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
866 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000867
868 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000869 for vld_index, vld in enumerate(db_nsr.get("vld")):
870 target_vim = "vim:{}".format(ns_params["vimAccountId"])
871 target_vld = {
872 "id": vld["id"],
873 "name": vld["name"],
874 "mgmt-network": vld.get("mgmt-network", False),
875 "type": vld.get("type"),
876 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300877 target_vim: {
878 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100879 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -0300880 }
garciadeblas5697b8b2021-03-24 09:17:02 +0100881 },
tierno2357f4e2020-10-19 16:38:59 +0000882 }
883 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000884 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +0000885 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +0300886 if vim_config := db_vim.get("config"):
887 if sdnc_id := vim_config.get("sdn-controller"):
888 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
889 target_sdn = "sdn:{}".format(sdnc_id)
890 target_vld["vim_info"][target_sdn] = {
891 "sdn": True,
892 "target_vim": target_vim,
893 "vlds": [sdn_vld],
894 "type": vld.get("type"),
895 }
tierno2357f4e2020-10-19 16:38:59 +0000896
bravof922c4172020-11-24 21:21:43 -0300897 nsd_vnf_profiles = get_vnf_profiles(nsd)
898 for nsd_vnf_profile in nsd_vnf_profiles:
899 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
900 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100901 cp2target[
902 "member_vnf:{}.{}".format(
903 cp["constituent-cpd-id"][0][
904 "constituent-base-element-id"
905 ],
906 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
907 )
908 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000909
910 # check at nsd descriptor, if there is an ip-profile
911 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +0000912 nsd_vlp = find_in_list(
913 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100914 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
915 == vld["id"],
916 )
917 if (
918 nsd_vlp
919 and nsd_vlp.get("virtual-link-protocol-data")
920 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
921 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500922 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100923 "l3-protocol-data"
924 ]
bravof922c4172020-11-24 21:21:43 -0300925
tierno2357f4e2020-10-19 16:38:59 +0000926 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +0100927 vld_instantiation_params = find_in_list(
928 get_iterable(ns_params, "vld"),
929 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
930 )
tierno2357f4e2020-10-19 16:38:59 +0000931 if vld_instantiation_params:
932 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300933 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000934 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +0300935 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
936 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -0300937
tierno69f0d382020-05-07 13:08:09 +0000938 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +0100939 vnfd = find_in_list(
940 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
941 )
942 vnf_params = find_in_list(
943 get_iterable(ns_params, "vnf"),
944 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
945 )
tierno69f0d382020-05-07 13:08:09 +0000946 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000947 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000948 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000949 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +0100950 vnf_cp = find_in_list(
951 vnfd.get("int-virtual-link-desc", ()),
952 lambda cpd: cpd.get("id") == vld["id"],
953 )
tierno69f0d382020-05-07 13:08:09 +0000954 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +0100955 ns_cp = "member_vnf:{}.{}".format(
956 vnfr["member-vnf-index-ref"], vnf_cp["id"]
957 )
tierno69f0d382020-05-07 13:08:09 +0000958 if cp2target.get(ns_cp):
959 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300960
garciadeblas5697b8b2021-03-24 09:17:02 +0100961 vld["vim_info"] = {
962 target_vim: {"vim_network_name": vld.get("vim-network-name")}
963 }
tierno2357f4e2020-10-19 16:38:59 +0000964 # check if this network needs SDN assist
965 target_sdn = None
966 if vld.get("pci-interfaces"):
967 db_vim = get_vim_account(vnfr["vim-account-id"])
968 sdnc_id = db_vim["config"].get("sdn-controller")
969 if sdnc_id:
970 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
971 target_sdn = "sdn:{}".format(sdnc_id)
972 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +0100973 "sdn": True,
974 "target_vim": target_vim,
975 "vlds": [sdn_vld],
976 "type": vld.get("type"),
977 }
tierno69f0d382020-05-07 13:08:09 +0000978
tierno2357f4e2020-10-19 16:38:59 +0000979 # check at vnfd descriptor, if there is an ip-profile
980 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300981 vnfd_vlp = find_in_list(
982 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100983 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -0300984 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100985 if (
986 vnfd_vlp
987 and vnfd_vlp.get("virtual-link-protocol-data")
988 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
989 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500990 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100991 "l3-protocol-data"
992 ]
tierno2357f4e2020-10-19 16:38:59 +0000993 # update vld_params with instantiation params
994 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +0100995 vld_instantiation_params = find_in_list(
996 get_iterable(vnf_params, "internal-vld"),
997 lambda i_vld: i_vld["name"] == vld["id"],
998 )
tierno2357f4e2020-10-19 16:38:59 +0000999 if vld_instantiation_params:
1000 vld_params.update(vld_instantiation_params)
1001 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1002
1003 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001004 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001005 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1006 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001007 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001008
bravof922c4172020-11-24 21:21:43 -03001009 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1010
1011 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001012 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1013 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001014 if (
1015 vdu_configuration
1016 and vdu_configuration.get("config-access")
1017 and vdu_configuration.get("config-access").get("ssh-access")
1018 ):
bravof922c4172020-11-24 21:21:43 -03001019 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001020 vdur["ssh-access-required"] = vdu_configuration[
1021 "config-access"
1022 ]["ssh-access"]["required"]
1023 elif (
1024 vnf_configuration
1025 and vnf_configuration.get("config-access")
1026 and vnf_configuration.get("config-access").get("ssh-access")
1027 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1028 ):
bravof922c4172020-11-24 21:21:43 -03001029 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001030 vdur["ssh-access-required"] = vnf_configuration[
1031 "config-access"
1032 ]["ssh-access"]["required"]
1033 elif ssh_keys_instantiation and find_in_list(
1034 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1035 ):
bravof922c4172020-11-24 21:21:43 -03001036 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001037
bravof922c4172020-11-24 21:21:43 -03001038 self.logger.debug("NS > vdur > {}".format(vdur))
1039
1040 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001041 # cloud-init
1042 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001043 vdur["cloud-init"] = "{}:file:{}".format(
1044 vnfd["_id"], vdud.get("cloud-init-file")
1045 )
tierno2357f4e2020-10-19 16:38:59 +00001046 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1047 if vdur["cloud-init"] not in target["cloud_init_content"]:
1048 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001049 if base_folder["pkg-dir"]:
1050 cloud_init_file = "{}/{}/cloud_init/{}".format(
1051 base_folder["folder"],
1052 base_folder["pkg-dir"],
1053 vdud.get("cloud-init-file"),
1054 )
1055 else:
1056 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1057 base_folder["folder"],
1058 vdud.get("cloud-init-file"),
1059 )
tierno2357f4e2020-10-19 16:38:59 +00001060 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001061 target["cloud_init_content"][
1062 vdur["cloud-init"]
1063 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001064 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001065 vdur["cloud-init"] = "{}:vdu:{}".format(
1066 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1067 )
tierno2357f4e2020-10-19 16:38:59 +00001068 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001069 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1070 "cloud-init"
1071 ]
tierno2357f4e2020-10-19 16:38:59 +00001072 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001073 deploy_params_vdu = self._format_additional_params(
1074 vdur.get("additionalParams") or {}
1075 )
1076 deploy_params_vdu["OSM"] = get_osm_params(
1077 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1078 )
tierno2357f4e2020-10-19 16:38:59 +00001079 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001080
1081 # flavor
1082 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001083 if target_vim not in ns_flavor["vim_info"]:
1084 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001085
1086 # deal with images
1087 # in case alternative images are provided we must check if they should be applied
1088 # for the vim_type, modify the vim_type taking into account
1089 ns_image_id = int(vdur["ns-image-id"])
1090 if vdur.get("alt-image-ids"):
1091 db_vim = get_vim_account(vnfr["vim-account-id"])
1092 vim_type = db_vim["vim_type"]
1093 for alt_image_id in vdur.get("alt-image-ids"):
1094 ns_alt_image = target["image"][int(alt_image_id)]
1095 if vim_type == ns_alt_image.get("vim-type"):
1096 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001097 self.logger.debug(
1098 "use alternative image id: {}".format(alt_image_id)
1099 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001100 ns_image_id = alt_image_id
1101 vdur["ns-image-id"] = ns_image_id
1102 break
1103 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001104 if target_vim not in ns_image["vim_info"]:
1105 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001106
Alexis Romero305b5c42022-03-11 15:29:18 +01001107 # Affinity groups
1108 if vdur.get("affinity-or-anti-affinity-group-id"):
1109 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1110 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1111 if target_vim not in ns_ags["vim_info"]:
1112 ns_ags["vim_info"][target_vim] = {}
1113
vegall63162192023-03-06 14:19:16 +00001114 # shared-volumes
1115 if vdur.get("shared-volumes-id"):
1116 for sv_id in vdur["shared-volumes-id"]:
1117 ns_sv = find_in_list(
1118 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1119 )
1120 if ns_sv:
1121 ns_sv["vim_info"][target_vim] = {}
1122
tierno2357f4e2020-10-19 16:38:59 +00001123 vdur["vim_info"] = {target_vim: {}}
1124 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001125 if vnf_params:
1126 vdu_instantiation_params = find_in_list(
1127 get_iterable(vnf_params, "vdu"),
1128 lambda i_vdu: i_vdu["id"] == vdud["id"],
1129 )
1130 if vdu_instantiation_params:
1131 # Parse the vdu_volumes from the instantiation params
1132 vdu_volumes = get_volumes_from_instantiation_params(
1133 vdu_instantiation_params, vdud
1134 )
1135 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001136 vdur["additionalParams"]["OSM"][
1137 "vim_flavor_id"
1138 ] = vdu_instantiation_params.get("vim-flavor-id")
kayal20011028e362024-06-27 08:23:36 +05301139 vdur["additionalParams"]["OSM"][
kayal2001de102fe2024-11-28 10:51:52 +05301140 "vim_flavor_name"
1141 ] = vdu_instantiation_params.get("vim-flavor-name")
1142 vdur["additionalParams"]["OSM"][
kayal20011028e362024-06-27 08:23:36 +05301143 "instance_name"
1144 ] = vdu_instantiation_params.get("instance_name")
kayal2001ed6528c2024-11-28 11:31:56 +05301145 vdur["additionalParams"]["OSM"][
1146 "security-group-name"
1147 ] = vdu_instantiation_params.get("security-group-name")
tierno2357f4e2020-10-19 16:38:59 +00001148 vdur_list.append(vdur)
1149 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001150 target["vnf"].append(target_vnf)
1151
garciadeblas07f4e4c2022-06-09 09:42:58 +02001152 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001153 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001154 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001155 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001156 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001157 nsr_id,
1158 action_id,
1159 nslcmop_id,
1160 start_deploy,
1161 timeout_ns_deploy,
1162 stage,
1163 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001164 )
tierno69f0d382020-05-07 13:08:09 +00001165
1166 # Updating NSR
1167 db_nsr_update = {
1168 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001169 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001170 }
1171 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1172 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1173 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001174 self.logger.debug(
1175 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1176 )
tierno69f0d382020-05-07 13:08:09 +00001177 return
1178
garciadeblas5697b8b2021-03-24 09:17:02 +01001179 async def _wait_ng_ro(
1180 self,
1181 nsr_id,
1182 action_id,
1183 nslcmop_id=None,
1184 start_time=None,
1185 timeout=600,
1186 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001187 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001188 ):
tierno69f0d382020-05-07 13:08:09 +00001189 detailed_status_old = None
1190 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001191 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001192 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001193 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001194 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001195 if desc_status["status"] == "FAILED":
1196 raise NgRoException(desc_status["details"])
1197 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001198 if stage:
1199 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001200 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001201 if stage:
1202 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001203 break
1204 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001205 assert False, "ROclient.check_ns_status returns unknown {}".format(
1206 desc_status["status"]
1207 )
tierno2357f4e2020-10-19 16:38:59 +00001208 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001209 detailed_status_old = stage[2]
1210 db_nsr_update["detailed-status"] = " ".join(stage)
1211 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1212 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001213 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001214 else: # timeout_ns_deploy
1215 raise NgRoException("Timeout waiting ns to deploy")
1216
garciadeblas5697b8b2021-03-24 09:17:02 +01001217 async def _terminate_ng_ro(
1218 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1219 ):
tierno69f0d382020-05-07 13:08:09 +00001220 db_nsr_update = {}
1221 failed_detail = []
1222 action_id = None
1223 start_deploy = time()
1224 try:
1225 target = {
1226 "ns": {"vld": []},
1227 "vnf": [],
1228 "image": [],
1229 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001230 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001231 }
1232 desc = await self.RO.deploy(nsr_id, target)
1233 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001234 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001235 self.logger.debug(
1236 logging_text
1237 + "ns terminate action at RO. action_id={}".format(action_id)
1238 )
tierno69f0d382020-05-07 13:08:09 +00001239
1240 # wait until done
1241 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001242 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001243 nsr_id,
1244 action_id,
1245 nslcmop_id,
1246 start_deploy,
1247 delete_timeout,
1248 stage,
1249 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001250 )
tierno69f0d382020-05-07 13:08:09 +00001251 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1252 # delete all nsr
1253 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001254 except NgRoException as e:
1255 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001256 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1257 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001258 self.logger.debug(
1259 logging_text + "RO_action_id={} already deleted".format(action_id)
1260 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001261 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001262 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001263 self.logger.debug(
1264 logging_text
1265 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1266 )
tierno69f0d382020-05-07 13:08:09 +00001267 else:
1268 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001269 self.logger.error(
1270 logging_text
1271 + "RO_action_id={} delete error: {}".format(action_id, e)
1272 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001273 except Exception as e:
1274 failed_detail.append("delete error: {}".format(e))
1275 self.logger.error(
1276 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1277 )
tierno69f0d382020-05-07 13:08:09 +00001278
1279 if failed_detail:
1280 stage[2] = "Error deleting from VIM"
1281 else:
1282 stage[2] = "Deleted from VIM"
1283 db_nsr_update["detailed-status"] = " ".join(stage)
1284 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1285 self._write_op_status(nslcmop_id, stage)
1286
1287 if failed_detail:
1288 raise LcmException("; ".join(failed_detail))
1289 return
1290
garciadeblas5697b8b2021-03-24 09:17:02 +01001291 async def instantiate_RO(
1292 self,
1293 logging_text,
1294 nsr_id,
1295 nsd,
1296 db_nsr,
1297 db_nslcmop,
1298 db_vnfrs,
1299 db_vnfds,
1300 n2vc_key_list,
1301 stage,
1302 ):
tiernoe95ed362020-04-23 08:24:57 +00001303 """
1304 Instantiate at RO
1305 :param logging_text: preffix text to use at logging
1306 :param nsr_id: nsr identity
1307 :param nsd: database content of ns descriptor
1308 :param db_nsr: database content of ns record
1309 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1310 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001311 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001312 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1313 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1314 :return: None or exception
1315 """
tiernoe876f672020-02-13 14:34:48 +00001316 try:
tiernoe876f672020-02-13 14:34:48 +00001317 start_deploy = time()
1318 ns_params = db_nslcmop.get("operationParams")
1319 if ns_params and ns_params.get("timeout_ns_deploy"):
1320 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1321 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001322 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001323
tiernoe876f672020-02-13 14:34:48 +00001324 # Check for and optionally request placement optimization. Database will be updated if placement activated
1325 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001326 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1327 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1328 for vnfr in db_vnfrs.values():
1329 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1330 break
1331 else:
1332 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001333
garciadeblas5697b8b2021-03-24 09:17:02 +01001334 return await self._instantiate_ng_ro(
1335 logging_text,
1336 nsr_id,
1337 nsd,
1338 db_nsr,
1339 db_nslcmop,
1340 db_vnfrs,
1341 db_vnfds,
1342 n2vc_key_list,
1343 stage,
1344 start_deploy,
1345 timeout_ns_deploy,
1346 )
tierno2357f4e2020-10-19 16:38:59 +00001347 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001348 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001349 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001350 self.logger.error(
1351 "Error deploying at VIM {}".format(e),
1352 exc_info=not isinstance(
1353 e,
1354 (
1355 ROclient.ROClientException,
1356 LcmException,
1357 DbException,
1358 NgRoException,
1359 ),
1360 ),
1361 )
tiernoe876f672020-02-13 14:34:48 +00001362 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001363
tierno7ecbc342020-09-21 14:05:39 +00001364 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1365 """
1366 Wait for kdu to be up, get ip address
1367 :param logging_text: prefix use for logging
1368 :param nsr_id:
1369 :param vnfr_id:
1370 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001371 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001372 """
1373
1374 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1375 nb_tries = 0
1376
1377 while nb_tries < 360:
1378 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001379 kdur = next(
1380 (
1381 x
1382 for x in get_iterable(db_vnfr, "kdur")
1383 if x.get("kdu-name") == kdu_name
1384 ),
1385 None,
1386 )
tierno7ecbc342020-09-21 14:05:39 +00001387 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001388 raise LcmException(
1389 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1390 )
tierno7ecbc342020-09-21 14:05:39 +00001391 if kdur.get("status"):
1392 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001393 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001394 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001395 raise LcmException(
1396 "target KDU={} is in error state".format(kdu_name)
1397 )
tierno7ecbc342020-09-21 14:05:39 +00001398
Gabriel Cubae7898982023-05-11 01:57:21 -05001399 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001400 nb_tries += 1
1401 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1402
garciadeblas5697b8b2021-03-24 09:17:02 +01001403 async def wait_vm_up_insert_key_ro(
1404 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1405 ):
tiernoa5088192019-11-26 16:12:53 +00001406 """
1407 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1408 :param logging_text: prefix use for logging
1409 :param nsr_id:
1410 :param vnfr_id:
1411 :param vdu_id:
1412 :param vdu_index:
1413 :param pub_key: public ssh key to inject, None to skip
1414 :param user: user to apply the public ssh key
1415 :return: IP address
1416 """
quilesj7e13aeb2019-10-08 13:34:55 +02001417
tierno2357f4e2020-10-19 16:38:59 +00001418 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001419 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001420 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001421 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001422
tiernod8323042019-08-09 11:32:23 +00001423 while True:
quilesj3149f262019-12-03 10:58:10 +00001424 ro_retries += 1
1425 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001426 raise LcmException(
1427 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1428 )
quilesj3149f262019-12-03 10:58:10 +00001429
Gabriel Cubae7898982023-05-11 01:57:21 -05001430 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001431
1432 # get ip address
tiernod8323042019-08-09 11:32:23 +00001433 if not target_vdu_id:
1434 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001435
1436 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001437 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001438 raise LcmException(
1439 "Cannot inject ssh-key because target VNF is in error state"
1440 )
tiernod8323042019-08-09 11:32:23 +00001441 ip_address = db_vnfr.get("ip-address")
1442 if not ip_address:
1443 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001444 vdur = next(
1445 (
1446 x
1447 for x in get_iterable(db_vnfr, "vdur")
1448 if x.get("ip-address") == ip_address
1449 ),
1450 None,
1451 )
quilesj3149f262019-12-03 10:58:10 +00001452 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001453 vdur = next(
1454 (
1455 x
1456 for x in get_iterable(db_vnfr, "vdur")
1457 if x.get("vdu-id-ref") == vdu_id
1458 and x.get("count-index") == vdu_index
1459 ),
1460 None,
1461 )
quilesj3149f262019-12-03 10:58:10 +00001462
garciadeblas5697b8b2021-03-24 09:17:02 +01001463 if (
1464 not vdur and len(db_vnfr.get("vdur", ())) == 1
1465 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001466 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001467 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001468 raise LcmException(
1469 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1470 vnfr_id, vdu_id, vdu_index
1471 )
1472 )
tierno2357f4e2020-10-19 16:38:59 +00001473 # New generation RO stores information at "vim_info"
1474 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001475 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001476 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001477 target_vim = next(
1478 t for t in vdur["vim_info"]
1479 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001480 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001481 if (
1482 vdur.get("pdu-type")
1483 or vdur.get("status") == "ACTIVE"
1484 or ng_ro_status == "ACTIVE"
1485 ):
quilesj3149f262019-12-03 10:58:10 +00001486 ip_address = vdur.get("ip-address")
1487 if not ip_address:
1488 continue
1489 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001490 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001491 raise LcmException(
1492 "Cannot inject ssh-key because target VM is in error state"
1493 )
quilesj3149f262019-12-03 10:58:10 +00001494
tiernod8323042019-08-09 11:32:23 +00001495 if not target_vdu_id:
1496 continue
tiernod8323042019-08-09 11:32:23 +00001497
quilesj7e13aeb2019-10-08 13:34:55 +02001498 # inject public key into machine
1499 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001500 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001501 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001502 if vdur.get("pdu-type"):
1503 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1504 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001505 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001506 target = {
1507 "action": {
1508 "action": "inject_ssh_key",
1509 "key": pub_key,
1510 "user": user,
1511 },
1512 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1513 }
1514 desc = await self.RO.deploy(nsr_id, target)
1515 action_id = desc["action_id"]
1516 await self._wait_ng_ro(
1517 nsr_id, action_id, timeout=600, operation="instantiation"
1518 )
1519 break
tierno69f0d382020-05-07 13:08:09 +00001520 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001521 raise LcmException(
1522 "Reaching max tries injecting key. Error: {}".format(e)
1523 )
quilesj7e13aeb2019-10-08 13:34:55 +02001524 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001525 break
1526
1527 return ip_address
1528
tierno5ee02052019-12-05 19:55:02 +00001529 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1530 """
1531 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1532 """
1533 my_vca = vca_deployed_list[vca_index]
1534 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001535 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001536 return
1537 timeout = 300
1538 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001539 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1540 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1541 configuration_status_list = db_nsr["configurationStatus"]
1542 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001543 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001544 # myself
tierno5ee02052019-12-05 19:55:02 +00001545 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001546 if not my_vca.get("member-vnf-index") or (
1547 vca_deployed.get("member-vnf-index")
1548 == my_vca.get("member-vnf-index")
1549 ):
quilesj3655ae02019-12-12 16:08:35 +00001550 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001551 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001552 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001553 elif internal_status == "BROKEN":
1554 raise LcmException(
1555 "Configuration aborted because dependent charm/s has failed"
1556 )
quilesj3655ae02019-12-12 16:08:35 +00001557 else:
1558 break
tierno5ee02052019-12-05 19:55:02 +00001559 else:
quilesj3655ae02019-12-12 16:08:35 +00001560 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001561 return
1562 await asyncio.sleep(10)
1563 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001564
1565 raise LcmException("Configuration aborted because dependent charm/s timeout")
1566
David Garciac1fe90a2021-03-31 19:12:02 +02001567 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001568 vca_id = None
1569 if db_vnfr:
1570 vca_id = deep_get(db_vnfr, ("vca-id",))
1571 elif db_nsr:
1572 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1573 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1574 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001575
garciadeblas5697b8b2021-03-24 09:17:02 +01001576 async def instantiate_N2VC(
1577 self,
1578 logging_text,
1579 vca_index,
1580 nsi_id,
1581 db_nsr,
1582 db_vnfr,
1583 vdu_id,
1584 kdu_name,
1585 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001586 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001587 config_descriptor,
1588 deploy_params,
1589 base_folder,
1590 nslcmop_id,
1591 stage,
1592 vca_type,
1593 vca_name,
1594 ee_config_descriptor,
1595 ):
tiernod8323042019-08-09 11:32:23 +00001596 nsr_id = db_nsr["_id"]
1597 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001598 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001599 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001600 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001601 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001602 "collection": "nsrs",
1603 "filter": {"_id": nsr_id},
1604 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001605 }
tiernod8323042019-08-09 11:32:23 +00001606 step = ""
1607 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001608 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001609 element_under_configuration = nsr_id
1610
tiernod8323042019-08-09 11:32:23 +00001611 vnfr_id = None
1612 if db_vnfr:
1613 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001614 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001615
garciadeblas5697b8b2021-03-24 09:17:02 +01001616 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001617
aktas98488ed2021-07-29 17:42:49 +03001618 if vca_type == "native_charm":
1619 index_number = 0
1620 else:
1621 index_number = vdu_index or 0
1622
tiernod8323042019-08-09 11:32:23 +00001623 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001624 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001625 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001626 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001627 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001628 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001629 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001630 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001631 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001632 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001633 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001634 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001635 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001636 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001637
1638 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001639 if base_folder["pkg-dir"]:
1640 artifact_path = "{}/{}/{}/{}".format(
1641 base_folder["folder"],
1642 base_folder["pkg-dir"],
1643 "charms"
aticig15db6142022-01-24 12:51:26 +03001644 if vca_type
1645 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001646 else "helm-charts",
1647 vca_name,
1648 )
1649 else:
1650 artifact_path = "{}/Scripts/{}/{}/".format(
1651 base_folder["folder"],
1652 "charms"
aticig15db6142022-01-24 12:51:26 +03001653 if vca_type
1654 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001655 else "helm-charts",
1656 vca_name,
1657 )
bravof922c4172020-11-24 21:21:43 -03001658
1659 self.logger.debug("Artifact path > {}".format(artifact_path))
1660
tiernoa278b842020-07-08 15:33:55 +00001661 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001662 initial_config_primitive_list = config_descriptor.get(
1663 "initial-config-primitive"
1664 )
tiernoa278b842020-07-08 15:33:55 +00001665
garciadeblas5697b8b2021-03-24 09:17:02 +01001666 self.logger.debug(
1667 "Initial config primitive list > {}".format(
1668 initial_config_primitive_list
1669 )
1670 )
bravof922c4172020-11-24 21:21:43 -03001671
tiernoa278b842020-07-08 15:33:55 +00001672 # add config if not present for NS charm
1673 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001674 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001675 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1676 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1677 )
tiernod8323042019-08-09 11:32:23 +00001678
garciadeblas5697b8b2021-03-24 09:17:02 +01001679 self.logger.debug(
1680 "Initial config primitive list #2 > {}".format(
1681 initial_config_primitive_list
1682 )
1683 )
tierno588547c2020-07-01 15:30:20 +00001684 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001685 # find old ee_id if exists
1686 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001687
David Garciac1fe90a2021-03-31 19:12:02 +02001688 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001689 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001690 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001691 self._write_configuration_status(
1692 nsr_id=nsr_id,
1693 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001694 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001695 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001696 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001697 )
tiernod8323042019-08-09 11:32:23 +00001698
tierno588547c2020-07-01 15:30:20 +00001699 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001700 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001701
1702 ee_id = None
1703 credentials = None
1704 if vca_type == "k8s_proxy_charm":
1705 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001706 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001707 namespace=namespace,
1708 artifact_path=artifact_path,
1709 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001710 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001711 )
Luis Vegae11384e2023-10-10 22:36:33 +00001712 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001713 ee_id, credentials = await self.vca_map[
1714 vca_type
1715 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001716 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001717 reuse_ee_id=ee_id,
1718 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001719 config=osm_config,
1720 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001721 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001722 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001723 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001724 else:
1725 ee_id, credentials = await self.vca_map[
1726 vca_type
1727 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001728 namespace=namespace,
1729 reuse_ee_id=ee_id,
1730 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001731 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001732 )
quilesj3655ae02019-12-12 16:08:35 +00001733
tierno588547c2020-07-01 15:30:20 +00001734 elif vca_type == "native_charm":
1735 step = "Waiting to VM being up and getting IP address"
1736 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001737 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1738 logging_text,
1739 nsr_id,
1740 vnfr_id,
1741 vdu_id,
1742 vdu_index,
1743 user=None,
1744 pub_key=None,
1745 )
tierno588547c2020-07-01 15:30:20 +00001746 credentials = {"hostname": rw_mgmt_ip}
1747 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001748 username = deep_get(
1749 config_descriptor, ("config-access", "ssh-access", "default-user")
1750 )
tierno588547c2020-07-01 15:30:20 +00001751 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1752 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001753 if not username and initial_config_primitive_list:
1754 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001755 for param in config_primitive.get("parameter", ()):
1756 if param["name"] == "ssh-username":
1757 username = param["value"]
1758 break
1759 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001760 raise LcmException(
1761 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1762 "'config-access.ssh-access.default-user'"
1763 )
tierno588547c2020-07-01 15:30:20 +00001764 credentials["username"] = username
1765 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001766
tierno588547c2020-07-01 15:30:20 +00001767 self._write_configuration_status(
1768 nsr_id=nsr_id,
1769 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001770 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001771 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001772 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001773 )
quilesj3655ae02019-12-12 16:08:35 +00001774
tierno588547c2020-07-01 15:30:20 +00001775 step = "register execution environment {}".format(credentials)
1776 self.logger.debug(logging_text + step)
1777 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001778 credentials=credentials,
1779 namespace=namespace,
1780 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001781 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001782 )
tierno3bedc9b2019-11-27 15:46:57 +00001783
tierno588547c2020-07-01 15:30:20 +00001784 # for compatibility with MON/POL modules, the need model and application name at database
1785 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001786 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001787 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1788 if len(ee_id_parts) >= 2:
1789 model_name = ee_id_parts[0]
1790 application_name = ee_id_parts[1]
1791 db_nsr_update[db_update_entry + "model"] = model_name
1792 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001793
1794 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001795 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001796
tiernoc231a872020-01-21 08:49:05 +00001797 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001798 nsr_id=nsr_id,
1799 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001800 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001801 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001802 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001803 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001804 )
1805
tierno3bedc9b2019-11-27 15:46:57 +00001806 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001807 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001808 config = None
tierno588547c2020-07-01 15:30:20 +00001809 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001810 config_primitive = next(
1811 (p for p in initial_config_primitive_list if p["name"] == "config"),
1812 None,
1813 )
tiernoa278b842020-07-08 15:33:55 +00001814 if config_primitive:
1815 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001816 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001817 )
tierno588547c2020-07-01 15:30:20 +00001818 num_units = 1
1819 if vca_type == "lxc_proxy_charm":
1820 if element_type == "NS":
1821 num_units = db_nsr.get("config-units") or 1
1822 elif element_type == "VNF":
1823 num_units = db_vnfr.get("config-units") or 1
1824 elif element_type == "VDU":
1825 for v in db_vnfr["vdur"]:
1826 if vdu_id == v["vdu-id-ref"]:
1827 num_units = v.get("config-units") or 1
1828 break
David Garciaaae391f2020-11-09 11:12:54 +01001829 if vca_type != "k8s_proxy_charm":
1830 await self.vca_map[vca_type].install_configuration_sw(
1831 ee_id=ee_id,
1832 artifact_path=artifact_path,
1833 db_dict=db_dict,
1834 config=config,
1835 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001836 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001837 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001838 )
quilesj7e13aeb2019-10-08 13:34:55 +02001839
quilesj63f90042020-01-17 09:53:55 +00001840 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001841 self.update_db_2(
1842 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1843 )
quilesj63f90042020-01-17 09:53:55 +00001844
1845 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001846 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001847 logging_text=logging_text,
1848 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001849 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001850 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001851 )
quilesj63f90042020-01-17 09:53:55 +00001852
Patricia Reinosob4312c02023-01-06 22:28:44 +00001853 if not is_relation_added:
1854 raise LcmException("Relations could not be added to VCA.")
1855
quilesj7e13aeb2019-10-08 13:34:55 +02001856 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001857 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001858 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001859 pub_key = None
1860 user = None
tierno588547c2020-07-01 15:30:20 +00001861 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001862 if deep_get(
1863 config_descriptor, ("config-access", "ssh-access", "required")
1864 ):
tierno588547c2020-07-01 15:30:20 +00001865 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001866 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001867 user = deep_get(
1868 config_descriptor,
1869 ("config-access", "ssh-access", "default-user"),
1870 )
tierno3bedc9b2019-11-27 15:46:57 +00001871 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001872 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001873 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001874 )
quilesj7e13aeb2019-10-08 13:34:55 +02001875
garciadeblas5697b8b2021-03-24 09:17:02 +01001876 step = "Insert public key into VM user={} ssh_key={}".format(
1877 user, pub_key
1878 )
tierno3bedc9b2019-11-27 15:46:57 +00001879 else:
tierno588547c2020-07-01 15:30:20 +00001880 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001881 step = "Waiting to VM being up and getting IP address"
1882 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001883
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001884 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1885 rw_mgmt_ip = None
1886
tierno3bedc9b2019-11-27 15:46:57 +00001887 # n2vc_redesign STEP 5.1
1888 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001889 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001890 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001891 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001892 logging_text, nsr_id, vnfr_id, kdu_name
1893 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001894 vnfd = self.db.get_one(
1895 "vnfds_revisions",
1896 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1897 )
1898 kdu = get_kdu(vnfd, kdu_name)
1899 kdu_services = [
1900 service["name"] for service in get_kdu_services(kdu)
1901 ]
1902 exposed_services = []
1903 for service in services:
1904 if any(s in service["name"] for s in kdu_services):
1905 exposed_services.append(service)
1906 await self.vca_map[vca_type].exec_primitive(
1907 ee_id=ee_id,
1908 primitive_name="config",
1909 params_dict={
1910 "osm-config": json.dumps(
1911 OsmConfigBuilder(
1912 k8s={"services": exposed_services}
1913 ).build()
1914 )
1915 },
1916 vca_id=vca_id,
1917 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001918
1919 # This verification is needed in order to avoid trying to add a public key
1920 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1921 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1922 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1923 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001924 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001925 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1926 logging_text,
1927 nsr_id,
1928 vnfr_id,
1929 vdu_id,
1930 vdu_index,
1931 user=user,
1932 pub_key=pub_key,
1933 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001934
garciadeblas5697b8b2021-03-24 09:17:02 +01001935 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001936
tiernoa5088192019-11-26 16:12:53 +00001937 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001938 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001939
1940 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001941 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001942
1943 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001944 if initial_config_primitive_list:
1945 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001946
1947 # stage, in function of element type: vdu, kdu, vnf or ns
1948 my_vca = vca_deployed_list[vca_index]
1949 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1950 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001951 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001952 elif my_vca.get("member-vnf-index"):
1953 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001954 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001955 else:
1956 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001957 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00001958
tiernoc231a872020-01-21 08:49:05 +00001959 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01001960 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00001961 )
1962
garciadeblas5697b8b2021-03-24 09:17:02 +01001963 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00001964
tiernoe876f672020-02-13 14:34:48 +00001965 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001966 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001967 # adding information on the vca_deployed if it is a NS execution environment
1968 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001969 deploy_params["ns_config_info"] = json.dumps(
1970 self._get_ns_config_info(nsr_id)
1971 )
tiernod8323042019-08-09 11:32:23 +00001972 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01001973 primitive_params_ = self._map_primitive_params(
1974 initial_config_primitive, {}, deploy_params
1975 )
tierno3bedc9b2019-11-27 15:46:57 +00001976
garciadeblas5697b8b2021-03-24 09:17:02 +01001977 step = "execute primitive '{}' params '{}'".format(
1978 initial_config_primitive["name"], primitive_params_
1979 )
tiernod8323042019-08-09 11:32:23 +00001980 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001981 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001982 ee_id=ee_id,
1983 primitive_name=initial_config_primitive["name"],
1984 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02001985 db_dict=db_dict,
1986 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001987 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02001988 )
tiernoe876f672020-02-13 14:34:48 +00001989 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1990 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01001991 if config_descriptor.get("terminate-config-primitive"):
1992 self.update_db_2(
1993 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
1994 )
tiernoe876f672020-02-13 14:34:48 +00001995 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001996
tiernod8323042019-08-09 11:32:23 +00001997 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001998
tiernob996d942020-07-03 14:52:28 +00001999 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00002000 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02002001 # TODO: review for those cases where the helm chart is a reference and
2002 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002003 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002004 ee_id=ee_id,
2005 artifact_path=artifact_path,
2006 ee_config_descriptor=ee_config_descriptor,
2007 vnfr_id=vnfr_id,
2008 nsr_id=nsr_id,
2009 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002010 element_type=element_type,
2011 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2012 vdu_id=vdu_id,
2013 vdu_index=vdu_index,
2014 kdu_name=kdu_name,
2015 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002016 )
2017 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002018 self.update_db_2(
2019 "nsrs",
2020 nsr_id,
2021 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2022 )
tiernob996d942020-07-03 14:52:28 +00002023
bravof73bac502021-05-11 07:38:47 -04002024 for job in prometheus_jobs:
2025 self.db.set_one(
2026 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002027 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002028 job,
2029 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002030 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002031 )
2032
quilesj7e13aeb2019-10-08 13:34:55 +02002033 step = "instantiated at VCA"
2034 self.logger.debug(logging_text + step)
2035
tiernoc231a872020-01-21 08:49:05 +00002036 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002037 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002038 )
2039
tiernod8323042019-08-09 11:32:23 +00002040 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002041 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002042 if not isinstance(
2043 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2044 ):
2045 self.logger.error(
2046 "Exception while {} : {}".format(step, e), exc_info=True
2047 )
tiernoc231a872020-01-21 08:49:05 +00002048 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002049 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002050 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002051 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002052
garciadeblas5697b8b2021-03-24 09:17:02 +01002053 def _write_ns_status(
2054 self,
2055 nsr_id: str,
2056 ns_state: str,
2057 current_operation: str,
2058 current_operation_id: str,
2059 error_description: str = None,
2060 error_detail: str = None,
2061 other_update: dict = None,
2062 ):
tiernoe876f672020-02-13 14:34:48 +00002063 """
2064 Update db_nsr fields.
2065 :param nsr_id:
2066 :param ns_state:
2067 :param current_operation:
2068 :param current_operation_id:
2069 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002070 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002071 :param other_update: Other required changes at database if provided, will be cleared
2072 :return:
2073 """
quilesj4cda56b2019-12-05 10:02:20 +00002074 try:
tiernoe876f672020-02-13 14:34:48 +00002075 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002076 db_dict[
2077 "_admin.nslcmop"
2078 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002079 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002080 db_dict["_admin.operation-type"] = (
2081 current_operation if current_operation != "IDLE" else None
2082 )
quilesj4cda56b2019-12-05 10:02:20 +00002083 db_dict["currentOperation"] = current_operation
2084 db_dict["currentOperationID"] = current_operation_id
2085 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002086 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002087
2088 if ns_state:
2089 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002090 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002091 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002092 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002093
garciadeblas5697b8b2021-03-24 09:17:02 +01002094 def _write_op_status(
2095 self,
2096 op_id: str,
2097 stage: list = None,
2098 error_message: str = None,
2099 queuePosition: int = 0,
2100 operation_state: str = None,
2101 other_update: dict = None,
2102 ):
quilesj3655ae02019-12-12 16:08:35 +00002103 try:
tiernoe876f672020-02-13 14:34:48 +00002104 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002105 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002106 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002107 db_dict["stage"] = stage[0]
2108 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002109 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002110 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002111
2112 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002113 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002114 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002115 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002116 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002117 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002118 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002119 self.logger.warn(
2120 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2121 )
quilesj3655ae02019-12-12 16:08:35 +00002122
tierno51183952020-04-03 15:48:18 +00002123 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002124 try:
tierno51183952020-04-03 15:48:18 +00002125 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002126 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002127 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002128 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002129 db_nsr_update = {
2130 "configurationStatus.{}.status".format(index): status
2131 for index, v in enumerate(config_status)
2132 if v
2133 }
quilesj3655ae02019-12-12 16:08:35 +00002134 # update status
tierno51183952020-04-03 15:48:18 +00002135 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002136
tiernoe876f672020-02-13 14:34:48 +00002137 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002138 self.logger.warn(
2139 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2140 )
quilesj3655ae02019-12-12 16:08:35 +00002141
garciadeblas5697b8b2021-03-24 09:17:02 +01002142 def _write_configuration_status(
2143 self,
2144 nsr_id: str,
2145 vca_index: int,
2146 status: str = None,
2147 element_under_configuration: str = None,
2148 element_type: str = None,
2149 other_update: dict = None,
2150 ):
quilesj3655ae02019-12-12 16:08:35 +00002151 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2152 # .format(vca_index, status))
2153
2154 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002155 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002156 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002157 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002158 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002159 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002160 db_dict[
2161 db_path + "elementUnderConfiguration"
2162 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002163 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002164 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002165 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002166 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002167 self.logger.warn(
2168 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2169 status, nsr_id, vca_index, e
2170 )
2171 )
quilesj4cda56b2019-12-05 10:02:20 +00002172
tierno38089af2020-04-16 07:56:58 +00002173 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2174 """
2175 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2176 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2177 Database is used because the result can be obtained from a different LCM worker in case of HA.
2178 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2179 :param db_nslcmop: database content of nslcmop
2180 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002181 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2182 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002183 """
tierno8790a3d2020-04-23 22:49:52 +00002184 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002185 nslcmop_id = db_nslcmop["_id"]
2186 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002187 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002188 self.logger.debug(
2189 logging_text + "Invoke and wait for placement optimization"
2190 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002191 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002192 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002193 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002194 pla_result = None
2195 while not pla_result and wait >= 0:
2196 await asyncio.sleep(db_poll_interval)
2197 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002198 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002199 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002200
2201 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002202 raise LcmException(
2203 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2204 )
magnussonle9198bb2020-01-21 13:00:51 +01002205
garciadeblas5697b8b2021-03-24 09:17:02 +01002206 for pla_vnf in pla_result["vnf"]:
2207 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2208 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002209 continue
tierno8790a3d2020-04-23 22:49:52 +00002210 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002211 self.db.set_one(
2212 "vnfrs",
2213 {"_id": vnfr["_id"]},
2214 {"vim-account-id": pla_vnf["vimAccountId"]},
2215 )
tierno38089af2020-04-16 07:56:58 +00002216 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002217 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002218 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002219
aguilard1ae3c562023-02-16 17:24:35 +00002220 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2221 alerts = []
2222 nsr_id = vnfr["nsr-id-ref"]
2223 df = vnfd.get("df", [{}])[0]
2224 # Checking for auto-healing configuration
2225 if "healing-aspect" in df:
2226 healing_aspects = df["healing-aspect"]
2227 for healing in healing_aspects:
2228 for healing_policy in healing.get("healing-policy", ()):
2229 vdu_id = healing_policy["vdu-id"]
2230 vdur = next(
2231 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2232 {},
2233 )
2234 if not vdur:
2235 continue
2236 metric_name = "vm_status"
2237 vdu_name = vdur.get("name")
2238 vnf_member_index = vnfr["member-vnf-index-ref"]
2239 uuid = str(uuid4())
2240 name = f"healing_{uuid}"
2241 action = healing_policy
2242 # action_on_recovery = healing.get("action-on-recovery")
2243 # cooldown_time = healing.get("cooldown-time")
2244 # day1 = healing.get("day1")
2245 alert = {
2246 "uuid": uuid,
2247 "name": name,
2248 "metric": metric_name,
2249 "tags": {
2250 "ns_id": nsr_id,
2251 "vnf_member_index": vnf_member_index,
2252 "vdu_name": vdu_name,
2253 },
2254 "alarm_status": "ok",
2255 "action_type": "healing",
2256 "action": action,
2257 }
2258 alerts.append(alert)
2259 return alerts
2260
2261 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2262 alerts = []
2263 nsr_id = vnfr["nsr-id-ref"]
2264 df = vnfd.get("df", [{}])[0]
2265 # Checking for auto-scaling configuration
2266 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002267 scaling_aspects = df["scaling-aspect"]
2268 all_vnfd_monitoring_params = {}
2269 for ivld in vnfd.get("int-virtual-link-desc", ()):
2270 for mp in ivld.get("monitoring-parameters", ()):
2271 all_vnfd_monitoring_params[mp.get("id")] = mp
2272 for vdu in vnfd.get("vdu", ()):
2273 for mp in vdu.get("monitoring-parameter", ()):
2274 all_vnfd_monitoring_params[mp.get("id")] = mp
2275 for df in vnfd.get("df", ()):
2276 for mp in df.get("monitoring-parameter", ()):
2277 all_vnfd_monitoring_params[mp.get("id")] = mp
2278 for scaling_aspect in scaling_aspects:
2279 scaling_group_name = scaling_aspect.get("name", "")
2280 # Get monitored VDUs
2281 all_monitored_vdus = set()
2282 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2283 "deltas", ()
2284 ):
2285 for vdu_delta in delta.get("vdu-delta", ()):
2286 all_monitored_vdus.add(vdu_delta.get("id"))
2287 monitored_vdurs = list(
2288 filter(
2289 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2290 vnfr["vdur"],
2291 )
2292 )
2293 if not monitored_vdurs:
2294 self.logger.error(
2295 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2296 )
2297 continue
2298 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2299 if scaling_policy["scaling-type"] != "automatic":
2300 continue
2301 threshold_time = scaling_policy.get("threshold-time", "1")
2302 cooldown_time = scaling_policy.get("cooldown-time", "0")
2303 for scaling_criteria in scaling_policy["scaling-criteria"]:
2304 monitoring_param_ref = scaling_criteria.get(
2305 "vnf-monitoring-param-ref"
2306 )
2307 vnf_monitoring_param = all_vnfd_monitoring_params[
2308 monitoring_param_ref
2309 ]
2310 for vdur in monitored_vdurs:
2311 vdu_id = vdur["vdu-id-ref"]
2312 metric_name = vnf_monitoring_param.get("performance-metric")
Rahul Kumar54671c52024-05-09 15:34:01 +05302313 if "exporters-endpoints" not in df:
2314 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002315 vnf_member_index = vnfr["member-vnf-index-ref"]
2316 scalein_threshold = scaling_criteria.get(
2317 "scale-in-threshold"
2318 )
2319 scaleout_threshold = scaling_criteria.get(
2320 "scale-out-threshold"
2321 )
2322 # Looking for min/max-number-of-instances
2323 instances_min_number = 1
2324 instances_max_number = 1
2325 vdu_profile = df["vdu-profile"]
2326 if vdu_profile:
2327 profile = next(
2328 item for item in vdu_profile if item["id"] == vdu_id
2329 )
2330 instances_min_number = profile.get(
2331 "min-number-of-instances", 1
2332 )
2333 instances_max_number = profile.get(
2334 "max-number-of-instances", 1
2335 )
2336
2337 if scalein_threshold:
2338 uuid = str(uuid4())
2339 name = f"scalein_{uuid}"
2340 operation = scaling_criteria[
2341 "scale-in-relational-operation"
2342 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002343 rel_operator = self.rel_operation_types.get(
2344 operation, "<="
2345 )
aguilard1ae3c562023-02-16 17:24:35 +00002346 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2347 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302348 if (
2349 "exporters-endpoints" in df
2350 and metric_name.startswith("kpi_")
2351 ):
2352 new_metric_name = (
2353 f'osm_{metric_name.replace("kpi_", "").strip()}'
2354 )
2355 metric_port = df["exporters-endpoints"].get(
2356 "metric-port", 9100
2357 )
2358 vdu_ip = vdur["ip-address"]
2359 ip_port = str(vdu_ip) + ":" + str(metric_port)
2360 metric_selector = (
2361 f'{new_metric_name}{{instance="{ip_port}"}}'
2362 )
2363 expression = f"({metric_selector} {rel_operator} {scalein_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002364 labels = {
2365 "ns_id": nsr_id,
2366 "vnf_member_index": vnf_member_index,
2367 "vdu_id": vdu_id,
2368 }
2369 prom_cfg = {
2370 "alert": name,
2371 "expr": expression,
2372 "for": str(threshold_time) + "m",
2373 "labels": labels,
2374 }
2375 action = scaling_policy
2376 action = {
2377 "scaling-group": scaling_group_name,
2378 "cooldown-time": cooldown_time,
2379 }
2380 alert = {
2381 "uuid": uuid,
2382 "name": name,
2383 "metric": metric_name,
2384 "tags": {
2385 "ns_id": nsr_id,
2386 "vnf_member_index": vnf_member_index,
2387 "vdu_id": vdu_id,
2388 },
2389 "alarm_status": "ok",
2390 "action_type": "scale_in",
2391 "action": action,
2392 "prometheus_config": prom_cfg,
2393 }
2394 alerts.append(alert)
2395
2396 if scaleout_threshold:
2397 uuid = str(uuid4())
2398 name = f"scaleout_{uuid}"
2399 operation = scaling_criteria[
2400 "scale-out-relational-operation"
2401 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002402 rel_operator = self.rel_operation_types.get(
2403 operation, "<="
2404 )
aguilard1ae3c562023-02-16 17:24:35 +00002405 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2406 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302407 if (
2408 "exporters-endpoints" in df
2409 and metric_name.startswith("kpi_")
2410 ):
2411 new_metric_name = (
2412 f'osm_{metric_name.replace("kpi_", "").strip()}'
2413 )
2414 metric_port = df["exporters-endpoints"].get(
2415 "metric-port", 9100
2416 )
2417 vdu_ip = vdur["ip-address"]
2418 ip_port = str(vdu_ip) + ":" + str(metric_port)
2419 metric_selector = (
2420 f'{new_metric_name}{{instance="{ip_port}"}}'
2421 )
2422 expression = f"({metric_selector} {rel_operator} {scaleout_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002423 labels = {
2424 "ns_id": nsr_id,
2425 "vnf_member_index": vnf_member_index,
2426 "vdu_id": vdu_id,
2427 }
2428 prom_cfg = {
2429 "alert": name,
2430 "expr": expression,
2431 "for": str(threshold_time) + "m",
2432 "labels": labels,
2433 }
2434 action = scaling_policy
2435 action = {
2436 "scaling-group": scaling_group_name,
2437 "cooldown-time": cooldown_time,
2438 }
2439 alert = {
2440 "uuid": uuid,
2441 "name": name,
2442 "metric": metric_name,
2443 "tags": {
2444 "ns_id": nsr_id,
2445 "vnf_member_index": vnf_member_index,
2446 "vdu_id": vdu_id,
2447 },
2448 "alarm_status": "ok",
2449 "action_type": "scale_out",
2450 "action": action,
2451 "prometheus_config": prom_cfg,
2452 }
2453 alerts.append(alert)
2454 return alerts
2455
garciadeblas9148fa82023-05-30 12:51:14 +02002456 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2457 alerts = []
2458 nsr_id = vnfr["nsr-id-ref"]
2459 vnf_member_index = vnfr["member-vnf-index-ref"]
2460
2461 # Checking for VNF alarm configuration
2462 for vdur in vnfr["vdur"]:
2463 vdu_id = vdur["vdu-id-ref"]
2464 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2465 if "alarm" in vdu:
2466 # Get VDU monitoring params, since alerts are based on them
2467 vdu_monitoring_params = {}
2468 for mp in vdu.get("monitoring-parameter", []):
2469 vdu_monitoring_params[mp.get("id")] = mp
2470 if not vdu_monitoring_params:
2471 self.logger.error(
2472 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2473 )
2474 continue
2475 # Get alarms in the VDU
2476 alarm_descriptors = vdu["alarm"]
2477 # Create VDU alarms for each alarm in the VDU
2478 for alarm_descriptor in alarm_descriptors:
2479 # Check that the VDU alarm refers to a proper monitoring param
2480 alarm_monitoring_param = alarm_descriptor.get(
2481 "vnf-monitoring-param-ref", ""
2482 )
2483 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2484 alarm_monitoring_param, {}
2485 )
2486 if not vdu_specific_monitoring_param:
2487 self.logger.error(
2488 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2489 )
2490 continue
2491 metric_name = vdu_specific_monitoring_param.get(
2492 "performance-metric"
2493 )
2494 if not metric_name:
2495 self.logger.error(
2496 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2497 )
2498 continue
2499 # Set params of the alarm to be created in Prometheus
2500 metric_name = f"osm_{metric_name}"
2501 metric_threshold = alarm_descriptor.get("value")
2502 uuid = str(uuid4())
2503 alert_name = f"vdu_alarm_{uuid}"
2504 operation = alarm_descriptor["operation"]
2505 rel_operator = self.rel_operation_types.get(operation, "<=")
2506 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 +00002507 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002508 labels = {
2509 "ns_id": nsr_id,
2510 "vnf_member_index": vnf_member_index,
2511 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002512 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002513 }
2514 prom_cfg = {
2515 "alert": alert_name,
2516 "expr": expression,
2517 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2518 "labels": labels,
2519 }
2520 alarm_action = dict()
2521 for action_type in ["ok", "insufficient-data", "alarm"]:
2522 if (
2523 "actions" in alarm_descriptor
2524 and action_type in alarm_descriptor["actions"]
2525 ):
aguilardeb076722023-05-31 09:45:00 +00002526 alarm_action[action_type] = alarm_descriptor["actions"][
2527 action_type
2528 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002529 alert = {
2530 "uuid": uuid,
2531 "name": alert_name,
2532 "metric": metric_name,
2533 "tags": {
2534 "ns_id": nsr_id,
2535 "vnf_member_index": vnf_member_index,
2536 "vdu_id": vdu_id,
2537 },
2538 "alarm_status": "ok",
2539 "action_type": "vdu_alarm",
2540 "action": alarm_action,
2541 "prometheus_config": prom_cfg,
2542 }
2543 alerts.append(alert)
2544 return alerts
2545
magnussonle9198bb2020-01-21 13:00:51 +01002546 def update_nsrs_with_pla_result(self, params):
2547 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002548 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2549 self.update_db_2(
2550 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2551 )
magnussonle9198bb2020-01-21 13:00:51 +01002552 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002553 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002554
tierno59d22d22018-09-25 18:10:19 +02002555 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002556 """
2557
2558 :param nsr_id: ns instance to deploy
2559 :param nslcmop_id: operation to run
2560 :return:
2561 """
kuused124bfe2019-06-18 12:09:24 +02002562
2563 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002564 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002565 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002566 self.logger.debug(
2567 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2568 )
kuused124bfe2019-06-18 12:09:24 +02002569 return
2570
tierno59d22d22018-09-25 18:10:19 +02002571 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2572 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002573
tierno59d22d22018-09-25 18:10:19 +02002574 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002575
2576 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002577 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002578
2579 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002580 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002581
2582 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002583 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002584 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002585 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002586
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002587 timeout_ns_deploy = self.timeout.ns_deploy
2588
tierno59d22d22018-09-25 18:10:19 +02002589 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002590 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002591 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002592 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002593 exc = None
tiernoe876f672020-02-13 14:34:48 +00002594 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002595 stage = [
2596 "Stage 1/5: preparation of the environment.",
2597 "Waiting for previous operations to terminate.",
2598 "",
2599 ]
tiernoe876f672020-02-13 14:34:48 +00002600 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002601 try:
kuused124bfe2019-06-18 12:09:24 +02002602 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002603 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002604
quilesj7e13aeb2019-10-08 13:34:55 +02002605 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002606 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002607 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002608 db_nsr_update["detailed-status"] = "creating"
2609 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002610 self._write_ns_status(
2611 nsr_id=nsr_id,
2612 ns_state="BUILDING",
2613 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002614 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002615 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002616 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002617 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002618
quilesj7e13aeb2019-10-08 13:34:55 +02002619 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002620 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002621 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002622 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2623 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2624 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2625 )
tierno744303e2020-01-13 16:46:31 +00002626 ns_params = db_nslcmop.get("operationParams")
2627 if ns_params and ns_params.get("timeout_ns_deploy"):
2628 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002629
2630 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002631 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002632 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002633 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002634 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002635 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002636 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002637 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002638 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002639 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002640
quilesj7e13aeb2019-10-08 13:34:55 +02002641 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002642 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002643 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002644 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002645
quilesj7e13aeb2019-10-08 13:34:55 +02002646 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002647 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002648
2649 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002650 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002651 if vnfr.get("kdur"):
2652 kdur_list = []
2653 for kdur in vnfr["kdur"]:
2654 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002655 kdur["additionalParams"] = json.loads(
2656 kdur["additionalParams"]
2657 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002658 kdur_list.append(kdur)
2659 vnfr["kdur"] = kdur_list
2660
bravof922c4172020-11-24 21:21:43 -03002661 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2662 vnfd_id = vnfr["vnfd-id"]
2663 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002664 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002665
quilesj7e13aeb2019-10-08 13:34:55 +02002666 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002667 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002668 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002669 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2670 vnfd_id, vnfd_ref
2671 )
tiernoe876f672020-02-13 14:34:48 +00002672 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002673 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002674
quilesj7e13aeb2019-10-08 13:34:55 +02002675 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002676 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002677
2678 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002679 vca_deployed_list = None
2680 if db_nsr["_admin"].get("deployed"):
2681 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2682 if vca_deployed_list is None:
2683 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002684 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002685 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002686 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002687 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002688 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002689 elif isinstance(vca_deployed_list, dict):
2690 # maintain backward compatibility. Change a dict to list at database
2691 vca_deployed_list = list(vca_deployed_list.values())
2692 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002693 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002694
garciadeblas5697b8b2021-03-24 09:17:02 +01002695 if not isinstance(
2696 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2697 ):
tiernoa009e552019-01-30 16:45:44 +00002698 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2699 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002700
tiernobaa51102018-12-14 13:16:18 +00002701 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2702 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2703 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002704 self.db.set_list(
2705 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2706 )
quilesj3655ae02019-12-12 16:08:35 +00002707
2708 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002709 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2710 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002711
tiernob5203912020-08-11 11:20:13 +00002712 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002713 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002714 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002715 await self.deploy_kdus(
2716 logging_text=logging_text,
2717 nsr_id=nsr_id,
2718 nslcmop_id=nslcmop_id,
2719 db_vnfrs=db_vnfrs,
2720 db_vnfds=db_vnfds,
2721 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002722 )
tiernoe876f672020-02-13 14:34:48 +00002723
2724 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002725 # n2vc_redesign STEP 1 Get VCA public ssh-key
2726 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002727 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002728 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002729 if self.vca_config.public_key:
2730 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002731
tiernoe876f672020-02-13 14:34:48 +00002732 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002733 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002734 self.instantiate_RO(
2735 logging_text=logging_text,
2736 nsr_id=nsr_id,
2737 nsd=nsd,
2738 db_nsr=db_nsr,
2739 db_nslcmop=db_nslcmop,
2740 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002741 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002742 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002743 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002744 )
tiernod8323042019-08-09 11:32:23 +00002745 )
2746 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002747 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002748
tiernod8323042019-08-09 11:32:23 +00002749 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002750 stage[1] = "Deploying Execution Environments."
2751 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002752
Gabriel Cuba1411a002022-10-07 11:38:23 -05002753 # create namespace and certificate if any helm based EE is present in the NS
2754 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002755 await self.vca_map["helm-v3"].setup_ns_namespace(
2756 name=nsr_id,
2757 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002758 # create TLS certificates
2759 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002760 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002761 dns_prefix="*",
2762 nsr_id=nsr_id,
2763 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002764 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002765 )
2766
tiernod8323042019-08-09 11:32:23 +00002767 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002768 for vnf_profile in get_vnf_profiles(nsd):
2769 vnfd_id = vnf_profile["vnfd-id"]
2770 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2771 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002772 db_vnfr = db_vnfrs[member_vnf_index]
2773 base_folder = vnfd["_admin"]["storage"]
2774 vdu_id = None
2775 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002776 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002777 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002778 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002779
tierno8a518872018-12-21 13:42:14 +00002780 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002781 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002782 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002783 deploy_params.update(
2784 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2785 )
tierno8a518872018-12-21 13:42:14 +00002786
bravofe5a31bc2021-02-17 19:09:12 -03002787 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002788 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002789 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002790 logging_text=logging_text
2791 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002792 db_nsr=db_nsr,
2793 db_vnfr=db_vnfr,
2794 nslcmop_id=nslcmop_id,
2795 nsr_id=nsr_id,
2796 nsi_id=nsi_id,
2797 vnfd_id=vnfd_id,
2798 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002799 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002800 member_vnf_index=member_vnf_index,
2801 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002802 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002803 vdu_name=vdu_name,
2804 deploy_params=deploy_params,
2805 descriptor_config=descriptor_config,
2806 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002807 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002808 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002809 )
tierno59d22d22018-09-25 18:10:19 +02002810
2811 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002812 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002813 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002814 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002815 vdur = find_in_list(
2816 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2817 )
bravof922c4172020-11-24 21:21:43 -03002818
tierno626e0152019-11-29 14:16:16 +00002819 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002820 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002821 else:
2822 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002823 deploy_params_vdu["OSM"] = get_osm_params(
2824 db_vnfr, vdu_id, vdu_count_index=0
2825 )
endika76ba9232021-06-21 18:55:07 +02002826 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002827
2828 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002829 self.logger.debug(
2830 "Descriptor config > {}".format(descriptor_config)
2831 )
tierno588547c2020-07-01 15:30:20 +00002832 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002833 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002834 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002835 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002836 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002837 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002838 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002839 logging_text=logging_text
2840 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2841 member_vnf_index, vdu_id, vdu_index
2842 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002843 db_nsr=db_nsr,
2844 db_vnfr=db_vnfr,
2845 nslcmop_id=nslcmop_id,
2846 nsr_id=nsr_id,
2847 nsi_id=nsi_id,
2848 vnfd_id=vnfd_id,
2849 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002850 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002851 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002852 member_vnf_index=member_vnf_index,
2853 vdu_index=vdu_index,
2854 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002855 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002856 descriptor_config=descriptor_config,
2857 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002858 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002859 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002860 )
bravof922c4172020-11-24 21:21:43 -03002861 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002862 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002863 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002864 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002865 vdu_id = None
2866 vdu_index = 0
2867 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002868 kdu_index, kdur = next(
2869 x
2870 for x in enumerate(db_vnfr["kdur"])
2871 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002872 )
bravof922c4172020-11-24 21:21:43 -03002873 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002874 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002875 deploy_params_kdu.update(
2876 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002877 )
tierno59d22d22018-09-25 18:10:19 +02002878
calvinosanch9f9c6f22019-11-04 13:37:39 +01002879 self._deploy_n2vc(
2880 logging_text=logging_text,
2881 db_nsr=db_nsr,
2882 db_vnfr=db_vnfr,
2883 nslcmop_id=nslcmop_id,
2884 nsr_id=nsr_id,
2885 nsi_id=nsi_id,
2886 vnfd_id=vnfd_id,
2887 vdu_id=vdu_id,
2888 kdu_name=kdu_name,
2889 member_vnf_index=member_vnf_index,
2890 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002891 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002892 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002893 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002894 descriptor_config=descriptor_config,
2895 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002896 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002897 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002898 )
tierno59d22d22018-09-25 18:10:19 +02002899
k4.rahul74944982023-04-19 17:00:52 +05302900 # Check if each vnf has exporter for metric collection if so update prometheus job records
2901 if "exporters-endpoints" in vnfd.get("df")[0]:
2902 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2903 self.logger.debug("exporter config :{}".format(exporter_config))
2904 artifact_path = "{}/{}/{}".format(
2905 base_folder["folder"],
2906 base_folder["pkg-dir"],
2907 "exporter-endpoint",
2908 )
2909 ee_id = None
2910 ee_config_descriptor = exporter_config
2911 vnfr_id = db_vnfr["id"]
2912 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2913 logging_text,
2914 nsr_id,
2915 vnfr_id,
2916 vdu_id=None,
2917 vdu_index=None,
2918 user=None,
2919 pub_key=None,
2920 )
2921 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2922 self.logger.debug("Artifact_path:{}".format(artifact_path))
2923 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2924 vdu_id_for_prom = None
2925 vdu_index_for_prom = None
2926 for x in get_iterable(db_vnfr, "vdur"):
2927 vdu_id_for_prom = x.get("vdu-id-ref")
2928 vdu_index_for_prom = x.get("count-index")
2929 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2930 ee_id=ee_id,
2931 artifact_path=artifact_path,
2932 ee_config_descriptor=ee_config_descriptor,
2933 vnfr_id=vnfr_id,
2934 nsr_id=nsr_id,
2935 target_ip=rw_mgmt_ip,
2936 element_type="VDU",
2937 vdu_id=vdu_id_for_prom,
2938 vdu_index=vdu_index_for_prom,
2939 )
2940
2941 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2942 if prometheus_jobs:
2943 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2944 self.update_db_2(
2945 "nsrs",
2946 nsr_id,
2947 db_nsr_update,
2948 )
2949
2950 for job in prometheus_jobs:
2951 self.db.set_one(
2952 "prometheus_jobs",
2953 {"job_name": job["job_name"]},
2954 job,
2955 upsert=True,
2956 fail_on_empty=False,
2957 )
2958
tierno1b633412019-02-25 16:48:23 +00002959 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002960 descriptor_config = nsd.get("ns-configuration")
2961 if descriptor_config and descriptor_config.get("juju"):
2962 vnfd_id = None
2963 db_vnfr = None
2964 member_vnf_index = None
2965 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002966 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002967 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00002968 vdu_index = 0
2969 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002970
tiernod8323042019-08-09 11:32:23 +00002971 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002972 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002973 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002974 deploy_params.update(
2975 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2976 )
tiernod8323042019-08-09 11:32:23 +00002977 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002978 self._deploy_n2vc(
2979 logging_text=logging_text,
2980 db_nsr=db_nsr,
2981 db_vnfr=db_vnfr,
2982 nslcmop_id=nslcmop_id,
2983 nsr_id=nsr_id,
2984 nsi_id=nsi_id,
2985 vnfd_id=vnfd_id,
2986 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002987 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002988 member_vnf_index=member_vnf_index,
2989 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002990 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002991 vdu_name=vdu_name,
2992 deploy_params=deploy_params,
2993 descriptor_config=descriptor_config,
2994 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002995 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002996 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002997 )
tierno1b633412019-02-25 16:48:23 +00002998
tiernoe876f672020-02-13 14:34:48 +00002999 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00003000
garciadeblas5697b8b2021-03-24 09:17:02 +01003001 except (
3002 ROclient.ROClientException,
3003 DbException,
3004 LcmException,
3005 N2VCException,
3006 ) as e:
3007 self.logger.error(
3008 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3009 )
tierno59d22d22018-09-25 18:10:19 +02003010 exc = e
3011 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003012 self.logger.error(
3013 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3014 )
tierno59d22d22018-09-25 18:10:19 +02003015 exc = "Operation was cancelled"
3016 except Exception as e:
3017 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003018 self.logger.critical(
3019 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3020 exc_info=True,
3021 )
tierno59d22d22018-09-25 18:10:19 +02003022 finally:
3023 if exc:
tiernoe876f672020-02-13 14:34:48 +00003024 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003025 try:
tiernoe876f672020-02-13 14:34:48 +00003026 # wait for pending tasks
3027 if tasks_dict_info:
3028 stage[1] = "Waiting for instantiate pending tasks."
3029 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003030 error_list += await self._wait_for_tasks(
3031 logging_text,
3032 tasks_dict_info,
3033 timeout_ns_deploy,
3034 stage,
3035 nslcmop_id,
3036 nsr_id=nsr_id,
3037 )
tiernoe876f672020-02-13 14:34:48 +00003038 stage[1] = stage[2] = ""
3039 except asyncio.CancelledError:
3040 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003041 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3042 await self._wait_for_tasks(
3043 logging_text,
3044 tasks_dict_info,
3045 timeout_ns_deploy,
3046 stage,
3047 nslcmop_id,
3048 nsr_id=nsr_id,
3049 )
tiernoe876f672020-02-13 14:34:48 +00003050 except Exception as exc:
3051 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003052
tiernoe876f672020-02-13 14:34:48 +00003053 # update operation-status
3054 db_nsr_update["operational-status"] = "running"
3055 # let's begin with VCA 'configured' status (later we can change it)
3056 db_nsr_update["config-status"] = "configured"
3057 for task, task_name in tasks_dict_info.items():
3058 if not task.done() or task.cancelled() or task.exception():
3059 if task_name.startswith(self.task_name_deploy_vca):
3060 # A N2VC task is pending
3061 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003062 else:
tiernoe876f672020-02-13 14:34:48 +00003063 # RO or KDU task is pending
3064 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003065
tiernoe876f672020-02-13 14:34:48 +00003066 # update status at database
3067 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003068 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003069 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003070 error_description_nslcmop = "{} Detail: {}".format(
3071 stage[0], error_detail
3072 )
3073 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3074 nslcmop_id, stage[0]
3075 )
quilesj3655ae02019-12-12 16:08:35 +00003076
garciadeblas5697b8b2021-03-24 09:17:02 +01003077 db_nsr_update["detailed-status"] = (
3078 error_description_nsr + " Detail: " + error_detail
3079 )
tiernoe876f672020-02-13 14:34:48 +00003080 db_nslcmop_update["detailed-status"] = error_detail
3081 nslcmop_operation_state = "FAILED"
3082 ns_state = "BROKEN"
3083 else:
tiernoa2143262020-03-27 16:20:40 +00003084 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003085 error_description_nsr = error_description_nslcmop = None
3086 ns_state = "READY"
3087 db_nsr_update["detailed-status"] = "Done"
3088 db_nslcmop_update["detailed-status"] = "Done"
3089 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003090 # Gather auto-healing and auto-scaling alerts for each vnfr
3091 healing_alerts = []
3092 scaling_alerts = []
3093 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3094 vnfd = next(
3095 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3096 )
3097 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3098 for alert in healing_alerts:
3099 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3100 self.db.create("alerts", alert)
3101
3102 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3103 for alert in scaling_alerts:
3104 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3105 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003106
garciadeblas9148fa82023-05-30 12:51:14 +02003107 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3108 for alert in alarm_alerts:
3109 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3110 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003111 if db_nsr:
3112 self._write_ns_status(
3113 nsr_id=nsr_id,
3114 ns_state=ns_state,
3115 current_operation="IDLE",
3116 current_operation_id=None,
3117 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003118 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003119 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003120 )
tiernoa17d4f42020-04-28 09:59:23 +00003121 self._write_op_status(
3122 op_id=nslcmop_id,
3123 stage="",
3124 error_message=error_description_nslcmop,
3125 operation_state=nslcmop_operation_state,
3126 other_update=db_nslcmop_update,
3127 )
quilesj3655ae02019-12-12 16:08:35 +00003128
tierno59d22d22018-09-25 18:10:19 +02003129 if nslcmop_operation_state:
3130 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003131 await self.msg.aiowrite(
3132 "ns",
3133 "instantiated",
3134 {
3135 "nsr_id": nsr_id,
3136 "nslcmop_id": nslcmop_id,
3137 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003138 "startTime": db_nslcmop["startTime"],
3139 "links": db_nslcmop["links"],
3140 "operationParams": {
3141 "nsInstanceId": nsr_id,
3142 "nsdId": db_nsr["nsd-id"],
3143 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003144 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003145 )
tierno59d22d22018-09-25 18:10:19 +02003146 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003147 self.logger.error(
3148 logging_text + "kafka_write notification Exception {}".format(e)
3149 )
tierno59d22d22018-09-25 18:10:19 +02003150
3151 self.logger.debug(logging_text + "Exit")
3152 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3153
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003154 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003155 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003156 cached_vnfds[vnfd_id] = self.db.get_one(
3157 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3158 )
David Garciab4ebcd02021-10-28 02:00:43 +02003159 return cached_vnfds[vnfd_id]
3160
3161 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3162 if vnf_profile_id not in cached_vnfrs:
3163 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3164 "vnfrs",
3165 {
3166 "member-vnf-index-ref": vnf_profile_id,
3167 "nsr-id-ref": nsr_id,
3168 },
3169 )
3170 return cached_vnfrs[vnf_profile_id]
3171
3172 def _is_deployed_vca_in_relation(
3173 self, vca: DeployedVCA, relation: Relation
3174 ) -> bool:
3175 found = False
3176 for endpoint in (relation.provider, relation.requirer):
3177 if endpoint["kdu-resource-profile-id"]:
3178 continue
3179 found = (
3180 vca.vnf_profile_id == endpoint.vnf_profile_id
3181 and vca.vdu_profile_id == endpoint.vdu_profile_id
3182 and vca.execution_environment_ref == endpoint.execution_environment_ref
3183 )
3184 if found:
3185 break
3186 return found
3187
3188 def _update_ee_relation_data_with_implicit_data(
3189 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3190 ):
3191 ee_relation_data = safe_get_ee_relation(
3192 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3193 )
3194 ee_relation_level = EELevel.get_level(ee_relation_data)
3195 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3196 "execution-environment-ref"
3197 ]:
3198 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3199 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003200 project = nsd["_admin"]["projects_read"][0]
3201 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003202 entity_id = (
3203 vnfd_id
3204 if ee_relation_level == EELevel.VNF
3205 else ee_relation_data["vdu-profile-id"]
3206 )
3207 ee = get_juju_ee_ref(db_vnfd, entity_id)
3208 if not ee:
3209 raise Exception(
3210 f"not execution environments found for ee_relation {ee_relation_data}"
3211 )
3212 ee_relation_data["execution-environment-ref"] = ee["id"]
3213 return ee_relation_data
3214
3215 def _get_ns_relations(
3216 self,
3217 nsr_id: str,
3218 nsd: Dict[str, Any],
3219 vca: DeployedVCA,
3220 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003221 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003222 relations = []
3223 db_ns_relations = get_ns_configuration_relation_list(nsd)
3224 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003225 provider_dict = None
3226 requirer_dict = None
3227 if all(key in r for key in ("provider", "requirer")):
3228 provider_dict = r["provider"]
3229 requirer_dict = r["requirer"]
3230 elif "entities" in r:
3231 provider_id = r["entities"][0]["id"]
3232 provider_dict = {
3233 "nsr-id": nsr_id,
3234 "endpoint": r["entities"][0]["endpoint"],
3235 }
3236 if provider_id != nsd["id"]:
3237 provider_dict["vnf-profile-id"] = provider_id
3238 requirer_id = r["entities"][1]["id"]
3239 requirer_dict = {
3240 "nsr-id": nsr_id,
3241 "endpoint": r["entities"][1]["endpoint"],
3242 }
3243 if requirer_id != nsd["id"]:
3244 requirer_dict["vnf-profile-id"] = requirer_id
3245 else:
aticig15db6142022-01-24 12:51:26 +03003246 raise Exception(
3247 "provider/requirer or entities must be included in the relation."
3248 )
David Garciab4ebcd02021-10-28 02:00:43 +02003249 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003250 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003251 )
3252 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003253 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003254 )
3255 provider = EERelation(relation_provider)
3256 requirer = EERelation(relation_requirer)
3257 relation = Relation(r["name"], provider, requirer)
3258 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3259 if vca_in_relation:
3260 relations.append(relation)
3261 return relations
3262
3263 def _get_vnf_relations(
3264 self,
3265 nsr_id: str,
3266 nsd: Dict[str, Any],
3267 vca: DeployedVCA,
3268 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003269 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003270 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003271 if vca.target_element == "ns":
3272 self.logger.debug("VCA is a NS charm, not a VNF.")
3273 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003274 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3275 vnf_profile_id = vnf_profile["id"]
3276 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003277 project = nsd["_admin"]["projects_read"][0]
3278 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003279 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3280 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003281 provider_dict = None
3282 requirer_dict = None
3283 if all(key in r for key in ("provider", "requirer")):
3284 provider_dict = r["provider"]
3285 requirer_dict = r["requirer"]
3286 elif "entities" in r:
3287 provider_id = r["entities"][0]["id"]
3288 provider_dict = {
3289 "nsr-id": nsr_id,
3290 "vnf-profile-id": vnf_profile_id,
3291 "endpoint": r["entities"][0]["endpoint"],
3292 }
3293 if provider_id != vnfd_id:
3294 provider_dict["vdu-profile-id"] = provider_id
3295 requirer_id = r["entities"][1]["id"]
3296 requirer_dict = {
3297 "nsr-id": nsr_id,
3298 "vnf-profile-id": vnf_profile_id,
3299 "endpoint": r["entities"][1]["endpoint"],
3300 }
3301 if requirer_id != vnfd_id:
3302 requirer_dict["vdu-profile-id"] = requirer_id
3303 else:
aticig15db6142022-01-24 12:51:26 +03003304 raise Exception(
3305 "provider/requirer or entities must be included in the relation."
3306 )
David Garciab4ebcd02021-10-28 02:00:43 +02003307 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003308 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003309 )
3310 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003311 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003312 )
3313 provider = EERelation(relation_provider)
3314 requirer = EERelation(relation_requirer)
3315 relation = Relation(r["name"], provider, requirer)
3316 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3317 if vca_in_relation:
3318 relations.append(relation)
3319 return relations
3320
3321 def _get_kdu_resource_data(
3322 self,
3323 ee_relation: EERelation,
3324 db_nsr: Dict[str, Any],
3325 cached_vnfds: Dict[str, Any],
3326 ) -> DeployedK8sResource:
3327 nsd = get_nsd(db_nsr)
3328 vnf_profiles = get_vnf_profiles(nsd)
3329 vnfd_id = find_in_list(
3330 vnf_profiles,
3331 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3332 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003333 project = nsd["_admin"]["projects_read"][0]
3334 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003335 kdu_resource_profile = get_kdu_resource_profile(
3336 db_vnfd, ee_relation.kdu_resource_profile_id
3337 )
3338 kdu_name = kdu_resource_profile["kdu-name"]
3339 deployed_kdu, _ = get_deployed_kdu(
3340 db_nsr.get("_admin", ()).get("deployed", ()),
3341 kdu_name,
3342 ee_relation.vnf_profile_id,
3343 )
3344 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3345 return deployed_kdu
3346
3347 def _get_deployed_component(
3348 self,
3349 ee_relation: EERelation,
3350 db_nsr: Dict[str, Any],
3351 cached_vnfds: Dict[str, Any],
3352 ) -> DeployedComponent:
3353 nsr_id = db_nsr["_id"]
3354 deployed_component = None
3355 ee_level = EELevel.get_level(ee_relation)
3356 if ee_level == EELevel.NS:
3357 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3358 if vca:
3359 deployed_component = DeployedVCA(nsr_id, vca)
3360 elif ee_level == EELevel.VNF:
3361 vca = get_deployed_vca(
3362 db_nsr,
3363 {
3364 "vdu_id": None,
3365 "member-vnf-index": ee_relation.vnf_profile_id,
3366 "ee_descriptor_id": ee_relation.execution_environment_ref,
3367 },
3368 )
3369 if vca:
3370 deployed_component = DeployedVCA(nsr_id, vca)
3371 elif ee_level == EELevel.VDU:
3372 vca = get_deployed_vca(
3373 db_nsr,
3374 {
3375 "vdu_id": ee_relation.vdu_profile_id,
3376 "member-vnf-index": ee_relation.vnf_profile_id,
3377 "ee_descriptor_id": ee_relation.execution_environment_ref,
3378 },
3379 )
3380 if vca:
3381 deployed_component = DeployedVCA(nsr_id, vca)
3382 elif ee_level == EELevel.KDU:
3383 kdu_resource_data = self._get_kdu_resource_data(
3384 ee_relation, db_nsr, cached_vnfds
3385 )
3386 if kdu_resource_data:
3387 deployed_component = DeployedK8sResource(kdu_resource_data)
3388 return deployed_component
3389
3390 async def _add_relation(
3391 self,
3392 relation: Relation,
3393 vca_type: str,
3394 db_nsr: Dict[str, Any],
3395 cached_vnfds: Dict[str, Any],
3396 cached_vnfrs: Dict[str, Any],
3397 ) -> bool:
3398 deployed_provider = self._get_deployed_component(
3399 relation.provider, db_nsr, cached_vnfds
3400 )
3401 deployed_requirer = self._get_deployed_component(
3402 relation.requirer, db_nsr, cached_vnfds
3403 )
3404 if (
3405 deployed_provider
3406 and deployed_requirer
3407 and deployed_provider.config_sw_installed
3408 and deployed_requirer.config_sw_installed
3409 ):
3410 provider_db_vnfr = (
3411 self._get_vnfr(
3412 relation.provider.nsr_id,
3413 relation.provider.vnf_profile_id,
3414 cached_vnfrs,
3415 )
3416 if relation.provider.vnf_profile_id
3417 else None
3418 )
3419 requirer_db_vnfr = (
3420 self._get_vnfr(
3421 relation.requirer.nsr_id,
3422 relation.requirer.vnf_profile_id,
3423 cached_vnfrs,
3424 )
3425 if relation.requirer.vnf_profile_id
3426 else None
3427 )
3428 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3429 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3430 provider_relation_endpoint = RelationEndpoint(
3431 deployed_provider.ee_id,
3432 provider_vca_id,
3433 relation.provider.endpoint,
3434 )
3435 requirer_relation_endpoint = RelationEndpoint(
3436 deployed_requirer.ee_id,
3437 requirer_vca_id,
3438 relation.requirer.endpoint,
3439 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003440 try:
3441 await self.vca_map[vca_type].add_relation(
3442 provider=provider_relation_endpoint,
3443 requirer=requirer_relation_endpoint,
3444 )
3445 except N2VCException as exception:
3446 self.logger.error(exception)
3447 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003448 return True
3449 return False
3450
David Garciac1fe90a2021-03-31 19:12:02 +02003451 async def _add_vca_relations(
3452 self,
3453 logging_text,
3454 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003455 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003456 vca_index: int,
3457 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003458 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003459 # steps:
3460 # 1. find all relations for this VCA
3461 # 2. wait for other peers related
3462 # 3. add relations
3463
3464 try:
quilesj63f90042020-01-17 09:53:55 +00003465 # STEP 1: find all relations for this VCA
3466
3467 # read nsr record
3468 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003469 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003470
3471 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003472 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3473 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003474
David Garciab4ebcd02021-10-28 02:00:43 +02003475 cached_vnfds = {}
3476 cached_vnfrs = {}
3477 relations = []
3478 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3479 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003480
3481 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003482 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003483 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003484 return True
3485
David Garciab4ebcd02021-10-28 02:00:43 +02003486 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003487
3488 # add all relations
3489 start = time()
3490 while True:
3491 # check timeout
3492 now = time()
3493 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003494 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003495 return False
3496
David Garciab4ebcd02021-10-28 02:00:43 +02003497 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003498 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3499
David Garciab4ebcd02021-10-28 02:00:43 +02003500 # for each relation, find the VCA's related
3501 for relation in relations.copy():
3502 added = await self._add_relation(
3503 relation,
3504 vca_type,
3505 db_nsr,
3506 cached_vnfds,
3507 cached_vnfrs,
3508 )
3509 if added:
3510 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003511
David Garciab4ebcd02021-10-28 02:00:43 +02003512 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003513 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003514 break
David Garciab4ebcd02021-10-28 02:00:43 +02003515 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003516
3517 return True
3518
3519 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003520 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003521 return False
3522
garciadeblas5697b8b2021-03-24 09:17:02 +01003523 async def _install_kdu(
3524 self,
3525 nsr_id: str,
3526 nsr_db_path: str,
3527 vnfr_data: dict,
3528 kdu_index: int,
3529 kdud: dict,
3530 vnfd: dict,
3531 k8s_instance_info: dict,
3532 k8params: dict = None,
3533 timeout: int = 600,
3534 vca_id: str = None,
3535 ):
tiernob9018152020-04-16 14:18:24 +00003536 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003537 k8sclustertype = k8s_instance_info["k8scluster-type"]
3538 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003539 db_dict_install = {
3540 "collection": "nsrs",
3541 "filter": {"_id": nsr_id},
3542 "path": nsr_db_path,
3543 }
lloretgalleg7c121132020-07-08 07:53:22 +00003544
romeromonser4554a702021-05-28 12:00:08 +02003545 if k8s_instance_info.get("kdu-deployment-name"):
3546 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3547 else:
3548 kdu_instance = self.k8scluster_map[
3549 k8sclustertype
3550 ].generate_kdu_instance_name(
3551 db_dict=db_dict_install,
3552 kdu_model=k8s_instance_info["kdu-model"],
3553 kdu_name=k8s_instance_info["kdu-name"],
3554 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003555
3556 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003557 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003558 item="nsrs",
3559 _id=nsr_id,
3560 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003561 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003562
3563 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3564 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3565 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3566 # namespace, this first verification could be removed, and the next step would be done for any kind
3567 # of KNF.
3568 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3569 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3570 if k8sclustertype in ("juju", "juju-bundle"):
3571 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3572 # that the user passed a namespace which he wants its KDU to be deployed in)
3573 if (
3574 self.db.count(
3575 table="nsrs",
3576 q_filter={
3577 "_id": nsr_id,
3578 "_admin.projects_write": k8s_instance_info["namespace"],
3579 "_admin.projects_read": k8s_instance_info["namespace"],
3580 },
3581 )
3582 > 0
3583 ):
3584 self.logger.debug(
3585 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3586 )
3587 self.update_db_2(
3588 item="nsrs",
3589 _id=nsr_id,
3590 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3591 )
3592 k8s_instance_info["namespace"] = kdu_instance
3593
David Garciad64e2742021-02-25 20:19:18 +01003594 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003595 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3596 kdu_model=k8s_instance_info["kdu-model"],
3597 atomic=True,
3598 params=k8params,
3599 db_dict=db_dict_install,
3600 timeout=timeout,
3601 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003602 namespace=k8s_instance_info["namespace"],
3603 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003604 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003605 )
lloretgalleg7c121132020-07-08 07:53:22 +00003606
3607 # Obtain services to obtain management service ip
3608 services = await self.k8scluster_map[k8sclustertype].get_services(
3609 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3610 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003611 namespace=k8s_instance_info["namespace"],
3612 )
lloretgalleg7c121132020-07-08 07:53:22 +00003613
3614 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003615 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003616 kdu_config = get_configuration(vnfd, kdud["name"])
3617 if kdu_config:
3618 target_ee_list = kdu_config.get("execution-environment-list", [])
3619 else:
3620 target_ee_list = []
3621
lloretgalleg7c121132020-07-08 07:53:22 +00003622 if services:
tierno7ecbc342020-09-21 14:05:39 +00003623 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003624 mgmt_services = [
3625 service
3626 for service in kdud.get("service", [])
3627 if service.get("mgmt-service")
3628 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003629 for mgmt_service in mgmt_services:
3630 for service in services:
3631 if service["name"].startswith(mgmt_service["name"]):
3632 # Mgmt service found, Obtain service ip
3633 ip = service.get("external_ip", service.get("cluster_ip"))
3634 if isinstance(ip, list) and len(ip) == 1:
3635 ip = ip[0]
3636
garciadeblas5697b8b2021-03-24 09:17:02 +01003637 vnfr_update_dict[
3638 "kdur.{}.ip-address".format(kdu_index)
3639 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003640
3641 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003642 service_external_cp = mgmt_service.get(
3643 "external-connection-point-ref"
3644 )
lloretgalleg7c121132020-07-08 07:53:22 +00003645 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003646 if (
3647 deep_get(vnfd, ("mgmt-interface", "cp"))
3648 == service_external_cp
3649 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003650 vnfr_update_dict["ip-address"] = ip
3651
bravof6ec62b72021-02-25 17:20:35 -03003652 if find_in_list(
3653 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003654 lambda ee: ee.get(
3655 "external-connection-point-ref", ""
3656 )
3657 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003658 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003659 vnfr_update_dict[
3660 "kdur.{}.ip-address".format(kdu_index)
3661 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003662 break
3663 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003664 self.logger.warn(
3665 "Mgmt service name: {} not found".format(
3666 mgmt_service["name"]
3667 )
3668 )
lloretgalleg7c121132020-07-08 07:53:22 +00003669
tierno7ecbc342020-09-21 14:05:39 +00003670 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3671 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003672
bravof9a256db2021-02-22 18:02:07 -03003673 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003674 if (
3675 kdu_config
3676 and kdu_config.get("initial-config-primitive")
3677 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
jegan99448902024-12-06 07:19:34 +00003678 and get_helm_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
garciadeblas5697b8b2021-03-24 09:17:02 +01003679 ):
3680 initial_config_primitive_list = kdu_config.get(
3681 "initial-config-primitive"
3682 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003683 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3684
3685 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003686 primitive_params_ = self._map_primitive_params(
3687 initial_config_primitive, {}, {}
3688 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003689
3690 await asyncio.wait_for(
3691 self.k8scluster_map[k8sclustertype].exec_primitive(
3692 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3693 kdu_instance=kdu_instance,
3694 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003695 params=primitive_params_,
3696 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003697 vca_id=vca_id,
3698 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003699 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003700 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003701
tiernob9018152020-04-16 14:18:24 +00003702 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003703 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003704 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003705 self.update_db_2(
3706 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3707 )
3708 self.update_db_2(
3709 "vnfrs",
3710 vnfr_data.get("_id"),
3711 {"kdur.{}.status".format(kdu_index): "ERROR"},
3712 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003713 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003714 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003715 self.logger.warning(
3716 f"An exception occurred while updating DB: {str(error)}"
3717 )
lloretgalleg7c121132020-07-08 07:53:22 +00003718 # reraise original error
3719 raise
3720
3721 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003722
garciadeblas5697b8b2021-03-24 09:17:02 +01003723 async def deploy_kdus(
3724 self,
3725 logging_text,
3726 nsr_id,
3727 nslcmop_id,
3728 db_vnfrs,
3729 db_vnfds,
3730 task_instantiation_info,
3731 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003732 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003733
garciadeblas5697b8b2021-03-24 09:17:02 +01003734 k8scluster_id_2_uuic = {
3735 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003736 "juju-bundle": {},
3737 }
tierno626e0152019-11-29 14:16:16 +00003738
tierno16f4a4e2020-07-20 09:05:51 +00003739 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003740 nonlocal k8scluster_id_2_uuic
3741 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3742 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3743
tierno16f4a4e2020-07-20 09:05:51 +00003744 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003745 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3746 "k8scluster", cluster_id
3747 )
tierno16f4a4e2020-07-20 09:05:51 +00003748 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003749 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3750 task_name, cluster_id
3751 )
tierno16f4a4e2020-07-20 09:05:51 +00003752 self.logger.debug(logging_text + text)
3753 await asyncio.wait(task_dependency, timeout=3600)
3754
garciadeblas5697b8b2021-03-24 09:17:02 +01003755 db_k8scluster = self.db.get_one(
3756 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3757 )
tierno626e0152019-11-29 14:16:16 +00003758 if not db_k8scluster:
3759 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003760
tierno626e0152019-11-29 14:16:16 +00003761 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3762 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003763 if cluster_type == "helm-chart-v3":
3764 try:
3765 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003766 k8s_credentials = yaml.safe_dump(
3767 db_k8scluster.get("credentials")
3768 )
3769 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3770 k8s_credentials, reuse_cluster_uuid=cluster_id
3771 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003772 db_k8scluster_update = {}
3773 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3774 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003775 db_k8scluster_update[
3776 "_admin.helm-chart-v3.created"
3777 ] = uninstall_sw
3778 db_k8scluster_update[
3779 "_admin.helm-chart-v3.operationalState"
3780 ] = "ENABLED"
3781 self.update_db_2(
3782 "k8sclusters", cluster_id, db_k8scluster_update
3783 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003784 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003785 self.logger.error(
3786 logging_text
3787 + "error initializing helm-v3 cluster: {}".format(str(e))
3788 )
3789 raise LcmException(
3790 "K8s cluster '{}' has not been initialized for '{}'".format(
3791 cluster_id, cluster_type
3792 )
3793 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003794 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003795 raise LcmException(
3796 "K8s cluster '{}' has not been initialized for '{}'".format(
3797 cluster_id, cluster_type
3798 )
3799 )
tierno626e0152019-11-29 14:16:16 +00003800 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3801 return k8s_id
3802
3803 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003804 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003805 try:
tierno626e0152019-11-29 14:16:16 +00003806 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003807 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003808
tierno626e0152019-11-29 14:16:16 +00003809 index = 0
tiernoe876f672020-02-13 14:34:48 +00003810 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003811 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003812
tierno626e0152019-11-29 14:16:16 +00003813 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003814 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003815 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3816 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003817 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003818 vnfd_id = vnfr_data.get("vnfd-id")
3819 vnfd_with_id = find_in_list(
3820 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3821 )
3822 kdud = next(
3823 kdud
3824 for kdud in vnfd_with_id["kdu"]
3825 if kdud["name"] == kdur["kdu-name"]
3826 )
tiernode1584f2020-04-07 09:07:33 +00003827 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003828 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003829 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003830 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003831 # Default version: helm3, if helm-version is v2 assign v2
3832 k8sclustertype = "helm-chart-v3"
3833 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003834 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003835 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003836 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003837 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003838 raise LcmException(
3839 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3840 "juju-bundle. Maybe an old NBI version is running".format(
3841 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3842 )
3843 )
quilesjacde94f2020-01-23 10:07:08 +00003844 # check if kdumodel is a file and exists
3845 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003846 vnfd_with_id = find_in_list(
3847 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3848 )
3849 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003850 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003851 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003852 if storage["pkg-dir"]:
3853 filename = "{}/{}/{}s/{}".format(
3854 storage["folder"],
3855 storage["pkg-dir"],
3856 k8sclustertype,
3857 kdumodel,
3858 )
3859 else:
3860 filename = "{}/Scripts/{}s/{}".format(
3861 storage["folder"],
3862 k8sclustertype,
3863 kdumodel,
3864 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003865 if self.fs.file_exists(
3866 filename, mode="file"
3867 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003868 kdumodel = self.fs.path + filename
3869 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003870 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003871 except Exception as e: # it is not a file
3872 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003873
tiernoe876f672020-02-13 14:34:48 +00003874 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003875 step = "Synchronize repos for k8s cluster '{}'".format(
3876 k8s_cluster_id
3877 )
tierno16f4a4e2020-07-20 09:05:51 +00003878 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003879
lloretgalleg7c121132020-07-08 07:53:22 +00003880 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003881 if (
3882 k8sclustertype == "helm-chart"
3883 and cluster_uuid not in updated_cluster_list
3884 ) or (
3885 k8sclustertype == "helm-chart-v3"
3886 and cluster_uuid not in updated_v3_cluster_list
3887 ):
tiernoe876f672020-02-13 14:34:48 +00003888 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003889 self.k8scluster_map[k8sclustertype].synchronize_repos(
3890 cluster_uuid=cluster_uuid
3891 )
3892 )
tiernoe876f672020-02-13 14:34:48 +00003893 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003894 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003895 unset = {
3896 "_admin.helm_charts_added." + item: None
3897 for item in del_repo_list
3898 }
3899 updated = {
3900 "_admin.helm_charts_added." + item: name
3901 for item, name in added_repo_dict.items()
3902 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003903 updated_cluster_list.append(cluster_uuid)
3904 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003905 unset = {
3906 "_admin.helm_charts_v3_added." + item: None
3907 for item in del_repo_list
3908 }
3909 updated = {
3910 "_admin.helm_charts_v3_added." + item: name
3911 for item, name in added_repo_dict.items()
3912 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003913 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003914 self.logger.debug(
3915 logging_text + "repos synchronized on k8s cluster "
3916 "'{}' to_delete: {}, to_add: {}".format(
3917 k8s_cluster_id, del_repo_list, added_repo_dict
3918 )
3919 )
3920 self.db.set_one(
3921 "k8sclusters",
3922 {"_id": k8s_cluster_id},
3923 updated,
3924 unset=unset,
3925 )
lloretgallegedc5f332020-02-20 11:50:50 +01003926
lloretgalleg7c121132020-07-08 07:53:22 +00003927 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003928 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3929 vnfr_data["member-vnf-index-ref"],
3930 kdur["kdu-name"],
3931 k8s_cluster_id,
3932 )
3933 k8s_instance_info = {
3934 "kdu-instance": None,
3935 "k8scluster-uuid": cluster_uuid,
3936 "k8scluster-type": k8sclustertype,
3937 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3938 "kdu-name": kdur["kdu-name"],
3939 "kdu-model": kdumodel,
3940 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003941 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003942 }
tiernob9018152020-04-16 14:18:24 +00003943 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003944 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003945 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003946 vnfd_with_id = find_in_list(
3947 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3948 )
tiernoa2143262020-03-27 16:20:40 +00003949 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003950 self._install_kdu(
3951 nsr_id,
3952 db_path,
3953 vnfr_data,
3954 kdu_index,
3955 kdud,
3956 vnfd_with_id,
3957 k8s_instance_info,
3958 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003959 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003960 vca_id=vca_id,
3961 )
3962 )
3963 self.lcm_tasks.register(
3964 "ns",
3965 nsr_id,
3966 nslcmop_id,
3967 "instantiate_KDU-{}".format(index),
3968 task,
3969 )
3970 task_instantiation_info[task] = "Deploying KDU {}".format(
3971 kdur["kdu-name"]
3972 )
tiernoe876f672020-02-13 14:34:48 +00003973
tierno626e0152019-11-29 14:16:16 +00003974 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003975
tiernoe876f672020-02-13 14:34:48 +00003976 except (LcmException, asyncio.CancelledError):
3977 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003978 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003979 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3980 if isinstance(e, (N2VCException, DbException)):
3981 self.logger.error(logging_text + msg)
3982 else:
3983 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003984 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003985 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003986 if db_nsr_update:
3987 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003988
garciadeblas5697b8b2021-03-24 09:17:02 +01003989 def _deploy_n2vc(
3990 self,
3991 logging_text,
3992 db_nsr,
3993 db_vnfr,
3994 nslcmop_id,
3995 nsr_id,
3996 nsi_id,
3997 vnfd_id,
3998 vdu_id,
3999 kdu_name,
4000 member_vnf_index,
4001 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004002 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004003 vdu_name,
4004 deploy_params,
4005 descriptor_config,
4006 base_folder,
4007 task_instantiation_info,
4008 stage,
4009 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004010 # launch instantiate_N2VC in a asyncio task and register task object
4011 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4012 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004013 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004014
garciadeblas5697b8b2021-03-24 09:17:02 +01004015 self.logger.debug(
4016 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4017 )
aticig9bc63ac2022-07-27 09:32:06 +03004018
4019 charm_name = ""
4020 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004021 if "execution-environment-list" in descriptor_config:
4022 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004023 elif "juju" in descriptor_config:
4024 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004025 if "execution-environment-list" not in descriptor_config:
4026 # charm name is only required for ns charms
4027 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004028 else: # other types as script are not supported
4029 ee_list = []
4030
4031 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004032 self.logger.debug(
4033 logging_text
4034 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4035 ee_item.get("juju"), ee_item.get("helm-chart")
4036 )
4037 )
tiernoa278b842020-07-08 15:33:55 +00004038 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05004039 vca_name, charm_name, vca_type = self.get_vca_info(
4040 ee_item, db_nsr, get_charm_name
4041 )
4042 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004043 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004044 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004045 )
quilesj7e13aeb2019-10-08 13:34:55 +02004046 continue
quilesj3655ae02019-12-12 16:08:35 +00004047
tierno588547c2020-07-01 15:30:20 +00004048 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004049 for vca_index, vca_deployed in enumerate(
4050 db_nsr["_admin"]["deployed"]["VCA"]
4051 ):
tierno588547c2020-07-01 15:30:20 +00004052 if not vca_deployed:
4053 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004054 if (
4055 vca_deployed.get("member-vnf-index") == member_vnf_index
4056 and vca_deployed.get("vdu_id") == vdu_id
4057 and vca_deployed.get("kdu_name") == kdu_name
4058 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4059 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4060 ):
tierno588547c2020-07-01 15:30:20 +00004061 break
4062 else:
4063 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004064 target = (
4065 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4066 )
tiernoa278b842020-07-08 15:33:55 +00004067 if vdu_id:
4068 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4069 elif kdu_name:
4070 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004071 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004072 "target_element": target,
4073 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004074 "member-vnf-index": member_vnf_index,
4075 "vdu_id": vdu_id,
4076 "kdu_name": kdu_name,
4077 "vdu_count_index": vdu_index,
4078 "operational-status": "init", # TODO revise
4079 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004080 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004081 "vnfd_id": vnfd_id,
4082 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004083 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004084 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004085 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004086 }
4087 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004088
tierno588547c2020-07-01 15:30:20 +00004089 # create VCA and configurationStatus in db
4090 db_dict = {
4091 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004092 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004093 }
4094 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004095
tierno588547c2020-07-01 15:30:20 +00004096 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4097
bravof922c4172020-11-24 21:21:43 -03004098 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4099 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4100 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4101
tierno588547c2020-07-01 15:30:20 +00004102 # Launch task
4103 task_n2vc = asyncio.ensure_future(
4104 self.instantiate_N2VC(
4105 logging_text=logging_text,
4106 vca_index=vca_index,
4107 nsi_id=nsi_id,
4108 db_nsr=db_nsr,
4109 db_vnfr=db_vnfr,
4110 vdu_id=vdu_id,
4111 kdu_name=kdu_name,
4112 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004113 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004114 deploy_params=deploy_params,
4115 config_descriptor=descriptor_config,
4116 base_folder=base_folder,
4117 nslcmop_id=nslcmop_id,
4118 stage=stage,
4119 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004120 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004121 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004122 )
quilesj7e13aeb2019-10-08 13:34:55 +02004123 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004124 self.lcm_tasks.register(
4125 "ns",
4126 nsr_id,
4127 nslcmop_id,
4128 "instantiate_N2VC-{}".format(vca_index),
4129 task_n2vc,
4130 )
4131 task_instantiation_info[
4132 task_n2vc
4133 ] = self.task_name_deploy_vca + " {}.{}".format(
4134 member_vnf_index or "", vdu_id or ""
4135 )
tiernobaa51102018-12-14 13:16:18 +00004136
calvinosanch9f9c6f22019-11-04 13:37:39 +01004137 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004138 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004139 for key, value in params.items():
4140 if str(value).startswith("!!yaml "):
4141 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004142 return params
4143
kuuse8b998e42019-07-30 15:22:16 +02004144 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004145 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004146 primitive_params = {}
4147 params = {
4148 "member_vnf_index": vnf_index,
4149 "primitive": primitive,
4150 "primitive_params": primitive_params,
4151 }
4152 desc_params = {}
4153 return self._map_primitive_params(seq, params, desc_params)
4154
kuuseac3a8882019-10-03 10:48:06 +02004155 # sub-operations
4156
tierno51183952020-04-03 15:48:18 +00004157 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004158 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4159 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004160 # b. Skip sub-operation
4161 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4162 return self.SUBOPERATION_STATUS_SKIP
4163 else:
tierno7c4e24c2020-05-13 08:41:35 +00004164 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004165 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004166 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004167 operationState = "PROCESSING"
4168 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004169 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004170 db_nslcmop, op_index, operationState, detailed_status
4171 )
kuuseac3a8882019-10-03 10:48:06 +02004172 # Return the sub-operation index
4173 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4174 # with arguments extracted from the sub-operation
4175 return op_index
4176
4177 # Find a sub-operation where all keys in a matching dictionary must match
4178 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4179 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004180 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004181 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004182 for i, op in enumerate(op_list):
4183 if all(op.get(k) == match[k] for k in match):
4184 return i
4185 return self.SUBOPERATION_STATUS_NOT_FOUND
4186
4187 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004188 def _update_suboperation_status(
4189 self, db_nslcmop, op_index, operationState, detailed_status
4190 ):
kuuseac3a8882019-10-03 10:48:06 +02004191 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004192 q_filter = {"_id": db_nslcmop["_id"]}
4193 update_dict = {
4194 "_admin.operations.{}.operationState".format(op_index): operationState,
4195 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4196 }
4197 self.db.set_one(
4198 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4199 )
kuuseac3a8882019-10-03 10:48:06 +02004200
4201 # Add sub-operation, return the index of the added sub-operation
4202 # Optionally, set operationState, detailed-status, and operationType
4203 # Status and type are currently set for 'scale' sub-operations:
4204 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4205 # 'detailed-status' : status message
4206 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4207 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004208 def _add_suboperation(
4209 self,
4210 db_nslcmop,
4211 vnf_index,
4212 vdu_id,
4213 vdu_count_index,
4214 vdu_name,
4215 primitive,
4216 mapped_primitive_params,
4217 operationState=None,
4218 detailed_status=None,
4219 operationType=None,
4220 RO_nsr_id=None,
4221 RO_scaling_info=None,
4222 ):
tiernoe876f672020-02-13 14:34:48 +00004223 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004224 return self.SUBOPERATION_STATUS_NOT_FOUND
4225 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004226 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4227 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004228 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004229 new_op = {
4230 "member_vnf_index": vnf_index,
4231 "vdu_id": vdu_id,
4232 "vdu_count_index": vdu_count_index,
4233 "primitive": primitive,
4234 "primitive_params": mapped_primitive_params,
4235 }
kuuseac3a8882019-10-03 10:48:06 +02004236 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004237 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004238 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004239 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004240 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004241 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004242 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004243 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004244 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004245 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004246 if not op_list:
4247 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004248 db_nslcmop_admin.update({"operations": [new_op]})
4249 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004250 else:
4251 # Existing operations, append operation to list
4252 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004253
garciadeblas5697b8b2021-03-24 09:17:02 +01004254 db_nslcmop_update = {"_admin.operations": op_list}
4255 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004256 op_index = len(op_list) - 1
4257 return op_index
4258
4259 # Helper methods for scale() sub-operations
4260
4261 # pre-scale/post-scale:
4262 # Check for 3 different cases:
4263 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4264 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004265 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004266 def _check_or_add_scale_suboperation(
4267 self,
4268 db_nslcmop,
4269 vnf_index,
4270 vnf_config_primitive,
4271 primitive_params,
4272 operationType,
4273 RO_nsr_id=None,
4274 RO_scaling_info=None,
4275 ):
kuuseac3a8882019-10-03 10:48:06 +02004276 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004277 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004278 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004279 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004280 "member_vnf_index": vnf_index,
4281 "RO_nsr_id": RO_nsr_id,
4282 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004283 }
4284 else:
4285 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004286 "member_vnf_index": vnf_index,
4287 "primitive": vnf_config_primitive,
4288 "primitive_params": primitive_params,
4289 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004290 }
4291 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004292 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004293 # a. New sub-operation
4294 # The sub-operation does not exist, add it.
4295 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4296 # The following parameters are set to None for all kind of scaling:
4297 vdu_id = None
4298 vdu_count_index = None
4299 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004300 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004301 vnf_config_primitive = None
4302 primitive_params = None
4303 else:
4304 RO_nsr_id = None
4305 RO_scaling_info = None
4306 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004307 operationState = "PROCESSING"
4308 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004309 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004310 self._add_suboperation(
4311 db_nslcmop,
4312 vnf_index,
4313 vdu_id,
4314 vdu_count_index,
4315 vdu_name,
4316 vnf_config_primitive,
4317 primitive_params,
4318 operationState,
4319 detailed_status,
4320 operationType,
4321 RO_nsr_id,
4322 RO_scaling_info,
4323 )
kuuseac3a8882019-10-03 10:48:06 +02004324 return self.SUBOPERATION_STATUS_NEW
4325 else:
4326 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4327 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004328 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004329
preethika.pdf7d8e02019-12-10 13:10:48 +00004330 # Function to return execution_environment id
4331
David Garciac1fe90a2021-03-31 19:12:02 +02004332 async def destroy_N2VC(
4333 self,
4334 logging_text,
4335 db_nslcmop,
4336 vca_deployed,
4337 config_descriptor,
4338 vca_index,
4339 destroy_ee=True,
4340 exec_primitives=True,
4341 scaling_in=False,
4342 vca_id: str = None,
4343 ):
tiernoe876f672020-02-13 14:34:48 +00004344 """
4345 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4346 :param logging_text:
4347 :param db_nslcmop:
4348 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4349 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4350 :param vca_index: index in the database _admin.deployed.VCA
4351 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004352 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4353 not executed properly
aktas13251562021-02-12 22:19:10 +03004354 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004355 :return: None or exception
4356 """
tiernoe876f672020-02-13 14:34:48 +00004357
tierno588547c2020-07-01 15:30:20 +00004358 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004359 logging_text
4360 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004361 vca_index, vca_deployed, config_descriptor, destroy_ee
4362 )
4363 )
4364
4365 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4366
4367 # execute terminate_primitives
4368 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004369 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004370 config_descriptor.get("terminate-config-primitive"),
4371 vca_deployed.get("ee_descriptor_id"),
4372 )
tierno588547c2020-07-01 15:30:20 +00004373 vdu_id = vca_deployed.get("vdu_id")
4374 vdu_count_index = vca_deployed.get("vdu_count_index")
4375 vdu_name = vca_deployed.get("vdu_name")
4376 vnf_index = vca_deployed.get("member-vnf-index")
4377 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004378 for seq in terminate_primitives:
4379 # For each sequence in list, get primitive and call _ns_execute_primitive()
4380 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004381 vnf_index, seq.get("name")
4382 )
tierno588547c2020-07-01 15:30:20 +00004383 self.logger.debug(logging_text + step)
4384 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004385 primitive = seq.get("name")
4386 mapped_primitive_params = self._get_terminate_primitive_params(
4387 seq, vnf_index
4388 )
tierno588547c2020-07-01 15:30:20 +00004389
4390 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004391 self._add_suboperation(
4392 db_nslcmop,
4393 vnf_index,
4394 vdu_id,
4395 vdu_count_index,
4396 vdu_name,
4397 primitive,
4398 mapped_primitive_params,
4399 )
tierno588547c2020-07-01 15:30:20 +00004400 # Sub-operations: Call _ns_execute_primitive() instead of action()
4401 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004402 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004403 vca_deployed["ee_id"],
4404 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004405 mapped_primitive_params,
4406 vca_type=vca_type,
4407 vca_id=vca_id,
4408 )
tierno588547c2020-07-01 15:30:20 +00004409 except LcmException:
4410 # this happens when VCA is not deployed. In this case it is not needed to terminate
4411 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004412 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004413 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004414 raise LcmException(
4415 "terminate_primitive {} for vnf_member_index={} fails with "
4416 "error {}".format(seq.get("name"), vnf_index, result_detail)
4417 )
tierno588547c2020-07-01 15:30:20 +00004418 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004419 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4420 vca_index
4421 )
4422 self.update_db_2(
4423 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4424 )
tiernoe876f672020-02-13 14:34:48 +00004425
bravof73bac502021-05-11 07:38:47 -04004426 # Delete Prometheus Jobs if any
4427 # This uses NSR_ID, so it will destroy any jobs under this index
4428 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004429
tiernoe876f672020-02-13 14:34:48 +00004430 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004431 await self.vca_map[vca_type].delete_execution_environment(
4432 vca_deployed["ee_id"],
4433 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004434 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004435 vca_id=vca_id,
4436 )
kuuse0ca67472019-05-13 15:59:27 +02004437
David Garciac1fe90a2021-03-31 19:12:02 +02004438 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004439 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004440 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004441 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004442 await self.n2vc.delete_namespace(
4443 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004444 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004445 vca_id=vca_id,
4446 )
tiernof59ad6c2020-04-08 12:50:52 +00004447 except N2VCNotFound: # already deleted. Skip
4448 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004449 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004450
tiernoe876f672020-02-13 14:34:48 +00004451 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004452 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004453 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004454 if not task_is_locked_by_me:
4455 return
4456
tierno59d22d22018-09-25 18:10:19 +02004457 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4458 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004459 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004460 db_nsr = None
4461 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004462 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004463 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004464 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004465 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004466 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004467 tasks_dict_info = {}
4468 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004469 stage = [
4470 "Stage 1/3: Preparing task.",
4471 "Waiting for previous operations to terminate.",
4472 "",
4473 ]
tiernoe876f672020-02-13 14:34:48 +00004474 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004475 try:
kuused124bfe2019-06-18 12:09:24 +02004476 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004477 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004478
tiernoe876f672020-02-13 14:34:48 +00004479 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4480 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4481 operation_params = db_nslcmop.get("operationParams") or {}
4482 if operation_params.get("timeout_ns_terminate"):
4483 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4484 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4485 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4486
4487 db_nsr_update["operational-status"] = "terminating"
4488 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004489 self._write_ns_status(
4490 nsr_id=nsr_id,
4491 ns_state="TERMINATING",
4492 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004493 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004494 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004495 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004496 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004497 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004498 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4499 return
tierno59d22d22018-09-25 18:10:19 +02004500
tiernoe876f672020-02-13 14:34:48 +00004501 stage[1] = "Getting vnf descriptors from db."
4502 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004503 db_vnfrs_dict = {
4504 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4505 }
tiernoe876f672020-02-13 14:34:48 +00004506 db_vnfds_from_id = {}
4507 db_vnfds_from_member_index = {}
4508 # Loop over VNFRs
4509 for vnfr in db_vnfrs_list:
4510 vnfd_id = vnfr["vnfd-id"]
4511 if vnfd_id not in db_vnfds_from_id:
4512 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4513 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004514 db_vnfds_from_member_index[
4515 vnfr["member-vnf-index-ref"]
4516 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004517
tiernoe876f672020-02-13 14:34:48 +00004518 # Destroy individual execution environments when there are terminating primitives.
4519 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004520 # TODO - check before calling _destroy_N2VC
4521 # if not operation_params.get("skip_terminate_primitives"):#
4522 # or not vca.get("needed_terminate"):
4523 stage[0] = "Stage 2/3 execute terminating primitives."
4524 self.logger.debug(logging_text + stage[0])
4525 stage[1] = "Looking execution environment that needs terminate."
4526 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004527
tierno588547c2020-07-01 15:30:20 +00004528 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004529 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004530 vca_member_vnf_index = vca.get("member-vnf-index")
4531 vca_id = self.get_vca_id(
4532 db_vnfrs_dict.get(vca_member_vnf_index)
4533 if vca_member_vnf_index
4534 else None,
4535 db_nsr,
4536 )
tierno588547c2020-07-01 15:30:20 +00004537 if not vca or not vca.get("ee_id"):
4538 continue
4539 if not vca.get("member-vnf-index"):
4540 # ns
4541 config_descriptor = db_nsr.get("ns-configuration")
4542 elif vca.get("vdu_id"):
4543 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004544 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004545 elif vca.get("kdu_name"):
4546 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004547 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004548 else:
bravofe5a31bc2021-02-17 19:09:12 -03004549 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004550 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004551 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004552 exec_terminate_primitives = not operation_params.get(
4553 "skip_terminate_primitives"
4554 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004555 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4556 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004557 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004558 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4559 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004560 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004561 self.destroy_N2VC(
4562 logging_text,
4563 db_nslcmop,
4564 vca,
4565 config_descriptor,
4566 vca_index,
4567 destroy_ee,
4568 exec_terminate_primitives,
4569 vca_id=vca_id,
4570 )
4571 )
tierno588547c2020-07-01 15:30:20 +00004572 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004573
tierno588547c2020-07-01 15:30:20 +00004574 # wait for pending tasks of terminate primitives
4575 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004576 self.logger.debug(
4577 logging_text
4578 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4579 )
4580 error_list = await self._wait_for_tasks(
4581 logging_text,
4582 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004583 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004584 stage,
4585 nslcmop_id,
4586 )
tierno86e33612020-09-16 14:13:06 +00004587 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004588 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004589 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004590
tiernoe876f672020-02-13 14:34:48 +00004591 # remove All execution environments at once
4592 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004593
tierno49676be2020-04-07 16:34:35 +00004594 if nsr_deployed.get("VCA"):
4595 stage[1] = "Deleting all execution environments."
4596 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004597 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4598 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004599 # Delete Namespace and Certificates
4600 await self.vca_map["helm-v3"].delete_tls_certificate(
4601 namespace=db_nslcmop["nsInstanceId"],
4602 certificate_name=self.EE_TLS_NAME,
4603 )
4604 await self.vca_map["helm-v3"].delete_namespace(
4605 namespace=db_nslcmop["nsInstanceId"],
4606 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004607 else:
4608 vca_id = self.get_vca_id({}, db_nsr)
4609 task_delete_ee = asyncio.ensure_future(
4610 asyncio.wait_for(
4611 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4612 timeout=self.timeout.charm_delete,
4613 )
4614 )
4615 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004616
tiernoe876f672020-02-13 14:34:48 +00004617 # Delete from k8scluster
4618 stage[1] = "Deleting KDUs."
4619 self.logger.debug(logging_text + stage[1])
4620 # print(nsr_deployed)
4621 for kdu in get_iterable(nsr_deployed, "K8s"):
4622 if not kdu or not kdu.get("kdu-instance"):
4623 continue
4624 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004625 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004626 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4627 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004628 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004629 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4630 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004631 kdu_instance=kdu_instance,
4632 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004633 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004634 )
4635 )
tiernoe876f672020-02-13 14:34:48 +00004636 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004637 self.logger.error(
4638 logging_text
4639 + "Unknown k8s deployment type {}".format(
4640 kdu.get("k8scluster-type")
4641 )
4642 )
tiernoe876f672020-02-13 14:34:48 +00004643 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004644 tasks_dict_info[
4645 task_delete_kdu_instance
4646 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004647
4648 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004649 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004650 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004651 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004652 self._terminate_ng_ro(
4653 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4654 )
4655 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004656 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004657
tiernoe876f672020-02-13 14:34:48 +00004658 # rest of staff will be done at finally
4659
garciadeblas5697b8b2021-03-24 09:17:02 +01004660 except (
4661 ROclient.ROClientException,
4662 DbException,
4663 LcmException,
4664 N2VCException,
4665 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004666 self.logger.error(logging_text + "Exit Exception {}".format(e))
4667 exc = e
4668 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004669 self.logger.error(
4670 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4671 )
tiernoe876f672020-02-13 14:34:48 +00004672 exc = "Operation was cancelled"
4673 except Exception as e:
4674 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004675 self.logger.critical(
4676 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4677 exc_info=True,
4678 )
tiernoe876f672020-02-13 14:34:48 +00004679 finally:
4680 if exc:
4681 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004682 try:
tiernoe876f672020-02-13 14:34:48 +00004683 # wait for pending tasks
4684 if tasks_dict_info:
4685 stage[1] = "Waiting for terminate pending tasks."
4686 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004687 error_list += await self._wait_for_tasks(
4688 logging_text,
4689 tasks_dict_info,
4690 timeout_ns_terminate,
4691 stage,
4692 nslcmop_id,
4693 )
tiernoe876f672020-02-13 14:34:48 +00004694 stage[1] = stage[2] = ""
4695 except asyncio.CancelledError:
4696 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004697 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4698 await self._wait_for_tasks(
4699 logging_text,
4700 tasks_dict_info,
4701 timeout_ns_terminate,
4702 stage,
4703 nslcmop_id,
4704 )
tiernoe876f672020-02-13 14:34:48 +00004705 except Exception as exc:
4706 error_list.append(str(exc))
4707 # update status at database
4708 if error_list:
4709 error_detail = "; ".join(error_list)
4710 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004711 error_description_nslcmop = "{} Detail: {}".format(
4712 stage[0], error_detail
4713 )
4714 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4715 nslcmop_id, stage[0]
4716 )
tierno59d22d22018-09-25 18:10:19 +02004717
tierno59d22d22018-09-25 18:10:19 +02004718 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004719 db_nsr_update["detailed-status"] = (
4720 error_description_nsr + " Detail: " + error_detail
4721 )
tiernoe876f672020-02-13 14:34:48 +00004722 db_nslcmop_update["detailed-status"] = error_detail
4723 nslcmop_operation_state = "FAILED"
4724 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004725 else:
tiernoa2143262020-03-27 16:20:40 +00004726 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004727 error_description_nsr = error_description_nslcmop = None
4728 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004729 db_nsr_update["operational-status"] = "terminated"
4730 db_nsr_update["detailed-status"] = "Done"
4731 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4732 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004733 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004734
tiernoe876f672020-02-13 14:34:48 +00004735 if db_nsr:
4736 self._write_ns_status(
4737 nsr_id=nsr_id,
4738 ns_state=ns_state,
4739 current_operation="IDLE",
4740 current_operation_id=None,
4741 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004742 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004743 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004744 )
tiernoa17d4f42020-04-28 09:59:23 +00004745 self._write_op_status(
4746 op_id=nslcmop_id,
4747 stage="",
4748 error_message=error_description_nslcmop,
4749 operation_state=nslcmop_operation_state,
4750 other_update=db_nslcmop_update,
4751 )
Rahul Kumar54671c52024-05-09 15:34:01 +05304752 if nslcmop_operation_state == "COMPLETED":
4753 self.db.del_list("prometheus_jobs", {"nsr_id": nsr_id})
lloretgalleg6d488782020-07-22 10:13:46 +00004754 if ns_state == "NOT_INSTANTIATED":
4755 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004756 self.db.set_list(
4757 "vnfrs",
4758 {"nsr-id-ref": nsr_id},
4759 {"_admin.nsState": "NOT_INSTANTIATED"},
4760 )
lloretgalleg6d488782020-07-22 10:13:46 +00004761 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004762 self.logger.warn(
4763 logging_text
4764 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4765 nsr_id, e
4766 )
4767 )
tiernoa17d4f42020-04-28 09:59:23 +00004768 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004769 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004770 if nslcmop_operation_state:
4771 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004772 await self.msg.aiowrite(
4773 "ns",
4774 "terminated",
4775 {
4776 "nsr_id": nsr_id,
4777 "nslcmop_id": nslcmop_id,
4778 "operationState": nslcmop_operation_state,
4779 "autoremove": autoremove,
4780 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004781 )
tierno59d22d22018-09-25 18:10:19 +02004782 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004783 self.logger.error(
4784 logging_text + "kafka_write notification Exception {}".format(e)
4785 )
aguilard1ae3c562023-02-16 17:24:35 +00004786 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4787 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004788
tierno59d22d22018-09-25 18:10:19 +02004789 self.logger.debug(logging_text + "Exit")
4790 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4791
garciadeblas5697b8b2021-03-24 09:17:02 +01004792 async def _wait_for_tasks(
4793 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4794 ):
tiernoe876f672020-02-13 14:34:48 +00004795 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004796 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004797 error_list = []
4798 pending_tasks = list(created_tasks_info.keys())
4799 num_tasks = len(pending_tasks)
4800 num_done = 0
4801 stage[1] = "{}/{}.".format(num_done, num_tasks)
4802 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004803 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004804 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004805 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004806 done, pending_tasks = await asyncio.wait(
4807 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4808 )
tiernoe876f672020-02-13 14:34:48 +00004809 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004810 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004811 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004812 new_error = created_tasks_info[task] + ": Timeout"
4813 error_detail_list.append(new_error)
4814 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004815 break
4816 for task in done:
4817 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004818 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004819 else:
4820 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004821 if exc:
4822 if isinstance(exc, asyncio.TimeoutError):
4823 exc = "Timeout"
4824 new_error = created_tasks_info[task] + ": {}".format(exc)
4825 error_list.append(created_tasks_info[task])
4826 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004827 if isinstance(
4828 exc,
4829 (
4830 str,
4831 DbException,
4832 N2VCException,
4833 ROclient.ROClientException,
4834 LcmException,
4835 K8sException,
4836 NgRoException,
4837 ),
4838 ):
tierno067e04a2020-03-31 12:53:13 +00004839 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004840 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004841 exc_traceback = "".join(
4842 traceback.format_exception(None, exc, exc.__traceback__)
4843 )
4844 self.logger.error(
4845 logging_text
4846 + created_tasks_info[task]
4847 + " "
4848 + exc_traceback
4849 )
tierno067e04a2020-03-31 12:53:13 +00004850 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004851 self.logger.debug(
4852 logging_text + created_tasks_info[task] + ": Done"
4853 )
tiernoe876f672020-02-13 14:34:48 +00004854 stage[1] = "{}/{}.".format(num_done, num_tasks)
4855 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004856 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004857 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004858 self.update_db_2(
4859 "nsrs",
4860 nsr_id,
4861 {
4862 "errorDescription": "Error at: " + ", ".join(error_list),
4863 "errorDetail": ". ".join(error_detail_list),
4864 },
4865 )
tiernoe876f672020-02-13 14:34:48 +00004866 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004867 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004868
Gabriel Cubab6049d32023-10-30 13:44:49 -05004869 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4870 for task, name in created_tasks_info.items():
4871 self.logger.debug(logging_text + "Cancelling task: " + name)
4872 task.cancel()
4873
tiernoda1ff8c2020-10-22 14:12:46 +00004874 @staticmethod
4875 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004876 """
4877 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4878 The default-value is used. If it is between < > it look for a value at instantiation_params
4879 :param primitive_desc: portion of VNFD/NSD that describes primitive
4880 :param params: Params provided by user
4881 :param instantiation_params: Instantiation params provided by user
4882 :return: a dictionary with the calculated params
4883 """
4884 calculated_params = {}
4885 for parameter in primitive_desc.get("parameter", ()):
4886 param_name = parameter["name"]
4887 if param_name in params:
4888 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004889 elif "default-value" in parameter or "value" in parameter:
4890 if "value" in parameter:
4891 calculated_params[param_name] = parameter["value"]
4892 else:
4893 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004894 if (
4895 isinstance(calculated_params[param_name], str)
4896 and calculated_params[param_name].startswith("<")
4897 and calculated_params[param_name].endswith(">")
4898 ):
tierno98ad6ea2019-05-30 17:16:28 +00004899 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004900 calculated_params[param_name] = instantiation_params[
4901 calculated_params[param_name][1:-1]
4902 ]
tiernoda964822019-01-14 15:53:47 +00004903 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004904 raise LcmException(
4905 "Parameter {} needed to execute primitive {} not provided".format(
4906 calculated_params[param_name], primitive_desc["name"]
4907 )
4908 )
tiernoda964822019-01-14 15:53:47 +00004909 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004910 raise LcmException(
4911 "Parameter {} needed to execute primitive {} not provided".format(
4912 param_name, primitive_desc["name"]
4913 )
4914 )
tierno59d22d22018-09-25 18:10:19 +02004915
tiernoda964822019-01-14 15:53:47 +00004916 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004917 calculated_params[param_name] = yaml.safe_dump(
4918 calculated_params[param_name], default_flow_style=True, width=256
4919 )
4920 elif isinstance(calculated_params[param_name], str) and calculated_params[
4921 param_name
4922 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004923 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004924 if parameter.get("data-type") == "INTEGER":
4925 try:
4926 calculated_params[param_name] = int(calculated_params[param_name])
4927 except ValueError: # error converting string to int
4928 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004929 "Parameter {} of primitive {} must be integer".format(
4930 param_name, primitive_desc["name"]
4931 )
4932 )
tiernofa40e692020-10-14 14:59:36 +00004933 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004934 calculated_params[param_name] = not (
4935 (str(calculated_params[param_name])).lower() == "false"
4936 )
tiernoc3f2a822019-11-05 13:45:04 +00004937
4938 # add always ns_config_info if primitive name is config
4939 if primitive_desc["name"] == "config":
4940 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004941 calculated_params["ns_config_info"] = instantiation_params[
4942 "ns_config_info"
4943 ]
tiernoda964822019-01-14 15:53:47 +00004944 return calculated_params
4945
garciadeblas5697b8b2021-03-24 09:17:02 +01004946 def _look_for_deployed_vca(
4947 self,
4948 deployed_vca,
4949 member_vnf_index,
4950 vdu_id,
4951 vdu_count_index,
4952 kdu_name=None,
4953 ee_descriptor_id=None,
4954 ):
tiernoe876f672020-02-13 14:34:48 +00004955 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4956 for vca in deployed_vca:
4957 if not vca:
4958 continue
4959 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4960 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004961 if (
4962 vdu_count_index is not None
4963 and vdu_count_index != vca["vdu_count_index"]
4964 ):
tiernoe876f672020-02-13 14:34:48 +00004965 continue
4966 if kdu_name and kdu_name != vca["kdu_name"]:
4967 continue
tiernoa278b842020-07-08 15:33:55 +00004968 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4969 continue
tiernoe876f672020-02-13 14:34:48 +00004970 break
4971 else:
4972 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004973 raise LcmException(
4974 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4975 " is not deployed".format(
4976 member_vnf_index,
4977 vdu_id,
4978 vdu_count_index,
4979 kdu_name,
4980 ee_descriptor_id,
4981 )
4982 )
tiernoe876f672020-02-13 14:34:48 +00004983 # get ee_id
4984 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004985 vca_type = vca.get(
4986 "type", "lxc_proxy_charm"
4987 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004988 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004989 raise LcmException(
4990 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4991 "execution environment".format(
4992 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4993 )
4994 )
tierno588547c2020-07-01 15:30:20 +00004995 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004996
David Garciac1fe90a2021-03-31 19:12:02 +02004997 async def _ns_execute_primitive(
4998 self,
4999 ee_id,
5000 primitive,
5001 primitive_params,
5002 retries=0,
5003 retries_interval=30,
5004 timeout=None,
5005 vca_type=None,
5006 db_dict=None,
5007 vca_id: str = None,
5008 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005009 try:
tierno98ad6ea2019-05-30 17:16:28 +00005010 if primitive == "config":
5011 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005012
tierno588547c2020-07-01 15:30:20 +00005013 vca_type = vca_type or "lxc_proxy_charm"
5014
quilesj7e13aeb2019-10-08 13:34:55 +02005015 while retries >= 0:
5016 try:
tierno067e04a2020-03-31 12:53:13 +00005017 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005018 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005019 ee_id=ee_id,
5020 primitive_name=primitive,
5021 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005022 progress_timeout=self.timeout.progress_primitive,
5023 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005024 db_dict=db_dict,
5025 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005026 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005027 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005028 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005029 )
quilesj7e13aeb2019-10-08 13:34:55 +02005030 # execution was OK
5031 break
tierno067e04a2020-03-31 12:53:13 +00005032 except asyncio.CancelledError:
5033 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005034 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005035 retries -= 1
5036 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005037 self.logger.debug(
5038 "Error executing action {} on {} -> {}".format(
5039 primitive, ee_id, e
5040 )
5041 )
quilesj7e13aeb2019-10-08 13:34:55 +02005042 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005043 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005044 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005045 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005046 e = N2VCException(
5047 message="Timed out waiting for action to complete"
5048 )
5049 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005050
garciadeblas5697b8b2021-03-24 09:17:02 +01005051 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005052
tierno067e04a2020-03-31 12:53:13 +00005053 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005054 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005055 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005056 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005057
ksaikiranr3fde2c72021-03-15 10:39:06 +05305058 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5059 """
5060 Updating the vca_status with latest juju information in nsrs record
5061 :param: nsr_id: Id of the nsr
5062 :param: nslcmop_id: Id of the nslcmop
5063 :return: None
5064 """
5065
5066 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5067 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005068 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005069 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005070 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5071 cluster_uuid, kdu_instance, cluster_type = (
5072 k8s["k8scluster-uuid"],
5073 k8s["kdu-instance"],
5074 k8s["k8scluster-type"],
5075 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005076 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005077 cluster_uuid=cluster_uuid,
5078 kdu_instance=kdu_instance,
5079 filter={"_id": nsr_id},
5080 vca_id=vca_id,
5081 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005082 )
3697083243632024-06-07 05:44:08 +00005083 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005084 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305085 table, filter = "nsrs", {"_id": nsr_id}
5086 path = "_admin.deployed.VCA.{}.".format(vca_index)
5087 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305088
5089 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5090 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5091
tierno59d22d22018-09-25 18:10:19 +02005092 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005093 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005094 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005095 if not task_is_locked_by_me:
5096 return
5097
tierno59d22d22018-09-25 18:10:19 +02005098 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5099 self.logger.debug(logging_text + "Enter")
5100 # get all needed from database
5101 db_nsr = None
5102 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005103 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005104 db_nslcmop_update = {}
5105 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005106 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005107 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005108 step = ""
tierno59d22d22018-09-25 18:10:19 +02005109 try:
kuused124bfe2019-06-18 12:09:24 +02005110 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005111 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005112 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005113
quilesj4cda56b2019-12-05 10:02:20 +00005114 self._write_ns_status(
5115 nsr_id=nsr_id,
5116 ns_state=None,
5117 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005118 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005119 )
5120
tierno59d22d22018-09-25 18:10:19 +02005121 step = "Getting information from database"
5122 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5123 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005124 if db_nslcmop["operationParams"].get("primitive_params"):
5125 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5126 db_nslcmop["operationParams"]["primitive_params"]
5127 )
tiernoda964822019-01-14 15:53:47 +00005128
tiernoe4f7e6c2018-11-27 14:55:30 +00005129 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005130 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005131 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005132 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005133 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005134 primitive = db_nslcmop["operationParams"]["primitive"]
5135 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005136 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005137 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005138 )
tierno59d22d22018-09-25 18:10:19 +02005139
tierno1b633412019-02-25 16:48:23 +00005140 if vnf_index:
5141 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005142 db_vnfr = self.db.get_one(
5143 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5144 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005145 if db_vnfr.get("kdur"):
5146 kdur_list = []
5147 for kdur in db_vnfr["kdur"]:
5148 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005149 kdur["additionalParams"] = json.loads(
5150 kdur["additionalParams"]
5151 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005152 kdur_list.append(kdur)
5153 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005154 step = "Getting vnfd from database"
5155 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005156
5157 # Sync filesystem before running a primitive
5158 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005159 else:
tierno067e04a2020-03-31 12:53:13 +00005160 step = "Getting nsd from database"
5161 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005162
David Garciac1fe90a2021-03-31 19:12:02 +02005163 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005164 # for backward compatibility
5165 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5166 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5167 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5168 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5169
tiernoda964822019-01-14 15:53:47 +00005170 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005171 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005172 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005173 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005174 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005175 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005176 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005177 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005178 else:
tiernoa278b842020-07-08 15:33:55 +00005179 descriptor_configuration = db_nsd.get("ns-configuration")
5180
garciadeblas5697b8b2021-03-24 09:17:02 +01005181 if descriptor_configuration and descriptor_configuration.get(
5182 "config-primitive"
5183 ):
tiernoa278b842020-07-08 15:33:55 +00005184 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005185 if config_primitive["name"] == primitive:
5186 config_primitive_desc = config_primitive
5187 break
tiernoda964822019-01-14 15:53:47 +00005188
garciadeblas6bed6b32020-07-20 11:05:42 +00005189 if not config_primitive_desc:
5190 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005191 raise LcmException(
5192 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5193 primitive
5194 )
5195 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005196 primitive_name = primitive
5197 ee_descriptor_id = None
5198 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005199 primitive_name = config_primitive_desc.get(
5200 "execution-environment-primitive", primitive
5201 )
5202 ee_descriptor_id = config_primitive_desc.get(
5203 "execution-environment-ref"
5204 )
tierno1b633412019-02-25 16:48:23 +00005205
tierno1b633412019-02-25 16:48:23 +00005206 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005207 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005208 vdur = next(
5209 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5210 )
bravof922c4172020-11-24 21:21:43 -03005211 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005212 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005213 kdur = next(
5214 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5215 )
bravof922c4172020-11-24 21:21:43 -03005216 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005217 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005218 desc_params = parse_yaml_strings(
5219 db_vnfr.get("additionalParamsForVnf")
5220 )
tierno1b633412019-02-25 16:48:23 +00005221 else:
bravof922c4172020-11-24 21:21:43 -03005222 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005223 if kdu_name and get_configuration(db_vnfd, kdu_name):
5224 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005225 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005226 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005227 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005228 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005229 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005230 kdu = find_in_list(
5231 nsr_deployed["K8s"],
5232 lambda kdu: kdu_name == kdu["kdu-name"]
5233 and kdu["member-vnf-index"] == vnf_index,
5234 )
5235 kdu_action = (
5236 True
5237 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005238 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005239 else False
5240 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005241
tiernoda964822019-01-14 15:53:47 +00005242 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005243 if kdu_name and (
5244 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5245 ):
tierno067e04a2020-03-31 12:53:13 +00005246 # TODO Check if we will need something at vnf level
5247 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005248 if (
5249 kdu_name == kdu["kdu-name"]
5250 and kdu["member-vnf-index"] == vnf_index
5251 ):
tierno067e04a2020-03-31 12:53:13 +00005252 break
5253 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005254 raise LcmException(
5255 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5256 )
quilesj7e13aeb2019-10-08 13:34:55 +02005257
tierno067e04a2020-03-31 12:53:13 +00005258 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005259 msg = "unknown k8scluster-type '{}'".format(
5260 kdu.get("k8scluster-type")
5261 )
tierno067e04a2020-03-31 12:53:13 +00005262 raise LcmException(msg)
5263
garciadeblas5697b8b2021-03-24 09:17:02 +01005264 db_dict = {
5265 "collection": "nsrs",
5266 "filter": {"_id": nsr_id},
5267 "path": "_admin.deployed.K8s.{}".format(index),
5268 }
5269 self.logger.debug(
5270 logging_text
5271 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5272 )
tiernoa278b842020-07-08 15:33:55 +00005273 step = "Executing kdu {}".format(primitive_name)
garciadeblas8eb84d52024-07-19 12:08:07 +02005274 if primitive_name == "upgrade" and primitive_params:
5275 if primitive_params.get("kdu_model"):
5276 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005277 else:
5278 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005279 if kdu_model.count("/") < 2: # helm chart is not embedded
5280 parts = kdu_model.split(sep=":")
5281 if len(parts) == 2:
5282 kdu_model = parts[0]
garciadeblas8eb84d52024-07-19 12:08:07 +02005283 if primitive_params.get("kdu_atomic_upgrade"):
5284 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005285 "kdu_atomic_upgrade"
5286 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005287 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005288 else:
5289 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005290 # Type of upgrade: reset, reuse, reset_then_reuse
5291 reset_values = False
5292 reuse_values = False
5293 reset_then_reuse_values = False
5294 # If no option is specified, default behaviour is reuse_values
5295 # Otherwise, options will be parsed and used
5296 if (
garciadeblas8eb84d52024-07-19 12:08:07 +02005297 ("kdu_reset_values" not in primitive_params)
5298 and ("kdu_reuse_values" not in primitive_params)
5299 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasb891d382024-02-08 14:11:51 +01005300 ):
5301 reuse_values = True
5302 else:
garciadeblas8eb84d52024-07-19 12:08:07 +02005303 if primitive_params.get("kdu_reset_values"):
5304 reset_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005305 "kdu_reset_values"
5306 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005307 if primitive_params.get("kdu_reuse_values"):
5308 reuse_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005309 "kdu_reuse_values"
5310 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005311 if primitive_params.get("kdu_reset_then_reuse_values"):
5312 reset_then_reuse_values = primitive_params.get(
garciadeblasb891d382024-02-08 14:11:51 +01005313 "kdu_reset_then_reuse_values"
5314 ).lower() in ("yes", "true", "1")
5315 # Two true options are not possible
5316 if (
5317 sum([reset_values, reuse_values, reset_then_reuse_values])
5318 >= 2
5319 ):
5320 raise LcmException(
5321 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5322 )
garciadeblas8eb84d52024-07-19 12:08:07 +02005323 # kdur and desc_params already set from before
5324 if reset_values:
5325 desc_params = primitive_params
5326 else:
5327 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005328 detailed_status = await asyncio.wait_for(
5329 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5330 cluster_uuid=kdu.get("k8scluster-uuid"),
5331 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005332 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005333 reset_values=reset_values,
5334 reuse_values=reuse_values,
5335 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005336 kdu_model=kdu_model,
5337 params=desc_params,
5338 db_dict=db_dict,
5339 timeout=timeout_ns_action,
5340 ),
5341 timeout=timeout_ns_action + 10,
5342 )
5343 self.logger.debug(
5344 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5345 )
tiernoa278b842020-07-08 15:33:55 +00005346 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005347 detailed_status = await asyncio.wait_for(
5348 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5349 cluster_uuid=kdu.get("k8scluster-uuid"),
5350 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005351 db_dict=db_dict,
5352 ),
5353 timeout=timeout_ns_action,
5354 )
tiernoa278b842020-07-08 15:33:55 +00005355 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005356 detailed_status = await asyncio.wait_for(
5357 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5358 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005359 kdu_instance=kdu.get("kdu-instance"),
5360 vca_id=vca_id,
5361 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005362 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005363 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005364 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005365 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5366 kdu["kdu-name"], nsr_id
5367 )
5368 params = self._map_primitive_params(
5369 config_primitive_desc, primitive_params, desc_params
5370 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005371
5372 detailed_status = await asyncio.wait_for(
5373 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5374 cluster_uuid=kdu.get("k8scluster-uuid"),
5375 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005376 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005377 params=params,
5378 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005379 timeout=timeout_ns_action,
5380 vca_id=vca_id,
5381 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005382 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005383 )
tierno067e04a2020-03-31 12:53:13 +00005384
5385 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005386 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005387 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005388 detailed_status = ""
5389 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005390 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005391 ee_id, vca_type = self._look_for_deployed_vca(
5392 nsr_deployed["VCA"],
5393 member_vnf_index=vnf_index,
5394 vdu_id=vdu_id,
5395 vdu_count_index=vdu_count_index,
5396 ee_descriptor_id=ee_descriptor_id,
5397 )
5398 for vca_index, vca_deployed in enumerate(
5399 db_nsr["_admin"]["deployed"]["VCA"]
5400 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305401 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005402 db_dict = {
5403 "collection": "nsrs",
5404 "filter": {"_id": nsr_id},
5405 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5406 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305407 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005408 (
5409 nslcmop_operation_state,
5410 detailed_status,
5411 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005412 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005413 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005414 primitive_params=self._map_primitive_params(
5415 config_primitive_desc, primitive_params, desc_params
5416 ),
tierno588547c2020-07-01 15:30:20 +00005417 timeout=timeout_ns_action,
5418 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005419 db_dict=db_dict,
5420 vca_id=vca_id,
5421 )
tierno067e04a2020-03-31 12:53:13 +00005422
5423 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005424 error_description_nslcmop = (
5425 detailed_status if nslcmop_operation_state == "FAILED" else ""
5426 )
5427 self.logger.debug(
5428 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005429 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005430 nslcmop_operation_state, detailed_status
5431 )
5432 )
tierno59d22d22018-09-25 18:10:19 +02005433 return # database update is called inside finally
5434
tiernof59ad6c2020-04-08 12:50:52 +00005435 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005436 self.logger.error(logging_text + "Exit Exception {}".format(e))
5437 exc = e
5438 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005439 self.logger.error(
5440 logging_text + "Cancelled Exception while '{}'".format(step)
5441 )
tierno59d22d22018-09-25 18:10:19 +02005442 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005443 except asyncio.TimeoutError:
5444 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5445 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005446 except Exception as e:
5447 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005448 self.logger.critical(
5449 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5450 exc_info=True,
5451 )
tierno59d22d22018-09-25 18:10:19 +02005452 finally:
tierno067e04a2020-03-31 12:53:13 +00005453 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005454 db_nslcmop_update[
5455 "detailed-status"
5456 ] = (
5457 detailed_status
5458 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005459 nslcmop_operation_state = "FAILED"
5460 if db_nsr:
5461 self._write_ns_status(
5462 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005463 ns_state=db_nsr[
5464 "nsState"
5465 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005466 current_operation="IDLE",
5467 current_operation_id=None,
5468 # error_description=error_description_nsr,
5469 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005470 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005471 )
5472
garciadeblas5697b8b2021-03-24 09:17:02 +01005473 self._write_op_status(
5474 op_id=nslcmop_id,
5475 stage="",
5476 error_message=error_description_nslcmop,
5477 operation_state=nslcmop_operation_state,
5478 other_update=db_nslcmop_update,
5479 )
tierno067e04a2020-03-31 12:53:13 +00005480
tierno59d22d22018-09-25 18:10:19 +02005481 if nslcmop_operation_state:
5482 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005483 await self.msg.aiowrite(
5484 "ns",
5485 "actioned",
5486 {
5487 "nsr_id": nsr_id,
5488 "nslcmop_id": nslcmop_id,
5489 "operationState": nslcmop_operation_state,
5490 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005491 )
tierno59d22d22018-09-25 18:10:19 +02005492 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005493 self.logger.error(
5494 logging_text + "kafka_write notification Exception {}".format(e)
5495 )
tierno59d22d22018-09-25 18:10:19 +02005496 self.logger.debug(logging_text + "Exit")
5497 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005498 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005499
elumalaica7ece02022-04-12 12:47:32 +05305500 async def terminate_vdus(
5501 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5502 ):
5503 """This method terminates VDUs
5504
5505 Args:
5506 db_vnfr: VNF instance record
5507 member_vnf_index: VNF index to identify the VDUs to be removed
5508 db_nsr: NS instance record
5509 update_db_nslcmops: Nslcmop update record
5510 """
5511 vca_scaling_info = []
5512 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5513 scaling_info["scaling_direction"] = "IN"
5514 scaling_info["vdu-delete"] = {}
5515 scaling_info["kdu-delete"] = {}
5516 db_vdur = db_vnfr.get("vdur")
5517 vdur_list = copy(db_vdur)
5518 count_index = 0
5519 for index, vdu in enumerate(vdur_list):
5520 vca_scaling_info.append(
5521 {
5522 "osm_vdu_id": vdu["vdu-id-ref"],
5523 "member-vnf-index": member_vnf_index,
5524 "type": "delete",
5525 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005526 }
5527 )
elumalaica7ece02022-04-12 12:47:32 +05305528 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5529 scaling_info["vdu"].append(
5530 {
5531 "name": vdu.get("name") or vdu.get("vdu-name"),
5532 "vdu_id": vdu["vdu-id-ref"],
5533 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005534 }
5535 )
elumalaica7ece02022-04-12 12:47:32 +05305536 for interface in vdu["interfaces"]:
5537 scaling_info["vdu"][index]["interface"].append(
5538 {
5539 "name": interface["name"],
5540 "ip_address": interface["ip-address"],
5541 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005542 }
5543 )
elumalaica7ece02022-04-12 12:47:32 +05305544 self.logger.info("NS update scaling info{}".format(scaling_info))
5545 stage[2] = "Terminating VDUs"
5546 if scaling_info.get("vdu-delete"):
5547 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005548 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305549 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005550 logging_text,
5551 db_nsr,
5552 update_db_nslcmops,
5553 db_vnfr,
5554 scaling_info,
5555 stage,
elumalaica7ece02022-04-12 12:47:32 +05305556 )
5557
preethika.p28b0bf82022-09-23 07:36:28 +00005558 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305559 """This method is to Remove VNF instances from NS.
5560
5561 Args:
5562 nsr_id: NS instance id
5563 nslcmop_id: nslcmop id of update
5564 vnf_instance_id: id of the VNF instance to be removed
5565
5566 Returns:
5567 result: (str, str) COMPLETED/FAILED, details
5568 """
5569 try:
5570 db_nsr_update = {}
5571 logging_text = "Task ns={} update ".format(nsr_id)
5572 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5573 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5574 if check_vnfr_count > 1:
5575 stage = ["", "", ""]
5576 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005577 self.logger.debug(
5578 step + " after having waited for previous tasks to be completed"
5579 )
elumalaica7ece02022-04-12 12:47:32 +05305580 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5581 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5582 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5583 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5584 """ db_vnfr = self.db.get_one(
5585 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5586
5587 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005588 await self.terminate_vdus(
5589 db_vnfr,
5590 member_vnf_index,
5591 db_nsr,
5592 update_db_nslcmops,
5593 stage,
5594 logging_text,
5595 )
elumalaica7ece02022-04-12 12:47:32 +05305596
5597 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5598 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005599 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5600 "constituent-vnfr-ref"
5601 )
elumalaica7ece02022-04-12 12:47:32 +05305602 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5603 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5604 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5605 return "COMPLETED", "Done"
5606 else:
5607 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005608 raise LcmException(
5609 "{} Cannot terminate the last VNF in this NS.".format(
5610 vnf_instance_id
5611 )
5612 )
elumalaica7ece02022-04-12 12:47:32 +05305613 except (LcmException, asyncio.CancelledError):
5614 raise
5615 except Exception as e:
5616 self.logger.debug("Error removing VNF {}".format(e))
5617 return "FAILED", "Error removing VNF {}".format(e)
5618
elumalaib9e357c2022-04-27 09:58:38 +05305619 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005620 self,
5621 nsr_id,
5622 nslcmop_id,
5623 db_vnfd,
5624 db_vnfr,
5625 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305626 ):
5627 """This method updates and redeploys VNF instances
5628
5629 Args:
5630 nsr_id: NS instance id
5631 nslcmop_id: nslcmop id
5632 db_vnfd: VNF descriptor
5633 db_vnfr: VNF instance record
5634 db_nsr: NS instance record
5635
5636 Returns:
5637 result: (str, str) COMPLETED/FAILED, details
5638 """
5639 try:
5640 count_index = 0
5641 stage = ["", "", ""]
5642 logging_text = "Task ns={} update ".format(nsr_id)
5643 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5644 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5645
5646 # Terminate old VNF resources
5647 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005648 await self.terminate_vdus(
5649 db_vnfr,
5650 member_vnf_index,
5651 db_nsr,
5652 update_db_nslcmops,
5653 stage,
5654 logging_text,
5655 )
elumalaib9e357c2022-04-27 09:58:38 +05305656
5657 # old_vnfd_id = db_vnfr["vnfd-id"]
5658 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5659 new_db_vnfd = db_vnfd
5660 # new_vnfd_ref = new_db_vnfd["id"]
5661 # new_vnfd_id = vnfd_id
5662
5663 # Create VDUR
5664 new_vnfr_cp = []
5665 for cp in new_db_vnfd.get("ext-cpd", ()):
5666 vnf_cp = {
5667 "name": cp.get("id"),
5668 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5669 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5670 "id": cp.get("id"),
5671 }
5672 new_vnfr_cp.append(vnf_cp)
5673 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5674 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5675 # 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 +00005676 new_vnfr_update = {
5677 "revision": latest_vnfd_revision,
5678 "connection-point": new_vnfr_cp,
5679 "vdur": new_vdur,
5680 "ip-address": "",
5681 }
elumalaib9e357c2022-04-27 09:58:38 +05305682 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5683 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005684 "vnfrs",
5685 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305686 )
5687
5688 # Instantiate new VNF resources
5689 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5690 vca_scaling_info = []
5691 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5692 scaling_info["scaling_direction"] = "OUT"
5693 scaling_info["vdu-create"] = {}
5694 scaling_info["kdu-create"] = {}
5695 vdud_instantiate_list = db_vnfd["vdu"]
5696 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005697 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305698 if cloud_init_text:
5699 additional_params = (
5700 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5701 or {}
5702 )
5703 cloud_init_list = []
5704 if cloud_init_text:
5705 # TODO Information of its own ip is not available because db_vnfr is not updated.
5706 additional_params["OSM"] = get_osm_params(
5707 updated_db_vnfr, vdud["id"], 1
5708 )
5709 cloud_init_list.append(
5710 self._parse_cloud_init(
5711 cloud_init_text,
5712 additional_params,
5713 db_vnfd["id"],
5714 vdud["id"],
5715 )
5716 )
5717 vca_scaling_info.append(
5718 {
5719 "osm_vdu_id": vdud["id"],
5720 "member-vnf-index": member_vnf_index,
5721 "type": "create",
5722 "vdu_index": count_index,
5723 }
5724 )
5725 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005726 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305727 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005728 "New Resources to be deployed: {}".format(scaling_info)
5729 )
elumalaib9e357c2022-04-27 09:58:38 +05305730 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005731 logging_text,
5732 db_nsr,
5733 update_db_nslcmops,
5734 updated_db_vnfr,
5735 scaling_info,
5736 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305737 )
5738 return "COMPLETED", "Done"
5739 except (LcmException, asyncio.CancelledError):
5740 raise
5741 except Exception as e:
5742 self.logger.debug("Error updating VNF {}".format(e))
5743 return "FAILED", "Error updating VNF {}".format(e)
5744
aticigdffa6212022-04-12 15:27:53 +03005745 async def _ns_charm_upgrade(
5746 self,
5747 ee_id,
5748 charm_id,
5749 charm_type,
5750 path,
5751 timeout: float = None,
5752 ) -> (str, str):
5753 """This method upgrade charms in VNF instances
5754
5755 Args:
5756 ee_id: Execution environment id
5757 path: Local path to the charm
5758 charm_id: charm-id
5759 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5760 timeout: (Float) Timeout for the ns update operation
5761
5762 Returns:
5763 result: (str, str) COMPLETED/FAILED, details
5764 """
5765 try:
5766 charm_type = charm_type or "lxc_proxy_charm"
5767 output = await self.vca_map[charm_type].upgrade_charm(
5768 ee_id=ee_id,
5769 path=path,
5770 charm_id=charm_id,
5771 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005772 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005773 )
5774
5775 if output:
5776 return "COMPLETED", output
5777
5778 except (LcmException, asyncio.CancelledError):
5779 raise
5780
5781 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005782 self.logger.debug("Error upgrading charm {}".format(path))
5783
5784 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5785
5786 async def update(self, nsr_id, nslcmop_id):
5787 """Update NS according to different update types
5788
5789 This method performs upgrade of VNF instances then updates the revision
5790 number in VNF record
5791
5792 Args:
5793 nsr_id: Network service will be updated
5794 nslcmop_id: ns lcm operation id
5795
5796 Returns:
5797 It may raise DbException, LcmException, N2VCException, K8sException
5798
5799 """
5800 # Try to lock HA task here
5801 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5802 if not task_is_locked_by_me:
5803 return
5804
5805 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5806 self.logger.debug(logging_text + "Enter")
5807
5808 # Set the required variables to be filled up later
5809 db_nsr = None
5810 db_nslcmop_update = {}
5811 vnfr_update = {}
5812 nslcmop_operation_state = None
5813 db_nsr_update = {}
5814 error_description_nslcmop = ""
5815 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305816 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005817 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005818 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005819
5820 try:
5821 # wait for any previous tasks in process
5822 step = "Waiting for previous operations to terminate"
5823 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5824 self._write_ns_status(
5825 nsr_id=nsr_id,
5826 ns_state=None,
5827 current_operation="UPDATING",
5828 current_operation_id=nslcmop_id,
5829 )
5830
5831 step = "Getting nslcmop from database"
5832 db_nslcmop = self.db.get_one(
5833 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5834 )
5835 update_type = db_nslcmop["operationParams"]["updateType"]
5836
5837 step = "Getting nsr from database"
5838 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5839 old_operational_status = db_nsr["operational-status"]
5840 db_nsr_update["operational-status"] = "updating"
5841 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5842 nsr_deployed = db_nsr["_admin"].get("deployed")
5843
5844 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005845 # Get the input parameters given through update request
5846 vnf_instance_id = db_nslcmop["operationParams"][
5847 "changeVnfPackageData"
5848 ].get("vnfInstanceId")
5849
5850 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5851 "vnfdId"
5852 )
5853 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5854
5855 step = "Getting vnfr from database"
5856 db_vnfr = self.db.get_one(
5857 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5858 )
5859
5860 step = "Getting vnfds from database"
5861 # Latest VNFD
5862 latest_vnfd = self.db.get_one(
5863 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5864 )
5865 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5866
5867 # Current VNFD
5868 current_vnf_revision = db_vnfr.get("revision", 1)
5869 current_vnfd = self.db.get_one(
5870 "vnfds_revisions",
5871 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5872 fail_on_empty=False,
5873 )
5874 # Charm artifact paths will be filled up later
5875 (
5876 current_charm_artifact_path,
5877 target_charm_artifact_path,
5878 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005879 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005880 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005881
5882 step = "Checking if revision has changed in VNFD"
5883 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305884 change_type = "policy_updated"
5885
aticigdffa6212022-04-12 15:27:53 +03005886 # There is new revision of VNFD, update operation is required
5887 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005888 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005889
5890 step = "Removing the VNFD packages if they exist in the local path"
5891 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5892 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5893
5894 step = "Get the VNFD packages from FSMongo"
5895 self.fs.sync(from_path=latest_vnfd_path)
5896 self.fs.sync(from_path=current_vnfd_path)
5897
5898 step = (
5899 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5900 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005901 current_base_folder = current_vnfd["_admin"]["storage"]
5902 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005903
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005904 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005905 get_iterable(nsr_deployed, "VCA")
5906 ):
5907 vnf_index = db_vnfr.get("member-vnf-index-ref")
5908
5909 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005910 if vca_deployed.get("member-vnf-index") == vnf_index:
5911 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5912 vca_type = vca_deployed.get("type")
5913 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005914
5915 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005916 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005917
5918 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005919 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005920 search_key = "kdu_name"
5921 else:
5922 search_key = "vnfd_id"
5923
5924 entity_id = vca_deployed.get(search_key)
5925
aticigdffa6212022-04-12 15:27:53 +03005926 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005927 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005928 )
5929
5930 if "execution-environment-list" in descriptor_config:
5931 ee_list = descriptor_config.get(
5932 "execution-environment-list", []
5933 )
5934 else:
5935 ee_list = []
5936
5937 # There could be several charm used in the same VNF
5938 for ee_item in ee_list:
5939 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005940 step = "Getting charm name"
5941 charm_name = ee_item["juju"].get("charm")
5942
5943 step = "Setting Charm artifact paths"
5944 current_charm_artifact_path.append(
5945 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005946 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005947 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005948 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005949 current_vnf_revision,
5950 )
5951 )
5952 target_charm_artifact_path.append(
5953 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005954 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005955 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005956 vca_type,
aticigd7083542022-05-30 20:45:55 +03005957 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005958 )
5959 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005960 elif ee_item.get("helm-chart"):
5961 # add chart to list and all parameters
5962 step = "Getting helm chart name"
5963 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00005964 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005965 step = "Setting Helm chart artifact paths"
5966
garciadeblasfb1e25f2022-11-18 14:36:22 +01005967 helm_artifacts.append(
5968 {
5969 "current_artifact_path": get_charm_artifact_path(
5970 current_base_folder,
5971 chart_name,
5972 vca_type,
5973 current_vnf_revision,
5974 ),
5975 "target_artifact_path": get_charm_artifact_path(
5976 latest_base_folder,
5977 chart_name,
5978 vca_type,
5979 latest_vnfd_revision,
5980 ),
5981 "ee_id": ee_id,
5982 "vca_index": vca_index,
5983 "vdu_index": vdu_count_index,
5984 }
5985 )
aticigdffa6212022-04-12 15:27:53 +03005986
5987 charm_artifact_paths = zip(
5988 current_charm_artifact_path, target_charm_artifact_path
5989 )
5990
5991 step = "Checking if software version has changed in VNFD"
5992 if find_software_version(current_vnfd) != find_software_version(
5993 latest_vnfd
5994 ):
aticigdffa6212022-04-12 15:27:53 +03005995 step = "Checking if existing VNF has charm"
5996 for current_charm_path, target_charm_path in list(
5997 charm_artifact_paths
5998 ):
5999 if current_charm_path:
6000 raise LcmException(
6001 "Software version change is not supported as VNF instance {} has charm.".format(
6002 vnf_instance_id
6003 )
6004 )
6005
kayal20010cd8af32024-03-13 10:23:16 +05306006 step = "Checking whether the descriptor has SFC"
6007 if db_nsr.get("nsd", {}).get("vnffgd"):
6008 raise LcmException(
6009 "Ns update is not allowed for NS with SFC"
6010 )
6011
aticigdffa6212022-04-12 15:27:53 +03006012 # There is no change in the charm package, then redeploy the VNF
6013 # based on new descriptor
6014 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306015 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006016 (result, detailed_status) = await self._ns_redeploy_vnf(
6017 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306018 )
6019 if result == "FAILED":
6020 nslcmop_operation_state = result
6021 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306022 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306023 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306024 db_nsr_update["detailed-status"] = detailed_status
6025 scaling_aspect = get_scaling_aspect(latest_vnfd)
6026 scaling_group_desc = db_nsr.get("_admin").get(
6027 "scaling-group", None
6028 )
6029 if scaling_group_desc:
6030 for aspect in scaling_aspect:
6031 scaling_group_id = aspect.get("id")
6032 for scale_index, scaling_group in enumerate(
6033 scaling_group_desc
6034 ):
6035 if scaling_group.get("name") == scaling_group_id:
6036 db_nsr_update[
6037 "_admin.scaling-group.{}.nb-scale-op".format(
6038 scale_index
6039 )
6040 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306041 self.logger.debug(
6042 logging_text
6043 + " step {} Done with result {} {}".format(
6044 step, nslcmop_operation_state, detailed_status
6045 )
6046 )
aticigdffa6212022-04-12 15:27:53 +03006047
6048 else:
6049 step = "Checking if any charm package has changed or not"
6050 for current_charm_path, target_charm_path in list(
6051 charm_artifact_paths
6052 ):
6053 if (
6054 current_charm_path
6055 and target_charm_path
6056 and self.check_charm_hash_changed(
6057 current_charm_path, target_charm_path
6058 )
6059 ):
aticigdffa6212022-04-12 15:27:53 +03006060 step = "Checking whether VNF uses juju bundle"
6061 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006062 raise LcmException(
6063 "Charm upgrade is not supported for the instance which"
6064 " uses juju-bundle: {}".format(
6065 check_juju_bundle_existence(current_vnfd)
6066 )
6067 )
6068
6069 step = "Upgrading Charm"
6070 (
6071 result,
6072 detailed_status,
6073 ) = await self._ns_charm_upgrade(
6074 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006075 charm_id=vca_id,
6076 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006077 path=self.fs.path + target_charm_path,
6078 timeout=timeout_seconds,
6079 )
6080
6081 if result == "FAILED":
6082 nslcmop_operation_state = result
6083 error_description_nslcmop = detailed_status
6084
6085 db_nslcmop_update["detailed-status"] = detailed_status
6086 self.logger.debug(
6087 logging_text
6088 + " step {} Done with result {} {}".format(
6089 step, nslcmop_operation_state, detailed_status
6090 )
6091 )
6092
6093 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306094 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6095 result = "COMPLETED"
6096 detailed_status = "Done"
6097 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006098
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006099 # helm base EE
6100 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006101 if not (
6102 item["current_artifact_path"]
6103 and item["target_artifact_path"]
6104 and self.check_charm_hash_changed(
6105 item["current_artifact_path"],
6106 item["target_artifact_path"],
6107 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006108 ):
6109 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006110 db_update_entry = "_admin.deployed.VCA.{}.".format(
6111 item["vca_index"]
6112 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006113 vnfr_id = db_vnfr["_id"]
6114 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6115 db_dict = {
6116 "collection": "nsrs",
6117 "filter": {"_id": nsr_id},
6118 "path": db_update_entry,
6119 }
6120 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006121 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006122 namespace=namespace,
6123 helm_id=helm_id,
6124 db_dict=db_dict,
6125 config=osm_config,
6126 artifact_path=item["target_artifact_path"],
6127 vca_type=vca_type,
6128 )
6129 vnf_id = db_vnfr.get("vnfd-ref")
6130 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6131 self.logger.debug("get ssh key block")
6132 rw_mgmt_ip = None
6133 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006134 config_descriptor,
6135 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006136 ):
6137 # Needed to inject a ssh key
6138 user = deep_get(
6139 config_descriptor,
6140 ("config-access", "ssh-access", "default-user"),
6141 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006142 step = (
6143 "Install configuration Software, getting public ssh key"
6144 )
6145 pub_key = await self.vca_map[
6146 vca_type
6147 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006148 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6149 )
6150
garciadeblasfb1e25f2022-11-18 14:36:22 +01006151 step = (
6152 "Insert public key into VM user={} ssh_key={}".format(
6153 user, pub_key
6154 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006155 )
6156 self.logger.debug(logging_text + step)
6157
6158 # wait for RO (ip-address) Insert pub_key into VM
6159 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6160 logging_text,
6161 nsr_id,
6162 vnfr_id,
6163 None,
6164 item["vdu_index"],
6165 user=user,
6166 pub_key=pub_key,
6167 )
6168
6169 initial_config_primitive_list = config_descriptor.get(
6170 "initial-config-primitive"
6171 )
6172 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006173 (
6174 p
6175 for p in initial_config_primitive_list
6176 if p["name"] == "config"
6177 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006178 None,
6179 )
6180 if not config_primitive:
6181 continue
6182
6183 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6184 if rw_mgmt_ip:
6185 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6186 if db_vnfr.get("additionalParamsForVnf"):
6187 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006188 parse_yaml_strings(
6189 db_vnfr["additionalParamsForVnf"].copy()
6190 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006191 )
6192 primitive_params_ = self._map_primitive_params(
6193 config_primitive, {}, deploy_params
6194 )
6195
6196 step = "execute primitive '{}' params '{}'".format(
6197 config_primitive["name"], primitive_params_
6198 )
6199 self.logger.debug(logging_text + step)
6200 await self.vca_map[vca_type].exec_primitive(
6201 ee_id=ee_id,
6202 primitive_name=config_primitive["name"],
6203 params_dict=primitive_params_,
6204 db_dict=db_dict,
6205 vca_id=vca_id,
6206 vca_type=vca_type,
6207 )
6208
6209 step = "Updating policies"
6210 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6211 detailed_status = "Done"
6212 db_nslcmop_update["detailed-status"] = "Done"
6213
aticigdffa6212022-04-12 15:27:53 +03006214 # If nslcmop_operation_state is None, so any operation is not failed.
6215 if not nslcmop_operation_state:
6216 nslcmop_operation_state = "COMPLETED"
6217
6218 # If update CHANGE_VNFPKG nslcmop_operation is successful
6219 # vnf revision need to be updated
6220 vnfr_update["revision"] = latest_vnfd_revision
6221 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6222
6223 self.logger.debug(
6224 logging_text
6225 + " task Done with result {} {}".format(
6226 nslcmop_operation_state, detailed_status
6227 )
6228 )
6229 elif update_type == "REMOVE_VNF":
6230 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306231 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6232 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6233 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6234 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006235 (result, detailed_status) = await self.remove_vnf(
6236 nsr_id, nslcmop_id, vnf_instance_id
6237 )
elumalaica7ece02022-04-12 12:47:32 +05306238 if result == "FAILED":
6239 nslcmop_operation_state = result
6240 error_description_nslcmop = detailed_status
6241 db_nslcmop_update["detailed-status"] = detailed_status
6242 change_type = "vnf_terminated"
6243 if not nslcmop_operation_state:
6244 nslcmop_operation_state = "COMPLETED"
6245 self.logger.debug(
6246 logging_text
6247 + " task Done with result {} {}".format(
6248 nslcmop_operation_state, detailed_status
6249 )
6250 )
aticigdffa6212022-04-12 15:27:53 +03006251
k4.rahulb827de92022-05-02 16:35:02 +00006252 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006253 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6254 "vnfInstanceId"
6255 ]
6256 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6257 "changeStateTo"
6258 ]
6259 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6260 "additionalParam"
6261 ]
k4.rahulb827de92022-05-02 16:35:02 +00006262 (result, detailed_status) = await self.rebuild_start_stop(
6263 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006264 )
k4.rahulb827de92022-05-02 16:35:02 +00006265 if result == "FAILED":
6266 nslcmop_operation_state = result
6267 error_description_nslcmop = detailed_status
6268 db_nslcmop_update["detailed-status"] = detailed_status
6269 if not nslcmop_operation_state:
6270 nslcmop_operation_state = "COMPLETED"
6271 self.logger.debug(
6272 logging_text
6273 + " task Done with result {} {}".format(
6274 nslcmop_operation_state, detailed_status
6275 )
6276 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306277 elif update_type == "VERTICAL_SCALE":
6278 self.logger.debug(
6279 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6280 )
6281 # Get the input parameters given through update request
6282 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6283 "vnfInstanceId"
6284 )
6285
6286 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6287 "vnfdId"
6288 )
6289 step = "Getting vnfr from database"
6290 db_vnfr = self.db.get_one(
6291 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6292 )
6293 self.logger.debug(step)
6294 step = "Getting vnfds from database"
6295 self.logger.debug("Start" + step)
6296 # Latest VNFD
6297 latest_vnfd = self.db.get_one(
6298 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6299 )
6300 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6301 # Current VNFD
6302 current_vnf_revision = db_vnfr.get("revision", 1)
6303 current_vnfd = self.db.get_one(
6304 "vnfds_revisions",
6305 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6306 fail_on_empty=False,
6307 )
6308 self.logger.debug("End" + step)
6309 # verify flavor changes
6310 step = "Checking for flavor change"
6311 if find_software_version(current_vnfd) != find_software_version(
6312 latest_vnfd
6313 ):
6314 self.logger.debug("Start" + step)
6315 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6316 "virtual-compute-desc"
6317 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6318 "virtual-storage-desc"
6319 ):
6320 raise LcmException(
6321 "No change in flavor check vnfd {}".format(vnfd_id)
6322 )
6323 else:
6324 raise LcmException(
6325 "No change in software_version of vnfd {}".format(vnfd_id)
6326 )
6327
6328 self.logger.debug("End" + step)
6329
6330 (result, detailed_status) = await self.vertical_scale(
6331 nsr_id, nslcmop_id
6332 )
6333 self.logger.debug(
6334 "vertical_scale result: {} detailed_status :{}".format(
6335 result, detailed_status
6336 )
6337 )
6338 if result == "FAILED":
6339 nslcmop_operation_state = result
6340 error_description_nslcmop = detailed_status
6341 db_nslcmop_update["detailed-status"] = detailed_status
6342 if not nslcmop_operation_state:
6343 nslcmop_operation_state = "COMPLETED"
6344 self.logger.debug(
6345 logging_text
6346 + " task Done with result {} {}".format(
6347 nslcmop_operation_state, detailed_status
6348 )
6349 )
k4.rahulb827de92022-05-02 16:35:02 +00006350
aticigdffa6212022-04-12 15:27:53 +03006351 # If nslcmop_operation_state is None, so any operation is not failed.
6352 # All operations are executed in overall.
6353 if not nslcmop_operation_state:
6354 nslcmop_operation_state = "COMPLETED"
6355 db_nsr_update["operational-status"] = old_operational_status
6356
6357 except (DbException, LcmException, N2VCException, K8sException) as e:
6358 self.logger.error(logging_text + "Exit Exception {}".format(e))
6359 exc = e
6360 except asyncio.CancelledError:
6361 self.logger.error(
6362 logging_text + "Cancelled Exception while '{}'".format(step)
6363 )
6364 exc = "Operation was cancelled"
6365 except asyncio.TimeoutError:
6366 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6367 exc = "Timeout"
6368 except Exception as e:
6369 exc = traceback.format_exc()
6370 self.logger.critical(
6371 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6372 exc_info=True,
6373 )
6374 finally:
6375 if exc:
6376 db_nslcmop_update[
6377 "detailed-status"
6378 ] = (
6379 detailed_status
6380 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6381 nslcmop_operation_state = "FAILED"
6382 db_nsr_update["operational-status"] = old_operational_status
6383 if db_nsr:
6384 self._write_ns_status(
6385 nsr_id=nsr_id,
6386 ns_state=db_nsr["nsState"],
6387 current_operation="IDLE",
6388 current_operation_id=None,
6389 other_update=db_nsr_update,
6390 )
6391
6392 self._write_op_status(
6393 op_id=nslcmop_id,
6394 stage="",
6395 error_message=error_description_nslcmop,
6396 operation_state=nslcmop_operation_state,
6397 other_update=db_nslcmop_update,
6398 )
6399
6400 if nslcmop_operation_state:
6401 try:
elumalaica7ece02022-04-12 12:47:32 +05306402 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306403 "nsr_id": nsr_id,
6404 "nslcmop_id": nslcmop_id,
6405 "operationState": nslcmop_operation_state,
6406 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006407 if (
6408 change_type in ("vnf_terminated", "policy_updated")
6409 and member_vnf_index
6410 ):
elumalaica7ece02022-04-12 12:47:32 +05306411 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006412 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006413 except Exception as e:
6414 self.logger.error(
6415 logging_text + "kafka_write notification Exception {}".format(e)
6416 )
6417 self.logger.debug(logging_text + "Exit")
6418 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6419 return nslcmop_operation_state, detailed_status
6420
tierno59d22d22018-09-25 18:10:19 +02006421 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006422 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006423 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006424 if not task_is_locked_by_me:
6425 return
6426
tierno59d22d22018-09-25 18:10:19 +02006427 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006428 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006429 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006430 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006431 self.logger.debug(logging_text + "Enter")
6432 # get all needed from database
6433 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006434 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006435 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006436 exc = None
tierno9ab95942018-10-10 16:44:22 +02006437 # in case of error, indicates what part of scale was failed to put nsr at error status
6438 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006439 old_operational_status = ""
6440 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006441 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006442 prom_job_name = ""
tierno59d22d22018-09-25 18:10:19 +02006443 try:
kuused124bfe2019-06-18 12:09:24 +02006444 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006445 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006446 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6447 self._write_ns_status(
6448 nsr_id=nsr_id,
6449 ns_state=None,
6450 current_operation="SCALING",
6451 current_operation_id=nslcmop_id,
6452 )
quilesj4cda56b2019-12-05 10:02:20 +00006453
ikalyvas02d9e7b2019-05-27 18:16:01 +03006454 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006455 self.logger.debug(
6456 step + " after having waited for previous tasks to be completed"
6457 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006458 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006459
ikalyvas02d9e7b2019-05-27 18:16:01 +03006460 step = "Getting nsr from database"
6461 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006462 old_operational_status = db_nsr["operational-status"]
6463 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006464
kayal20010cd8af32024-03-13 10:23:16 +05306465 step = "Checking whether the descriptor has SFC"
6466 if db_nsr.get("nsd", {}).get("vnffgd"):
6467 raise LcmException("Scaling is not allowed for NS with SFC")
6468
tierno59d22d22018-09-25 18:10:19 +02006469 step = "Parsing scaling parameters"
6470 db_nsr_update["operational-status"] = "scaling"
6471 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006472 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006473
garciadeblas5697b8b2021-03-24 09:17:02 +01006474 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6475 "scaleByStepData"
6476 ]["member-vnf-index"]
6477 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6478 "scaleByStepData"
6479 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006480 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006481 # for backward compatibility
6482 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6483 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6484 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6485 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6486
tierno59d22d22018-09-25 18:10:19 +02006487 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006488 db_vnfr = self.db.get_one(
6489 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6490 )
bravof922c4172020-11-24 21:21:43 -03006491
David Garciac1fe90a2021-03-31 19:12:02 +02006492 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6493
tierno59d22d22018-09-25 18:10:19 +02006494 step = "Getting vnfd from database"
6495 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006496
aktas13251562021-02-12 22:19:10 +03006497 base_folder = db_vnfd["_admin"]["storage"]
6498
tierno59d22d22018-09-25 18:10:19 +02006499 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006500 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006501 get_scaling_aspect(db_vnfd),
6502 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006503 )
6504 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006505 raise LcmException(
6506 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6507 "at vnfd:scaling-group-descriptor".format(scaling_group)
6508 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006509
tierno15b1cf12019-08-29 13:21:40 +00006510 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006511 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006512 nb_scale_op = 0
6513 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006514 self.update_db_2(
6515 "nsrs",
6516 nsr_id,
6517 {
6518 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006519 {
6520 "name": scaling_group,
6521 "vnf_index": vnf_index,
6522 "nb-scale-op": 0,
6523 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006524 ]
6525 },
6526 )
tierno59d22d22018-09-25 18:10:19 +02006527 admin_scale_index = 0
6528 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006529 for admin_scale_index, admin_scale_info in enumerate(
6530 db_nsr["_admin"]["scaling-group"]
6531 ):
36970ef037852024-04-01 15:41:31 +00006532 if (
6533 admin_scale_info["name"] == scaling_group
6534 and admin_scale_info["vnf_index"] == vnf_index
6535 ):
tierno59d22d22018-09-25 18:10:19 +02006536 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6537 break
tierno9ab95942018-10-10 16:44:22 +02006538 else: # not found, set index one plus last element and add new entry with the name
6539 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006540 db_nsr_update[
6541 "_admin.scaling-group.{}.name".format(admin_scale_index)
6542 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006543 db_nsr_update[
6544 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6545 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006546
6547 vca_scaling_info = []
6548 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006549 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006550 if "aspect-delta-details" not in scaling_descriptor:
6551 raise LcmException(
6552 "Aspect delta details not fount in scaling descriptor {}".format(
6553 scaling_descriptor["name"]
6554 )
6555 )
tierno59d22d22018-09-25 18:10:19 +02006556 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006557 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006558
aktas5f75f102021-03-15 11:26:10 +03006559 scaling_info["scaling_direction"] = "OUT"
6560 scaling_info["vdu-create"] = {}
6561 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006562 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006563 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006564 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006565 # vdu_index also provides the number of instance of the targeted vdu
6566 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006567 if vdu_index <= len(db_vnfr["vdur"]):
6568 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6569 prom_job_name = (
6570 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6571 )
6572 prom_job_name = prom_job_name.replace("_", "")
6573 prom_job_name = prom_job_name.replace("-", "")
6574 else:
6575 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006576 cloud_init_text = self._get_vdu_cloud_init_content(
6577 vdud, db_vnfd
6578 )
tierno72ef84f2020-10-06 08:22:07 +00006579 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006580 additional_params = (
6581 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6582 or {}
6583 )
bravof832f8992020-12-07 12:57:31 -03006584 cloud_init_list = []
6585
6586 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6587 max_instance_count = 10
6588 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006589 max_instance_count = vdu_profile.get(
6590 "max-number-of-instances", 10
6591 )
6592
6593 default_instance_num = get_number_of_instances(
6594 db_vnfd, vdud["id"]
6595 )
aktas5f75f102021-03-15 11:26:10 +03006596 instances_number = vdu_delta.get("number-of-instances", 1)
6597 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006598
aktas5f75f102021-03-15 11:26:10 +03006599 new_instance_count = nb_scale_op + default_instance_num
6600 # Control if new count is over max and vdu count is less than max.
6601 # Then assign new instance count
6602 if new_instance_count > max_instance_count > vdu_count:
6603 instances_number = new_instance_count - max_instance_count
6604 else:
6605 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006606
aktas5f75f102021-03-15 11:26:10 +03006607 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006608 raise LcmException(
6609 "reached the limit of {} (max-instance-count) "
6610 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006611 "scaling-group-descriptor '{}'".format(
6612 nb_scale_op, scaling_group
6613 )
bravof922c4172020-11-24 21:21:43 -03006614 )
bravof832f8992020-12-07 12:57:31 -03006615 for x in range(vdu_delta.get("number-of-instances", 1)):
6616 if cloud_init_text:
6617 # TODO Information of its own ip is not available because db_vnfr is not updated.
6618 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006619 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006620 )
bravof832f8992020-12-07 12:57:31 -03006621 cloud_init_list.append(
6622 self._parse_cloud_init(
6623 cloud_init_text,
6624 additional_params,
6625 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006626 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006627 )
6628 )
aktas5f75f102021-03-15 11:26:10 +03006629 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006630 {
6631 "osm_vdu_id": vdu_delta["id"],
6632 "member-vnf-index": vnf_index,
6633 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006634 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006635 }
6636 )
aktas5f75f102021-03-15 11:26:10 +03006637 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6638 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006639 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006640 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006641 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006642
6643 # Might have different kdus in the same delta
6644 # Should have list for each kdu
6645 if not scaling_info["kdu-create"].get(kdu_name, None):
6646 scaling_info["kdu-create"][kdu_name] = []
6647
6648 kdur = get_kdur(db_vnfr, kdu_name)
6649 if kdur.get("helm-chart"):
6650 k8s_cluster_type = "helm-chart-v3"
6651 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006652 elif kdur.get("juju-bundle"):
6653 k8s_cluster_type = "juju-bundle"
6654 else:
6655 raise LcmException(
6656 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6657 "juju-bundle. Maybe an old NBI version is running".format(
6658 db_vnfr["member-vnf-index-ref"], kdu_name
6659 )
6660 )
6661
6662 max_instance_count = 10
6663 if kdu_profile and "max-number-of-instances" in kdu_profile:
6664 max_instance_count = kdu_profile.get(
6665 "max-number-of-instances", 10
6666 )
6667
6668 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6669 deployed_kdu, _ = get_deployed_kdu(
6670 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006671 )
aktas5f75f102021-03-15 11:26:10 +03006672 if deployed_kdu is None:
6673 raise LcmException(
6674 "KDU '{}' for vnf '{}' not deployed".format(
6675 kdu_name, vnf_index
6676 )
6677 )
6678 kdu_instance = deployed_kdu.get("kdu-instance")
6679 instance_num = await self.k8scluster_map[
6680 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006681 ].get_scale_count(
6682 resource_name,
6683 kdu_instance,
6684 vca_id=vca_id,
6685 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6686 kdu_model=deployed_kdu.get("kdu-model"),
6687 )
aktas5f75f102021-03-15 11:26:10 +03006688 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006689 "number-of-instances", 1
6690 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006691
aktas5f75f102021-03-15 11:26:10 +03006692 # Control if new count is over max and instance_num is less than max.
6693 # Then assign max instance number to kdu replica count
6694 if kdu_replica_count > max_instance_count > instance_num:
6695 kdu_replica_count = max_instance_count
6696 if kdu_replica_count > max_instance_count:
6697 raise LcmException(
6698 "reached the limit of {} (max-instance-count) "
6699 "scaling-out operations for the "
6700 "scaling-group-descriptor '{}'".format(
6701 instance_num, scaling_group
6702 )
6703 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006704
aktas5f75f102021-03-15 11:26:10 +03006705 for x in range(kdu_delta.get("number-of-instances", 1)):
6706 vca_scaling_info.append(
6707 {
6708 "osm_kdu_id": kdu_name,
6709 "member-vnf-index": vnf_index,
6710 "type": "create",
6711 "kdu_index": instance_num + x - 1,
6712 }
6713 )
6714 scaling_info["kdu-create"][kdu_name].append(
6715 {
6716 "member-vnf-index": vnf_index,
6717 "type": "create",
6718 "k8s-cluster-type": k8s_cluster_type,
6719 "resource-name": resource_name,
6720 "scale": kdu_replica_count,
6721 }
6722 )
6723 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006724 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006725
6726 scaling_info["scaling_direction"] = "IN"
6727 scaling_info["vdu-delete"] = {}
6728 scaling_info["kdu-delete"] = {}
6729
bravof832f8992020-12-07 12:57:31 -03006730 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006731 for vdu_delta in delta.get("vdu-delta", {}):
6732 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006733 min_instance_count = 0
6734 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6735 if vdu_profile and "min-number-of-instances" in vdu_profile:
6736 min_instance_count = vdu_profile["min-number-of-instances"]
6737
garciadeblas5697b8b2021-03-24 09:17:02 +01006738 default_instance_num = get_number_of_instances(
6739 db_vnfd, vdu_delta["id"]
6740 )
aktas5f75f102021-03-15 11:26:10 +03006741 instance_num = vdu_delta.get("number-of-instances", 1)
6742 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006743
aktas5f75f102021-03-15 11:26:10 +03006744 new_instance_count = nb_scale_op + default_instance_num
6745
6746 if new_instance_count < min_instance_count < vdu_count:
6747 instances_number = min_instance_count - new_instance_count
6748 else:
6749 instances_number = instance_num
6750
6751 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006752 raise LcmException(
6753 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006754 "scaling-group-descriptor '{}'".format(
6755 nb_scale_op, scaling_group
6756 )
bravof832f8992020-12-07 12:57:31 -03006757 )
aktas13251562021-02-12 22:19:10 +03006758 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006759 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006760 {
6761 "osm_vdu_id": vdu_delta["id"],
6762 "member-vnf-index": vnf_index,
6763 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006764 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006765 }
6766 )
aktas5f75f102021-03-15 11:26:10 +03006767 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6768 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006769 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006770 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006771 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006772
6773 if not scaling_info["kdu-delete"].get(kdu_name, None):
6774 scaling_info["kdu-delete"][kdu_name] = []
6775
6776 kdur = get_kdur(db_vnfr, kdu_name)
6777 if kdur.get("helm-chart"):
6778 k8s_cluster_type = "helm-chart-v3"
6779 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006780 elif kdur.get("juju-bundle"):
6781 k8s_cluster_type = "juju-bundle"
6782 else:
6783 raise LcmException(
6784 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6785 "juju-bundle. Maybe an old NBI version is running".format(
6786 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6787 )
6788 )
6789
6790 min_instance_count = 0
6791 if kdu_profile and "min-number-of-instances" in kdu_profile:
6792 min_instance_count = kdu_profile["min-number-of-instances"]
6793
6794 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6795 deployed_kdu, _ = get_deployed_kdu(
6796 nsr_deployed, kdu_name, vnf_index
6797 )
6798 if deployed_kdu is None:
6799 raise LcmException(
6800 "KDU '{}' for vnf '{}' not deployed".format(
6801 kdu_name, vnf_index
6802 )
6803 )
6804 kdu_instance = deployed_kdu.get("kdu-instance")
6805 instance_num = await self.k8scluster_map[
6806 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006807 ].get_scale_count(
6808 resource_name,
6809 kdu_instance,
6810 vca_id=vca_id,
6811 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6812 kdu_model=deployed_kdu.get("kdu-model"),
6813 )
aktas5f75f102021-03-15 11:26:10 +03006814 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006815 "number-of-instances", 1
6816 )
tierno59d22d22018-09-25 18:10:19 +02006817
aktas5f75f102021-03-15 11:26:10 +03006818 if kdu_replica_count < min_instance_count < instance_num:
6819 kdu_replica_count = min_instance_count
6820 if kdu_replica_count < min_instance_count:
6821 raise LcmException(
6822 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6823 "scaling-group-descriptor '{}'".format(
6824 instance_num, scaling_group
6825 )
6826 )
6827
6828 for x in range(kdu_delta.get("number-of-instances", 1)):
6829 vca_scaling_info.append(
6830 {
6831 "osm_kdu_id": kdu_name,
6832 "member-vnf-index": vnf_index,
6833 "type": "delete",
6834 "kdu_index": instance_num - x - 1,
6835 }
6836 )
6837 scaling_info["kdu-delete"][kdu_name].append(
6838 {
6839 "member-vnf-index": vnf_index,
6840 "type": "delete",
6841 "k8s-cluster-type": k8s_cluster_type,
6842 "resource-name": resource_name,
6843 "scale": kdu_replica_count,
6844 }
6845 )
6846
tierno59d22d22018-09-25 18:10:19 +02006847 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006848 vdu_delete = copy(scaling_info.get("vdu-delete"))
6849 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006850 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006851 if vdu_delete.get(vdur["vdu-id-ref"]):
6852 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006853 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006854 {
6855 "name": vdur.get("name") or vdur.get("vdu-name"),
6856 "vdu_id": vdur["vdu-id-ref"],
6857 "interface": [],
6858 }
6859 )
tierno59d22d22018-09-25 18:10:19 +02006860 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006861 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006862 {
6863 "name": interface["name"],
6864 "ip_address": interface["ip-address"],
6865 "mac_address": interface.get("mac-address"),
6866 }
6867 )
tierno2357f4e2020-10-19 16:38:59 +00006868 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006869
kuuseac3a8882019-10-03 10:48:06 +02006870 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006871 step = "Executing pre-scale vnf-config-primitive"
6872 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006873 for scaling_config_action in scaling_descriptor[
6874 "scaling-config-action"
6875 ]:
6876 if (
6877 scaling_config_action.get("trigger") == "pre-scale-in"
6878 and scaling_type == "SCALE_IN"
6879 ) or (
6880 scaling_config_action.get("trigger") == "pre-scale-out"
6881 and scaling_type == "SCALE_OUT"
6882 ):
6883 vnf_config_primitive = scaling_config_action[
6884 "vnf-config-primitive-name-ref"
6885 ]
6886 step = db_nslcmop_update[
6887 "detailed-status"
6888 ] = "executing pre-scale scaling-config-action '{}'".format(
6889 vnf_config_primitive
6890 )
tiernoda964822019-01-14 15:53:47 +00006891
tierno59d22d22018-09-25 18:10:19 +02006892 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006893 for config_primitive in (
6894 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6895 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006896 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006897 break
6898 else:
6899 raise LcmException(
6900 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006901 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006902 "primitive".format(scaling_group, vnf_config_primitive)
6903 )
tiernoda964822019-01-14 15:53:47 +00006904
aktas5f75f102021-03-15 11:26:10 +03006905 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006906 if db_vnfr.get("additionalParamsForVnf"):
6907 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006908
tierno9ab95942018-10-10 16:44:22 +02006909 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006910 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006911 primitive_params = self._map_primitive_params(
6912 config_primitive, {}, vnfr_params
6913 )
kuuseac3a8882019-10-03 10:48:06 +02006914
tierno7c4e24c2020-05-13 08:41:35 +00006915 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006916 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006917 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006918 vnf_index,
6919 vnf_config_primitive,
6920 primitive_params,
6921 "PRE-SCALE",
6922 )
tierno7c4e24c2020-05-13 08:41:35 +00006923 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006924 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006925 result = "COMPLETED"
6926 result_detail = "Done"
6927 self.logger.debug(
6928 logging_text
6929 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6930 vnf_config_primitive, result, result_detail
6931 )
6932 )
kuuseac3a8882019-10-03 10:48:06 +02006933 else:
tierno7c4e24c2020-05-13 08:41:35 +00006934 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006935 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006936 op_index = (
6937 len(db_nslcmop.get("_admin", {}).get("operations"))
6938 - 1
6939 )
6940 self.logger.debug(
6941 logging_text
6942 + "vnf_config_primitive={} New sub-operation".format(
6943 vnf_config_primitive
6944 )
6945 )
kuuseac3a8882019-10-03 10:48:06 +02006946 else:
tierno7c4e24c2020-05-13 08:41:35 +00006947 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006948 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6949 op_index
6950 ]
6951 vnf_index = op.get("member_vnf_index")
6952 vnf_config_primitive = op.get("primitive")
6953 primitive_params = op.get("primitive_params")
6954 self.logger.debug(
6955 logging_text
6956 + "vnf_config_primitive={} Sub-operation retry".format(
6957 vnf_config_primitive
6958 )
6959 )
tierno588547c2020-07-01 15:30:20 +00006960 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006961 ee_descriptor_id = config_primitive.get(
6962 "execution-environment-ref"
6963 )
6964 primitive_name = config_primitive.get(
6965 "execution-environment-primitive", vnf_config_primitive
6966 )
6967 ee_id, vca_type = self._look_for_deployed_vca(
6968 nsr_deployed["VCA"],
6969 member_vnf_index=vnf_index,
6970 vdu_id=None,
6971 vdu_count_index=None,
6972 ee_descriptor_id=ee_descriptor_id,
6973 )
kuuseac3a8882019-10-03 10:48:06 +02006974 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006975 ee_id,
6976 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006977 primitive_params,
6978 vca_type=vca_type,
6979 vca_id=vca_id,
6980 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006981 self.logger.debug(
6982 logging_text
6983 + "vnf_config_primitive={} Done with result {} {}".format(
6984 vnf_config_primitive, result, result_detail
6985 )
6986 )
kuuseac3a8882019-10-03 10:48:06 +02006987 # Update operationState = COMPLETED | FAILED
6988 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006989 db_nslcmop, op_index, result, result_detail
6990 )
kuuseac3a8882019-10-03 10:48:06 +02006991
tierno59d22d22018-09-25 18:10:19 +02006992 if result == "FAILED":
6993 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006994 db_nsr_update["config-status"] = old_config_status
6995 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006996 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006997
garciadeblas5697b8b2021-03-24 09:17:02 +01006998 db_nsr_update[
6999 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
7000 ] = nb_scale_op
7001 db_nsr_update[
7002 "_admin.scaling-group.{}.time".format(admin_scale_index)
7003 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00007004
aktas13251562021-02-12 22:19:10 +03007005 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007006 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007007 step = db_nslcmop_update[
7008 "detailed-status"
7009 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007010 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007011 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007012 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007013 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007014 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007015 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007016 )
aktas5f75f102021-03-15 11:26:10 +03007017 if vca_info.get("osm_vdu_id"):
7018 vdu_id = vca_info["osm_vdu_id"]
7019 vdu_index = int(vca_info["vdu_index"])
7020 stage[
7021 1
7022 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7023 member_vnf_index, vdu_id, vdu_index
7024 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007025 stage[2] = step = "Scaling in VCA"
7026 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007027 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7028 config_update = db_nsr["configurationStatus"]
7029 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007030 if (
7031 (vca or vca.get("ee_id"))
7032 and vca["member-vnf-index"] == member_vnf_index
7033 and vca["vdu_count_index"] == vdu_index
7034 ):
aktas13251562021-02-12 22:19:10 +03007035 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007036 config_descriptor = get_configuration(
7037 db_vnfd, vca.get("vdu_id")
7038 )
aktas13251562021-02-12 22:19:10 +03007039 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007040 config_descriptor = get_configuration(
7041 db_vnfd, vca.get("kdu_name")
7042 )
aktas13251562021-02-12 22:19:10 +03007043 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007044 config_descriptor = get_configuration(
7045 db_vnfd, db_vnfd["id"]
7046 )
7047 operation_params = (
7048 db_nslcmop.get("operationParams") or {}
7049 )
7050 exec_terminate_primitives = not operation_params.get(
7051 "skip_terminate_primitives"
7052 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007053 task = asyncio.ensure_future(
7054 asyncio.wait_for(
7055 self.destroy_N2VC(
7056 logging_text,
7057 db_nslcmop,
7058 vca,
7059 config_descriptor,
7060 vca_index,
7061 destroy_ee=True,
7062 exec_primitives=exec_terminate_primitives,
7063 scaling_in=True,
7064 vca_id=vca_id,
7065 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007066 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007067 )
7068 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007069 tasks_dict_info[task] = "Terminating VCA {}".format(
7070 vca.get("ee_id")
7071 )
aktas13251562021-02-12 22:19:10 +03007072 del vca_update[vca_index]
7073 del config_update[vca_index]
7074 # wait for pending tasks of terminate primitives
7075 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007076 self.logger.debug(
7077 logging_text
7078 + "Waiting for tasks {}".format(
7079 list(tasks_dict_info.keys())
7080 )
7081 )
7082 error_list = await self._wait_for_tasks(
7083 logging_text,
7084 tasks_dict_info,
7085 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007086 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007087 ),
7088 stage,
7089 nslcmop_id,
7090 )
aktas13251562021-02-12 22:19:10 +03007091 tasks_dict_info.clear()
7092 if error_list:
7093 raise LcmException("; ".join(error_list))
7094
7095 db_vca_and_config_update = {
7096 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007097 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007098 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007099 self.update_db_2(
7100 "nsrs", db_nsr["_id"], db_vca_and_config_update
7101 )
aktas13251562021-02-12 22:19:10 +03007102 scale_process = None
7103 # SCALE-IN VCA - END
7104
kuuseac3a8882019-10-03 10:48:06 +02007105 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007106 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007107 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007108 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007109 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007110 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007111 )
aktas5f75f102021-03-15 11:26:10 +03007112 scaling_info.pop("vdu-create", None)
7113 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007114
tierno9ab95942018-10-10 16:44:22 +02007115 scale_process = None
aktas13251562021-02-12 22:19:10 +03007116 # SCALE RO - END
7117
aktas5f75f102021-03-15 11:26:10 +03007118 # SCALE KDU - BEGIN
7119 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7120 scale_process = "KDU"
7121 await self._scale_kdu(
7122 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7123 )
7124 scaling_info.pop("kdu-create", None)
7125 scaling_info.pop("kdu-delete", None)
7126
7127 scale_process = None
7128 # SCALE KDU - END
7129
7130 if db_nsr_update:
7131 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7132
aktas13251562021-02-12 22:19:10 +03007133 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007134 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007135 step = db_nslcmop_update[
7136 "detailed-status"
7137 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007138 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007139 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007140 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007141 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007142 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007143 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007144 )
aktas13251562021-02-12 22:19:10 +03007145 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007146 if vca_info.get("osm_vdu_id"):
7147 vdu_index = int(vca_info["vdu_index"])
7148 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7149 if db_vnfr.get("additionalParamsForVnf"):
7150 deploy_params.update(
7151 parse_yaml_strings(
7152 db_vnfr["additionalParamsForVnf"].copy()
7153 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007154 )
aktas5f75f102021-03-15 11:26:10 +03007155 descriptor_config = get_configuration(
7156 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007157 )
aktas5f75f102021-03-15 11:26:10 +03007158 if descriptor_config:
7159 vdu_id = None
7160 vdu_name = None
7161 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007162 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007163 self._deploy_n2vc(
7164 logging_text=logging_text
7165 + "member_vnf_index={} ".format(member_vnf_index),
7166 db_nsr=db_nsr,
7167 db_vnfr=db_vnfr,
7168 nslcmop_id=nslcmop_id,
7169 nsr_id=nsr_id,
7170 nsi_id=nsi_id,
7171 vnfd_id=vnfd_id,
7172 vdu_id=vdu_id,
7173 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007174 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007175 member_vnf_index=member_vnf_index,
7176 vdu_index=vdu_index,
7177 vdu_name=vdu_name,
7178 deploy_params=deploy_params,
7179 descriptor_config=descriptor_config,
7180 base_folder=base_folder,
7181 task_instantiation_info=tasks_dict_info,
7182 stage=stage,
7183 )
7184 vdu_id = vca_info["osm_vdu_id"]
7185 vdur = find_in_list(
7186 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007187 )
aktas5f75f102021-03-15 11:26:10 +03007188 descriptor_config = get_configuration(db_vnfd, vdu_id)
7189 if vdur.get("additionalParams"):
7190 deploy_params_vdu = parse_yaml_strings(
7191 vdur["additionalParams"]
7192 )
7193 else:
7194 deploy_params_vdu = deploy_params
7195 deploy_params_vdu["OSM"] = get_osm_params(
7196 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007197 )
aktas5f75f102021-03-15 11:26:10 +03007198 if descriptor_config:
7199 vdu_name = None
7200 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007201 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007202 stage[
7203 1
7204 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007205 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007206 )
7207 stage[2] = step = "Scaling out VCA"
7208 self._write_op_status(op_id=nslcmop_id, stage=stage)
7209 self._deploy_n2vc(
7210 logging_text=logging_text
7211 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7212 member_vnf_index, vdu_id, vdu_index
7213 ),
7214 db_nsr=db_nsr,
7215 db_vnfr=db_vnfr,
7216 nslcmop_id=nslcmop_id,
7217 nsr_id=nsr_id,
7218 nsi_id=nsi_id,
7219 vnfd_id=vnfd_id,
7220 vdu_id=vdu_id,
7221 kdu_name=kdu_name,
7222 member_vnf_index=member_vnf_index,
7223 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007224 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007225 vdu_name=vdu_name,
7226 deploy_params=deploy_params_vdu,
7227 descriptor_config=descriptor_config,
7228 base_folder=base_folder,
7229 task_instantiation_info=tasks_dict_info,
7230 stage=stage,
7231 )
aktas13251562021-02-12 22:19:10 +03007232 # SCALE-UP VCA - END
7233 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007234
kuuseac3a8882019-10-03 10:48:06 +02007235 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007236 # execute primitive service POST-SCALING
7237 step = "Executing post-scale vnf-config-primitive"
7238 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007239 for scaling_config_action in scaling_descriptor[
7240 "scaling-config-action"
7241 ]:
7242 if (
7243 scaling_config_action.get("trigger") == "post-scale-in"
7244 and scaling_type == "SCALE_IN"
7245 ) or (
7246 scaling_config_action.get("trigger") == "post-scale-out"
7247 and scaling_type == "SCALE_OUT"
7248 ):
7249 vnf_config_primitive = scaling_config_action[
7250 "vnf-config-primitive-name-ref"
7251 ]
7252 step = db_nslcmop_update[
7253 "detailed-status"
7254 ] = "executing post-scale scaling-config-action '{}'".format(
7255 vnf_config_primitive
7256 )
tiernoda964822019-01-14 15:53:47 +00007257
aktas5f75f102021-03-15 11:26:10 +03007258 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007259 if db_vnfr.get("additionalParamsForVnf"):
7260 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7261
tierno59d22d22018-09-25 18:10:19 +02007262 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007263 for config_primitive in (
7264 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7265 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007266 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007267 break
7268 else:
tiernoa278b842020-07-08 15:33:55 +00007269 raise LcmException(
7270 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7271 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007272 "config-primitive".format(
7273 scaling_group, vnf_config_primitive
7274 )
7275 )
tierno9ab95942018-10-10 16:44:22 +02007276 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007277 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007278 primitive_params = self._map_primitive_params(
7279 config_primitive, {}, vnfr_params
7280 )
tiernod6de1992018-10-11 13:05:52 +02007281
tierno7c4e24c2020-05-13 08:41:35 +00007282 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007283 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007284 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007285 vnf_index,
7286 vnf_config_primitive,
7287 primitive_params,
7288 "POST-SCALE",
7289 )
quilesj4cda56b2019-12-05 10:02:20 +00007290 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007291 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007292 result = "COMPLETED"
7293 result_detail = "Done"
7294 self.logger.debug(
7295 logging_text
7296 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7297 vnf_config_primitive, result, result_detail
7298 )
7299 )
kuuseac3a8882019-10-03 10:48:06 +02007300 else:
quilesj4cda56b2019-12-05 10:02:20 +00007301 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007302 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007303 op_index = (
7304 len(db_nslcmop.get("_admin", {}).get("operations"))
7305 - 1
7306 )
7307 self.logger.debug(
7308 logging_text
7309 + "vnf_config_primitive={} New sub-operation".format(
7310 vnf_config_primitive
7311 )
7312 )
kuuseac3a8882019-10-03 10:48:06 +02007313 else:
tierno7c4e24c2020-05-13 08:41:35 +00007314 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007315 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7316 op_index
7317 ]
7318 vnf_index = op.get("member_vnf_index")
7319 vnf_config_primitive = op.get("primitive")
7320 primitive_params = op.get("primitive_params")
7321 self.logger.debug(
7322 logging_text
7323 + "vnf_config_primitive={} Sub-operation retry".format(
7324 vnf_config_primitive
7325 )
7326 )
tierno588547c2020-07-01 15:30:20 +00007327 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007328 ee_descriptor_id = config_primitive.get(
7329 "execution-environment-ref"
7330 )
7331 primitive_name = config_primitive.get(
7332 "execution-environment-primitive", vnf_config_primitive
7333 )
7334 ee_id, vca_type = self._look_for_deployed_vca(
7335 nsr_deployed["VCA"],
7336 member_vnf_index=vnf_index,
7337 vdu_id=None,
7338 vdu_count_index=None,
7339 ee_descriptor_id=ee_descriptor_id,
7340 )
kuuseac3a8882019-10-03 10:48:06 +02007341 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007342 ee_id,
7343 primitive_name,
7344 primitive_params,
7345 vca_type=vca_type,
7346 vca_id=vca_id,
7347 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007348 self.logger.debug(
7349 logging_text
7350 + "vnf_config_primitive={} Done with result {} {}".format(
7351 vnf_config_primitive, result, result_detail
7352 )
7353 )
kuuseac3a8882019-10-03 10:48:06 +02007354 # Update operationState = COMPLETED | FAILED
7355 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007356 db_nslcmop, op_index, result, result_detail
7357 )
kuuseac3a8882019-10-03 10:48:06 +02007358
tierno59d22d22018-09-25 18:10:19 +02007359 if result == "FAILED":
7360 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007361 db_nsr_update["config-status"] = old_config_status
7362 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007363 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007364 # Check if each vnf has exporter for metric collection if so update prometheus job records
Rahul Kumar54671c52024-05-09 15:34:01 +05307365 if scaling_type == "SCALE_OUT" and bool(self.service_kpi.old_sa):
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007366 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7367 vnfr_id = db_vnfr["id"]
7368 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7369 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7370 self.logger.debug("exporter config :{}".format(exporter_config))
7371 artifact_path = "{}/{}/{}".format(
7372 base_folder["folder"],
7373 base_folder["pkg-dir"],
7374 "exporter-endpoint",
7375 )
7376 ee_id = None
7377 ee_config_descriptor = exporter_config
7378 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7379 logging_text,
7380 nsr_id,
7381 vnfr_id,
7382 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7383 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7384 user=None,
7385 pub_key=None,
7386 )
7387 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7388 self.logger.debug("Artifact_path:{}".format(artifact_path))
7389 vdu_id_for_prom = None
7390 vdu_index_for_prom = None
7391 for x in get_iterable(db_vnfr, "vdur"):
7392 vdu_id_for_prom = x.get("vdu-id-ref")
7393 vdu_index_for_prom = x.get("count-index")
7394 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7395 vnfr_id = vnfr_id.replace("_", "")
7396 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7397 ee_id=ee_id,
7398 artifact_path=artifact_path,
7399 ee_config_descriptor=ee_config_descriptor,
7400 vnfr_id=vnfr_id,
7401 nsr_id=nsr_id,
7402 target_ip=rw_mgmt_ip,
7403 element_type="VDU",
7404 vdu_id=vdu_id_for_prom,
7405 vdu_index=vdu_index_for_prom,
7406 )
tierno59d22d22018-09-25 18:10:19 +02007407
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007408 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7409 if prometheus_jobs:
7410 db_nsr_update[
7411 "_admin.deployed.prometheus_jobs"
7412 ] = prometheus_jobs
7413 self.update_db_2(
7414 "nsrs",
7415 nsr_id,
7416 db_nsr_update,
7417 )
7418
7419 for job in prometheus_jobs:
7420 self.db.set_one(
7421 "prometheus_jobs",
7422 {"job_name": ""},
7423 job,
7424 upsert=True,
7425 fail_on_empty=False,
7426 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007427 db_nsr_update[
7428 "detailed-status"
7429 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7430 db_nsr_update["operational-status"] = (
7431 "running"
7432 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007433 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007434 )
tiernod6de1992018-10-11 13:05:52 +02007435 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007436 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007437 except (
7438 ROclient.ROClientException,
7439 DbException,
7440 LcmException,
7441 NgRoException,
7442 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007443 self.logger.error(logging_text + "Exit Exception {}".format(e))
7444 exc = e
7445 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007446 self.logger.error(
7447 logging_text + "Cancelled Exception while '{}'".format(step)
7448 )
tierno59d22d22018-09-25 18:10:19 +02007449 exc = "Operation was cancelled"
7450 except Exception as e:
7451 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007452 self.logger.critical(
7453 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7454 exc_info=True,
7455 )
tierno59d22d22018-09-25 18:10:19 +02007456 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007457 error_list = list()
7458 if exc:
7459 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007460 self._write_ns_status(
7461 nsr_id=nsr_id,
7462 ns_state=None,
7463 current_operation="IDLE",
7464 current_operation_id=None,
7465 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007466 try:
7467 if tasks_dict_info:
7468 stage[1] = "Waiting for instantiate pending tasks."
7469 self.logger.debug(logging_text + stage[1])
7470 exc = await self._wait_for_tasks(
7471 logging_text,
7472 tasks_dict_info,
7473 self.timeout.ns_deploy,
7474 stage,
7475 nslcmop_id,
7476 nsr_id=nsr_id,
7477 )
7478 except asyncio.CancelledError:
7479 error_list.append("Cancelled")
7480 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7481 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007482 logging_text,
7483 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007484 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007485 stage,
7486 nslcmop_id,
7487 nsr_id=nsr_id,
7488 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007489 if error_list:
7490 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007491 db_nslcmop_update[
7492 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007493 ] = error_description_nslcmop = "FAILED {}: {}".format(
7494 step, error_detail
7495 )
tiernoa17d4f42020-04-28 09:59:23 +00007496 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007497 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007498 db_nsr_update["operational-status"] = old_operational_status
7499 db_nsr_update["config-status"] = old_config_status
7500 db_nsr_update["detailed-status"] = ""
7501 if scale_process:
7502 if "VCA" in scale_process:
7503 db_nsr_update["config-status"] = "failed"
7504 if "RO" in scale_process:
7505 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007506 db_nsr_update[
7507 "detailed-status"
7508 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007509 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007510 )
tiernoa17d4f42020-04-28 09:59:23 +00007511 else:
7512 error_description_nslcmop = None
7513 nslcmop_operation_state = "COMPLETED"
7514 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007515 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7516 self.db.del_one(
7517 "prometheus_jobs",
7518 {"job_name": prom_job_name},
7519 fail_on_empty=False,
7520 )
quilesj4cda56b2019-12-05 10:02:20 +00007521
garciadeblas5697b8b2021-03-24 09:17:02 +01007522 self._write_op_status(
7523 op_id=nslcmop_id,
7524 stage="",
7525 error_message=error_description_nslcmop,
7526 operation_state=nslcmop_operation_state,
7527 other_update=db_nslcmop_update,
7528 )
tiernoa17d4f42020-04-28 09:59:23 +00007529 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007530 self._write_ns_status(
7531 nsr_id=nsr_id,
7532 ns_state=None,
7533 current_operation="IDLE",
7534 current_operation_id=None,
7535 other_update=db_nsr_update,
7536 )
tiernoa17d4f42020-04-28 09:59:23 +00007537
tierno59d22d22018-09-25 18:10:19 +02007538 if nslcmop_operation_state:
7539 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007540 msg = {
7541 "nsr_id": nsr_id,
7542 "nslcmop_id": nslcmop_id,
7543 "operationState": nslcmop_operation_state,
7544 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007545 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007546 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007547 self.logger.error(
7548 logging_text + "kafka_write notification Exception {}".format(e)
7549 )
tierno59d22d22018-09-25 18:10:19 +02007550 self.logger.debug(logging_text + "Exit")
7551 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007552
aktas5f75f102021-03-15 11:26:10 +03007553 async def _scale_kdu(
7554 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7555 ):
7556 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7557 for kdu_name in _scaling_info:
7558 for kdu_scaling_info in _scaling_info[kdu_name]:
7559 deployed_kdu, index = get_deployed_kdu(
7560 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7561 )
7562 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7563 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007564 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007565 scale = int(kdu_scaling_info["scale"])
7566 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7567
7568 db_dict = {
7569 "collection": "nsrs",
7570 "filter": {"_id": nsr_id},
7571 "path": "_admin.deployed.K8s.{}".format(index),
7572 }
7573
7574 step = "scaling application {}".format(
7575 kdu_scaling_info["resource-name"]
7576 )
7577 self.logger.debug(logging_text + step)
7578
7579 if kdu_scaling_info["type"] == "delete":
7580 kdu_config = get_configuration(db_vnfd, kdu_name)
7581 if (
7582 kdu_config
7583 and kdu_config.get("terminate-config-primitive")
7584 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7585 ):
7586 terminate_config_primitive_list = kdu_config.get(
7587 "terminate-config-primitive"
7588 )
7589 terminate_config_primitive_list.sort(
7590 key=lambda val: int(val["seq"])
7591 )
7592
7593 for (
7594 terminate_config_primitive
7595 ) in terminate_config_primitive_list:
7596 primitive_params_ = self._map_primitive_params(
7597 terminate_config_primitive, {}, {}
7598 )
7599 step = "execute terminate config primitive"
7600 self.logger.debug(logging_text + step)
7601 await asyncio.wait_for(
7602 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7603 cluster_uuid=cluster_uuid,
7604 kdu_instance=kdu_instance,
7605 primitive_name=terminate_config_primitive["name"],
7606 params=primitive_params_,
7607 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007608 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007609 vca_id=vca_id,
7610 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007611 timeout=self.timeout.primitive
7612 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007613 )
7614
7615 await asyncio.wait_for(
7616 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007617 kdu_instance=kdu_instance,
7618 scale=scale,
7619 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007620 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007621 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007622 cluster_uuid=cluster_uuid,
7623 kdu_model=kdu_model,
7624 atomic=True,
7625 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007626 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007627 timeout=self.timeout.scale_on_error
7628 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007629 )
7630
7631 if kdu_scaling_info["type"] == "create":
7632 kdu_config = get_configuration(db_vnfd, kdu_name)
7633 if (
7634 kdu_config
7635 and kdu_config.get("initial-config-primitive")
7636 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7637 ):
7638 initial_config_primitive_list = kdu_config.get(
7639 "initial-config-primitive"
7640 )
7641 initial_config_primitive_list.sort(
7642 key=lambda val: int(val["seq"])
7643 )
7644
7645 for initial_config_primitive in initial_config_primitive_list:
7646 primitive_params_ = self._map_primitive_params(
7647 initial_config_primitive, {}, {}
7648 )
7649 step = "execute initial config primitive"
7650 self.logger.debug(logging_text + step)
7651 await asyncio.wait_for(
7652 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7653 cluster_uuid=cluster_uuid,
7654 kdu_instance=kdu_instance,
7655 primitive_name=initial_config_primitive["name"],
7656 params=primitive_params_,
7657 db_dict=db_dict,
7658 vca_id=vca_id,
7659 ),
7660 timeout=600,
7661 )
7662
garciadeblas5697b8b2021-03-24 09:17:02 +01007663 async def _scale_ng_ro(
7664 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7665 ):
tierno2357f4e2020-10-19 16:38:59 +00007666 nsr_id = db_nslcmop["nsInstanceId"]
7667 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7668 db_vnfrs = {}
7669
7670 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007671 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007672
7673 # for each vnf in ns, read vnfd
7674 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7675 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7676 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007677 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007678 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007679 # read from db
7680 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007681 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007682 n2vc_key = self.n2vc.get_public_key()
7683 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007684 self.scale_vnfr(
7685 db_vnfr,
7686 vdu_scaling_info.get("vdu-create"),
7687 vdu_scaling_info.get("vdu-delete"),
7688 mark_delete=True,
7689 )
tierno2357f4e2020-10-19 16:38:59 +00007690 # db_vnfr has been updated, update db_vnfrs to use it
7691 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007692 await self._instantiate_ng_ro(
7693 logging_text,
7694 nsr_id,
7695 db_nsd,
7696 db_nsr,
7697 db_nslcmop,
7698 db_vnfrs,
7699 db_vnfds,
7700 n2vc_key_list,
7701 stage=stage,
7702 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007703 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007704 )
tierno2357f4e2020-10-19 16:38:59 +00007705 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007706 self.scale_vnfr(
7707 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7708 )
tierno2357f4e2020-10-19 16:38:59 +00007709
bravof73bac502021-05-11 07:38:47 -04007710 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007711 self,
7712 ee_id: str,
7713 artifact_path: str,
7714 ee_config_descriptor: dict,
7715 vnfr_id: str,
7716 nsr_id: str,
7717 target_ip: str,
7718 element_type: str,
7719 vnf_member_index: str = "",
7720 vdu_id: str = "",
7721 vdu_index: int = None,
7722 kdu_name: str = "",
7723 kdu_index: int = None,
7724 ) -> dict:
7725 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7726 This method will wait until the corresponding VDU or KDU is fully instantiated
7727
7728 Args:
7729 ee_id (str): Execution Environment ID
7730 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7731 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7732 vnfr_id (str): VNFR ID where this EE applies
7733 nsr_id (str): NSR ID where this EE applies
7734 target_ip (str): VDU/KDU instance IP address
7735 element_type (str): NS or VNF or VDU or KDU
7736 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7737 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7738 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7739 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7740 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7741
7742 Raises:
7743 LcmException: When the VDU or KDU instance was not found in an hour
7744
7745 Returns:
7746 _type_: Prometheus jobs
7747 """
7748 # default the vdur and kdur names to an empty string, to avoid any later
7749 # problem with Prometheus when the element type is not VDU or KDU
7750 vdur_name = ""
7751 kdur_name = ""
7752
tiernob996d942020-07-03 14:52:28 +00007753 # look if exist a file called 'prometheus*.j2' and
7754 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007755 job_file = next(
7756 (
7757 f
7758 for f in artifact_content
7759 if f.startswith("prometheus") and f.endswith(".j2")
7760 ),
7761 None,
7762 )
tiernob996d942020-07-03 14:52:28 +00007763 if not job_file:
7764 return
k4.rahul74944982023-04-19 17:00:52 +05307765 self.logger.debug("Artifact path{}".format(artifact_path))
7766 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007767 with self.fs.file_open((artifact_path, job_file), "r") as f:
7768 job_data = f.read()
7769
Pedro Escaleira120695e2022-06-11 21:17:26 +01007770 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7771 if element_type in ("VDU", "KDU"):
7772 for _ in range(360):
7773 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7774 if vdu_id and vdu_index is not None:
7775 vdur = next(
7776 (
7777 x
7778 for x in get_iterable(db_vnfr, "vdur")
7779 if (
7780 x.get("vdu-id-ref") == vdu_id
7781 and x.get("count-index") == vdu_index
7782 )
7783 ),
7784 {},
7785 )
7786 if vdur.get("name"):
7787 vdur_name = vdur.get("name")
7788 break
7789 if kdu_name and kdu_index is not None:
7790 kdur = next(
7791 (
7792 x
7793 for x in get_iterable(db_vnfr, "kdur")
7794 if (
7795 x.get("kdu-name") == kdu_name
7796 and x.get("count-index") == kdu_index
7797 )
7798 ),
7799 {},
7800 )
7801 if kdur.get("name"):
7802 kdur_name = kdur.get("name")
7803 break
7804
Gabriel Cubae7898982023-05-11 01:57:21 -05007805 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007806 else:
7807 if vdu_id and vdu_index is not None:
7808 raise LcmException(
7809 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7810 )
7811 if kdu_name and kdu_index is not None:
7812 raise LcmException(
7813 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7814 )
7815
k4.rahul74944982023-04-19 17:00:52 +05307816 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007817 _, namespace, helm_id = get_ee_id_parts(
7818 ee_id
7819 ) # get namespace and EE gRPC service name
7820 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307821 host_port = "80"
7822 vnfr_id = vnfr_id.replace("-", "")
7823 variables = {
7824 "JOB_NAME": vnfr_id,
7825 "TARGET_IP": target_ip,
7826 "EXPORTER_POD_IP": host_name,
7827 "EXPORTER_POD_PORT": host_port,
7828 "NSR_ID": nsr_id,
7829 "VNF_MEMBER_INDEX": vnf_member_index,
7830 "VDUR_NAME": vdur_name,
7831 "KDUR_NAME": kdur_name,
7832 "ELEMENT_TYPE": element_type,
7833 }
7834 else:
7835 metric_path = ee_config_descriptor["metric-path"]
7836 target_port = ee_config_descriptor["metric-port"]
7837 vnfr_id = vnfr_id.replace("-", "")
7838 variables = {
7839 "JOB_NAME": vnfr_id,
7840 "TARGET_IP": target_ip,
7841 "TARGET_PORT": target_port,
7842 "METRIC_PATH": metric_path,
7843 }
7844
bravof73bac502021-05-11 07:38:47 -04007845 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007846 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7847 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007848 if (
7849 not isinstance(job.get("job_name"), str)
7850 or vnfr_id not in job["job_name"]
7851 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307852 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007853 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007854 job["vnfr_id"] = vnfr_id
7855 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007856
preethika.p28b0bf82022-09-23 07:36:28 +00007857 async def rebuild_start_stop(
7858 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7859 ):
k4.rahulb827de92022-05-02 16:35:02 +00007860 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7861 self.logger.info(logging_text + "Enter")
7862 stage = ["Preparing the environment", ""]
7863 # database nsrs record
7864 db_nsr_update = {}
7865 vdu_vim_name = None
7866 vim_vm_id = None
7867 # in case of error, indicates what part of scale was failed to put nsr at error status
7868 start_deploy = time()
7869 try:
7870 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7871 vim_account_id = db_vnfr.get("vim-account-id")
7872 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007873 vdu_id = additional_param["vdu_id"]
7874 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007875 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007876 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007877 )
k4.rahulb827de92022-05-02 16:35:02 +00007878 if vdur:
7879 vdu_vim_name = vdur["name"]
7880 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7881 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007882 else:
7883 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007884 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7885 # wait for any previous tasks in process
7886 stage[1] = "Waiting for previous operations to terminate"
7887 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007888 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007889
7890 stage[1] = "Reading from database."
7891 self.logger.info(stage[1])
7892 self._write_ns_status(
7893 nsr_id=nsr_id,
7894 ns_state=None,
7895 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007896 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007897 )
7898 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7899
7900 # read from db: ns
7901 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7902 db_nsr_update["operational-status"] = operation_type
7903 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7904 # Payload for RO
7905 desc = {
7906 operation_type: {
7907 "vim_vm_id": vim_vm_id,
7908 "vnf_id": vnf_id,
7909 "vdu_index": additional_param["count-index"],
7910 "vdu_id": vdur["id"],
7911 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007912 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007913 }
7914 }
7915 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7916 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7917 self.logger.info("ro nsr id: {}".format(nsr_id))
7918 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7919 self.logger.info("response from RO: {}".format(result_dict))
7920 action_id = result_dict["action_id"]
7921 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007922 nsr_id,
7923 action_id,
7924 nslcmop_id,
7925 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007926 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007927 None,
7928 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007929 )
7930 return "COMPLETED", "Done"
7931 except (ROclient.ROClientException, DbException, LcmException) as e:
7932 self.logger.error("Exit Exception {}".format(e))
7933 exc = e
7934 except asyncio.CancelledError:
7935 self.logger.error("Cancelled Exception while '{}'".format(stage))
7936 exc = "Operation was cancelled"
7937 except Exception as e:
7938 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007939 self.logger.critical(
7940 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7941 )
k4.rahulb827de92022-05-02 16:35:02 +00007942 return "FAILED", "Error in operate VNF {}".format(exc)
7943
elumalai80bcf1c2022-04-28 18:05:01 +05307944 async def migrate(self, nsr_id, nslcmop_id):
7945 """
7946 Migrate VNFs and VDUs instances in a NS
7947
7948 :param: nsr_id: NS Instance ID
7949 :param: nslcmop_id: nslcmop ID of migrate
7950
7951 """
7952 # Try to lock HA task here
7953 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7954 if not task_is_locked_by_me:
7955 return
7956 logging_text = "Task ns={} migrate ".format(nsr_id)
7957 self.logger.debug(logging_text + "Enter")
7958 # get all needed from database
7959 db_nslcmop = None
7960 db_nslcmop_update = {}
7961 nslcmop_operation_state = None
7962 db_nsr_update = {}
7963 target = {}
7964 exc = None
7965 # in case of error, indicates what part of scale was failed to put nsr at error status
7966 start_deploy = time()
7967
7968 try:
7969 # wait for any previous tasks in process
7970 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007971 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307972
7973 self._write_ns_status(
7974 nsr_id=nsr_id,
7975 ns_state=None,
7976 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007977 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307978 )
7979 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007980 self.logger.debug(
7981 step + " after having waited for previous tasks to be completed"
7982 )
elumalai80bcf1c2022-04-28 18:05:01 +05307983 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7984 migrate_params = db_nslcmop.get("operationParams")
7985
7986 target = {}
7987 target.update(migrate_params)
Pedro Pereirab6cccb22024-08-23 10:23:02 +01007988
7989 if "migrateToHost" in target:
7990 desc = await self.RO.migrate(nsr_id, target)
7991 self.logger.debug("RO return > {}".format(desc))
7992 action_id = desc["action_id"]
7993 await self._wait_ng_ro(
7994 nsr_id,
7995 action_id,
7996 nslcmop_id,
7997 start_deploy,
7998 self.timeout.migrate,
7999 operation="migrate",
8000 )
8001
8002 elif "targetHostK8sLabels" in target:
8003 await self.k8sclusterhelm3.migrate(nsr_id, target)
8004
elumalai80bcf1c2022-04-28 18:05:01 +05308005 except (ROclient.ROClientException, DbException, LcmException) as e:
8006 self.logger.error("Exit Exception {}".format(e))
8007 exc = e
8008 except asyncio.CancelledError:
8009 self.logger.error("Cancelled Exception while '{}'".format(step))
8010 exc = "Operation was cancelled"
8011 except Exception as e:
8012 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03008013 self.logger.critical(
8014 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8015 )
elumalai80bcf1c2022-04-28 18:05:01 +05308016 finally:
8017 self._write_ns_status(
8018 nsr_id=nsr_id,
8019 ns_state=None,
8020 current_operation="IDLE",
8021 current_operation_id=None,
8022 )
8023 if exc:
aticig349aa462022-05-19 12:29:35 +03008024 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308025 nslcmop_operation_state = "FAILED"
8026 else:
8027 nslcmop_operation_state = "COMPLETED"
8028 db_nslcmop_update["detailed-status"] = "Done"
8029 db_nsr_update["detailed-status"] = "Done"
8030
8031 self._write_op_status(
8032 op_id=nslcmop_id,
8033 stage="",
8034 error_message="",
8035 operation_state=nslcmop_operation_state,
8036 other_update=db_nslcmop_update,
8037 )
8038 if nslcmop_operation_state:
8039 try:
8040 msg = {
8041 "nsr_id": nsr_id,
8042 "nslcmop_id": nslcmop_id,
8043 "operationState": nslcmop_operation_state,
8044 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008045 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308046 except Exception as e:
8047 self.logger.error(
8048 logging_text + "kafka_write notification Exception {}".format(e)
8049 )
8050 self.logger.debug(logging_text + "Exit")
8051 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008052
garciadeblas07f4e4c2022-06-09 09:42:58 +02008053 async def heal(self, nsr_id, nslcmop_id):
8054 """
8055 Heal NS
8056
8057 :param nsr_id: ns instance to heal
8058 :param nslcmop_id: operation to run
8059 :return:
8060 """
8061
8062 # Try to lock HA task here
8063 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8064 if not task_is_locked_by_me:
8065 return
8066
8067 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8068 stage = ["", "", ""]
8069 tasks_dict_info = {}
8070 # ^ stage, step, VIM progress
8071 self.logger.debug(logging_text + "Enter")
8072 # get all needed from database
8073 db_nsr = None
8074 db_nslcmop_update = {}
8075 db_nsr_update = {}
8076 db_vnfrs = {} # vnf's info indexed by _id
8077 exc = None
8078 old_operational_status = ""
8079 old_config_status = ""
8080 nsi_id = None
8081 try:
8082 # wait for any previous tasks in process
8083 step = "Waiting for previous operations to terminate"
8084 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8085 self._write_ns_status(
8086 nsr_id=nsr_id,
8087 ns_state=None,
8088 current_operation="HEALING",
8089 current_operation_id=nslcmop_id,
8090 )
8091
8092 step = "Getting nslcmop from database"
8093 self.logger.debug(
8094 step + " after having waited for previous tasks to be completed"
8095 )
8096 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8097
8098 step = "Getting nsr from database"
8099 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8100 old_operational_status = db_nsr["operational-status"]
8101 old_config_status = db_nsr["config-status"]
8102
8103 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008104 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008105 "_admin.deployed.RO.operational-status": "healing",
8106 }
8107 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8108
8109 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008110 await self.heal_RO(
8111 logging_text=logging_text,
8112 nsr_id=nsr_id,
8113 db_nslcmop=db_nslcmop,
8114 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008115 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008116 # VCA tasks
8117 # read from db: nsd
8118 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8119 self.logger.debug(logging_text + stage[1])
8120 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8121 self.fs.sync(db_nsr["nsd-id"])
8122 db_nsr["nsd"] = nsd
8123 # read from db: vnfr's of this ns
8124 step = "Getting vnfrs from db"
8125 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8126 for vnfr in db_vnfrs_list:
8127 db_vnfrs[vnfr["_id"]] = vnfr
8128 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8129
8130 # Check for each target VNF
8131 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8132 for target_vnf in target_list:
8133 # Find this VNF in the list from DB
8134 vnfr_id = target_vnf.get("vnfInstanceId", None)
8135 if vnfr_id:
8136 db_vnfr = db_vnfrs[vnfr_id]
8137 vnfd_id = db_vnfr.get("vnfd-id")
8138 vnfd_ref = db_vnfr.get("vnfd-ref")
8139 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8140 base_folder = vnfd["_admin"]["storage"]
8141 vdu_id = None
8142 vdu_index = 0
8143 vdu_name = None
8144 kdu_name = None
8145 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8146 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8147
8148 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008149 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8150 "vdu", []
8151 )
garciadeblas50639832022-09-01 13:09:47 +02008152 if not target_vdu_list:
8153 # Codigo nuevo para crear diccionario
8154 target_vdu_list = []
8155 for existing_vdu in db_vnfr.get("vdur"):
8156 vdu_name = existing_vdu.get("vdu-name", None)
8157 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008158 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8159 "run-day1", False
8160 )
8161 vdu_to_be_healed = {
8162 "vdu-id": vdu_name,
8163 "count-index": vdu_index,
8164 "run-day1": vdu_run_day1,
8165 }
garciadeblas50639832022-09-01 13:09:47 +02008166 target_vdu_list.append(vdu_to_be_healed)
8167 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008168 deploy_params_vdu = target_vdu
8169 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008170 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8171 "additionalParams", {}
8172 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008173 deploy_params_vdu["run-day1"] = target_vnf[
8174 "additionalParams"
8175 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008176 vdu_name = target_vdu.get("vdu-id", None)
8177 # TODO: Get vdu_id from vdud.
8178 vdu_id = vdu_name
8179 # For multi instance VDU count-index is mandatory
8180 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008181 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008182
8183 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8184 stage[1] = "Deploying Execution Environments."
8185 self.logger.debug(logging_text + stage[1])
8186
8187 # VNF Level charm. Normal case when proxy charms.
8188 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8189 descriptor_config = get_configuration(vnfd, vnfd_ref)
8190 if descriptor_config:
8191 # Continue if healed machine is management machine
8192 vnf_ip_address = db_vnfr.get("ip-address")
8193 target_instance = None
8194 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008195 if (
8196 instance["vdu-name"] == vdu_name
8197 and instance["count-index"] == vdu_index
8198 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008199 target_instance = instance
8200 break
8201 if vnf_ip_address == target_instance.get("ip-address"):
8202 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008203 logging_text=logging_text
8204 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8205 member_vnf_index, vdu_name, vdu_index
8206 ),
8207 db_nsr=db_nsr,
8208 db_vnfr=db_vnfr,
8209 nslcmop_id=nslcmop_id,
8210 nsr_id=nsr_id,
8211 nsi_id=nsi_id,
8212 vnfd_id=vnfd_ref,
8213 vdu_id=None,
8214 kdu_name=None,
8215 member_vnf_index=member_vnf_index,
8216 vdu_index=0,
8217 vdu_name=None,
8218 deploy_params=deploy_params_vdu,
8219 descriptor_config=descriptor_config,
8220 base_folder=base_folder,
8221 task_instantiation_info=tasks_dict_info,
8222 stage=stage,
8223 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008224
8225 # VDU Level charm. Normal case with native charms.
8226 descriptor_config = get_configuration(vnfd, vdu_name)
8227 if descriptor_config:
8228 self._heal_n2vc(
8229 logging_text=logging_text
8230 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8231 member_vnf_index, vdu_name, vdu_index
8232 ),
8233 db_nsr=db_nsr,
8234 db_vnfr=db_vnfr,
8235 nslcmop_id=nslcmop_id,
8236 nsr_id=nsr_id,
8237 nsi_id=nsi_id,
8238 vnfd_id=vnfd_ref,
8239 vdu_id=vdu_id,
8240 kdu_name=kdu_name,
8241 member_vnf_index=member_vnf_index,
8242 vdu_index=vdu_index,
8243 vdu_name=vdu_name,
8244 deploy_params=deploy_params_vdu,
8245 descriptor_config=descriptor_config,
8246 base_folder=base_folder,
8247 task_instantiation_info=tasks_dict_info,
8248 stage=stage,
8249 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008250 except (
8251 ROclient.ROClientException,
8252 DbException,
8253 LcmException,
8254 NgRoException,
8255 ) as e:
8256 self.logger.error(logging_text + "Exit Exception {}".format(e))
8257 exc = e
8258 except asyncio.CancelledError:
8259 self.logger.error(
8260 logging_text + "Cancelled Exception while '{}'".format(step)
8261 )
8262 exc = "Operation was cancelled"
8263 except Exception as e:
8264 exc = traceback.format_exc()
8265 self.logger.critical(
8266 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8267 exc_info=True,
8268 )
8269 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008270 error_list = list()
36970544ef442024-04-01 10:58:42 +00008271 if db_vnfrs_list and target_list:
8272 for vnfrs in db_vnfrs_list:
8273 for vnf_instance in target_list:
8274 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8275 self.db.set_list(
8276 "vnfrs",
8277 {"_id": vnfrs["_id"]},
8278 {"_admin.modified": time()},
8279 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008280 if exc:
8281 error_list.append(str(exc))
8282 try:
8283 if tasks_dict_info:
8284 stage[1] = "Waiting for healing pending tasks."
8285 self.logger.debug(logging_text + stage[1])
8286 exc = await self._wait_for_tasks(
8287 logging_text,
8288 tasks_dict_info,
8289 self.timeout.ns_deploy,
8290 stage,
8291 nslcmop_id,
8292 nsr_id=nsr_id,
8293 )
8294 except asyncio.CancelledError:
8295 error_list.append("Cancelled")
8296 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8297 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008298 logging_text,
8299 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008300 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008301 stage,
8302 nslcmop_id,
8303 nsr_id=nsr_id,
8304 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008305 if error_list:
8306 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008307 db_nslcmop_update[
8308 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008309 ] = error_description_nslcmop = "FAILED {}: {}".format(
8310 step, error_detail
8311 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008312 nslcmop_operation_state = "FAILED"
8313 if db_nsr:
8314 db_nsr_update["operational-status"] = old_operational_status
8315 db_nsr_update["config-status"] = old_config_status
8316 db_nsr_update[
8317 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008318 ] = "FAILED healing nslcmop={} {}: {}".format(
8319 nslcmop_id, step, error_detail
8320 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008321 for task, task_name in tasks_dict_info.items():
8322 if not task.done() or task.cancelled() or task.exception():
8323 if task_name.startswith(self.task_name_deploy_vca):
8324 # A N2VC task is pending
8325 db_nsr_update["config-status"] = "failed"
8326 else:
8327 # RO task is pending
8328 db_nsr_update["operational-status"] = "failed"
8329 else:
8330 error_description_nslcmop = None
8331 nslcmop_operation_state = "COMPLETED"
8332 db_nslcmop_update["detailed-status"] = "Done"
8333 db_nsr_update["detailed-status"] = "Done"
8334 db_nsr_update["operational-status"] = "running"
8335 db_nsr_update["config-status"] = "configured"
8336
8337 self._write_op_status(
8338 op_id=nslcmop_id,
8339 stage="",
8340 error_message=error_description_nslcmop,
8341 operation_state=nslcmop_operation_state,
8342 other_update=db_nslcmop_update,
8343 )
8344 if db_nsr:
8345 self._write_ns_status(
8346 nsr_id=nsr_id,
8347 ns_state=None,
8348 current_operation="IDLE",
8349 current_operation_id=None,
8350 other_update=db_nsr_update,
8351 )
8352
8353 if nslcmop_operation_state:
8354 try:
8355 msg = {
8356 "nsr_id": nsr_id,
8357 "nslcmop_id": nslcmop_id,
8358 "operationState": nslcmop_operation_state,
8359 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008360 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008361 except Exception as e:
8362 self.logger.error(
8363 logging_text + "kafka_write notification Exception {}".format(e)
8364 )
8365 self.logger.debug(logging_text + "Exit")
8366 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8367
8368 async def heal_RO(
8369 self,
8370 logging_text,
8371 nsr_id,
8372 db_nslcmop,
8373 stage,
8374 ):
8375 """
8376 Heal at RO
8377 :param logging_text: preffix text to use at logging
8378 :param nsr_id: nsr identity
8379 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8380 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8381 :return: None or exception
8382 """
preethika.p28b0bf82022-09-23 07:36:28 +00008383
garciadeblas07f4e4c2022-06-09 09:42:58 +02008384 def get_vim_account(vim_account_id):
8385 nonlocal db_vims
8386 if vim_account_id in db_vims:
8387 return db_vims[vim_account_id]
8388 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8389 db_vims[vim_account_id] = db_vim
8390 return db_vim
8391
8392 try:
8393 start_heal = time()
8394 ns_params = db_nslcmop.get("operationParams")
8395 if ns_params and ns_params.get("timeout_ns_heal"):
8396 timeout_ns_heal = ns_params["timeout_ns_heal"]
8397 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008398 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008399
8400 db_vims = {}
8401
8402 nslcmop_id = db_nslcmop["_id"]
8403 target = {
8404 "action_id": nslcmop_id,
8405 }
preethika.p28b0bf82022-09-23 07:36:28 +00008406 self.logger.warning(
8407 "db_nslcmop={} and timeout_ns_heal={}".format(
8408 db_nslcmop, timeout_ns_heal
8409 )
8410 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008411 target.update(db_nslcmop.get("operationParams", {}))
8412
8413 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8414 desc = await self.RO.recreate(nsr_id, target)
8415 self.logger.debug("RO return > {}".format(desc))
8416 action_id = desc["action_id"]
8417 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8418 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008419 nsr_id,
8420 action_id,
8421 nslcmop_id,
8422 start_heal,
8423 timeout_ns_heal,
8424 stage,
8425 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008426 )
8427
8428 # Updating NSR
8429 db_nsr_update = {
8430 "_admin.deployed.RO.operational-status": "running",
8431 "detailed-status": " ".join(stage),
8432 }
8433 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8434 self._write_op_status(nslcmop_id, stage)
8435 self.logger.debug(
8436 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8437 )
8438
8439 except Exception as e:
8440 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008441 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008442 self.logger.error(
8443 "Error healing at VIM {}".format(e),
8444 exc_info=not isinstance(
8445 e,
8446 (
8447 ROclient.ROClientException,
8448 LcmException,
8449 DbException,
8450 NgRoException,
8451 ),
8452 ),
8453 )
8454 raise
8455
8456 def _heal_n2vc(
8457 self,
8458 logging_text,
8459 db_nsr,
8460 db_vnfr,
8461 nslcmop_id,
8462 nsr_id,
8463 nsi_id,
8464 vnfd_id,
8465 vdu_id,
8466 kdu_name,
8467 member_vnf_index,
8468 vdu_index,
8469 vdu_name,
8470 deploy_params,
8471 descriptor_config,
8472 base_folder,
8473 task_instantiation_info,
8474 stage,
8475 ):
8476 # launch instantiate_N2VC in a asyncio task and register task object
8477 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8478 # if not found, create one entry and update database
8479 # fill db_nsr._admin.deployed.VCA.<index>
8480
8481 self.logger.debug(
8482 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8483 )
aticig9bc63ac2022-07-27 09:32:06 +03008484
8485 charm_name = ""
8486 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008487 if "execution-environment-list" in descriptor_config:
8488 ee_list = descriptor_config.get("execution-environment-list", [])
8489 elif "juju" in descriptor_config:
8490 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008491 if "execution-environment-list" not in descriptor_config:
8492 # charm name is only required for ns charms
8493 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008494 else: # other types as script are not supported
8495 ee_list = []
8496
8497 for ee_item in ee_list:
8498 self.logger.debug(
8499 logging_text
8500 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8501 ee_item.get("juju"), ee_item.get("helm-chart")
8502 )
8503 )
8504 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008505 vca_name, charm_name, vca_type = self.get_vca_info(
8506 ee_item, db_nsr, get_charm_name
8507 )
8508 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008509 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008510 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008511 )
8512 continue
8513
8514 vca_index = -1
8515 for vca_index, vca_deployed in enumerate(
8516 db_nsr["_admin"]["deployed"]["VCA"]
8517 ):
8518 if not vca_deployed:
8519 continue
8520 if (
8521 vca_deployed.get("member-vnf-index") == member_vnf_index
8522 and vca_deployed.get("vdu_id") == vdu_id
8523 and vca_deployed.get("kdu_name") == kdu_name
8524 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8525 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8526 ):
8527 break
8528 else:
8529 # not found, create one.
8530 target = (
8531 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8532 )
8533 if vdu_id:
8534 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8535 elif kdu_name:
8536 target += "/kdu/{}".format(kdu_name)
8537 vca_deployed = {
8538 "target_element": target,
8539 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8540 "member-vnf-index": member_vnf_index,
8541 "vdu_id": vdu_id,
8542 "kdu_name": kdu_name,
8543 "vdu_count_index": vdu_index,
8544 "operational-status": "init", # TODO revise
8545 "detailed-status": "", # TODO revise
8546 "step": "initial-deploy", # TODO revise
8547 "vnfd_id": vnfd_id,
8548 "vdu_name": vdu_name,
8549 "type": vca_type,
8550 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008551 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008552 }
8553 vca_index += 1
8554
8555 # create VCA and configurationStatus in db
8556 db_dict = {
8557 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8558 "configurationStatus.{}".format(vca_index): dict(),
8559 }
8560 self.update_db_2("nsrs", nsr_id, db_dict)
8561
8562 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8563
8564 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8565 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8566 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8567
8568 # Launch task
8569 task_n2vc = asyncio.ensure_future(
8570 self.heal_N2VC(
8571 logging_text=logging_text,
8572 vca_index=vca_index,
8573 nsi_id=nsi_id,
8574 db_nsr=db_nsr,
8575 db_vnfr=db_vnfr,
8576 vdu_id=vdu_id,
8577 kdu_name=kdu_name,
8578 vdu_index=vdu_index,
8579 deploy_params=deploy_params,
8580 config_descriptor=descriptor_config,
8581 base_folder=base_folder,
8582 nslcmop_id=nslcmop_id,
8583 stage=stage,
8584 vca_type=vca_type,
8585 vca_name=vca_name,
8586 ee_config_descriptor=ee_item,
8587 )
8588 )
8589 self.lcm_tasks.register(
8590 "ns",
8591 nsr_id,
8592 nslcmop_id,
8593 "instantiate_N2VC-{}".format(vca_index),
8594 task_n2vc,
8595 )
8596 task_instantiation_info[
8597 task_n2vc
8598 ] = self.task_name_deploy_vca + " {}.{}".format(
8599 member_vnf_index or "", vdu_id or ""
8600 )
8601
8602 async def heal_N2VC(
8603 self,
8604 logging_text,
8605 vca_index,
8606 nsi_id,
8607 db_nsr,
8608 db_vnfr,
8609 vdu_id,
8610 kdu_name,
8611 vdu_index,
8612 config_descriptor,
8613 deploy_params,
8614 base_folder,
8615 nslcmop_id,
8616 stage,
8617 vca_type,
8618 vca_name,
8619 ee_config_descriptor,
8620 ):
8621 nsr_id = db_nsr["_id"]
8622 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8623 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8624 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8625 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8626 db_dict = {
8627 "collection": "nsrs",
8628 "filter": {"_id": nsr_id},
8629 "path": db_update_entry,
8630 }
8631 step = ""
8632 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008633 element_type = "NS"
8634 element_under_configuration = nsr_id
8635
8636 vnfr_id = None
8637 if db_vnfr:
8638 vnfr_id = db_vnfr["_id"]
8639 osm_config["osm"]["vnf_id"] = vnfr_id
8640
8641 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8642
8643 if vca_type == "native_charm":
8644 index_number = 0
8645 else:
8646 index_number = vdu_index or 0
8647
8648 if vnfr_id:
8649 element_type = "VNF"
8650 element_under_configuration = vnfr_id
8651 namespace += ".{}-{}".format(vnfr_id, index_number)
8652 if vdu_id:
8653 namespace += ".{}-{}".format(vdu_id, index_number)
8654 element_type = "VDU"
8655 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8656 osm_config["osm"]["vdu_id"] = vdu_id
8657 elif kdu_name:
8658 namespace += ".{}".format(kdu_name)
8659 element_type = "KDU"
8660 element_under_configuration = kdu_name
8661 osm_config["osm"]["kdu_name"] = kdu_name
8662
8663 # Get artifact path
8664 if base_folder["pkg-dir"]:
8665 artifact_path = "{}/{}/{}/{}".format(
8666 base_folder["folder"],
8667 base_folder["pkg-dir"],
8668 "charms"
8669 if vca_type
8670 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8671 else "helm-charts",
8672 vca_name,
8673 )
8674 else:
8675 artifact_path = "{}/Scripts/{}/{}/".format(
8676 base_folder["folder"],
8677 "charms"
8678 if vca_type
8679 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8680 else "helm-charts",
8681 vca_name,
8682 )
8683
8684 self.logger.debug("Artifact path > {}".format(artifact_path))
8685
8686 # get initial_config_primitive_list that applies to this element
8687 initial_config_primitive_list = config_descriptor.get(
8688 "initial-config-primitive"
8689 )
8690
8691 self.logger.debug(
8692 "Initial config primitive list > {}".format(
8693 initial_config_primitive_list
8694 )
8695 )
8696
8697 # add config if not present for NS charm
8698 ee_descriptor_id = ee_config_descriptor.get("id")
8699 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8700 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8701 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8702 )
8703
8704 self.logger.debug(
8705 "Initial config primitive list #2 > {}".format(
8706 initial_config_primitive_list
8707 )
8708 )
8709 # n2vc_redesign STEP 3.1
8710 # find old ee_id if exists
8711 ee_id = vca_deployed.get("ee_id")
8712
8713 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8714 # create or register execution environment in VCA. Only for native charms when healing
8715 if vca_type == "native_charm":
8716 step = "Waiting to VM being up and getting IP address"
8717 self.logger.debug(logging_text + step)
8718 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8719 logging_text,
8720 nsr_id,
8721 vnfr_id,
8722 vdu_id,
8723 vdu_index,
8724 user=None,
8725 pub_key=None,
8726 )
8727 credentials = {"hostname": rw_mgmt_ip}
8728 # get username
8729 username = deep_get(
8730 config_descriptor, ("config-access", "ssh-access", "default-user")
8731 )
8732 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8733 # merged. Meanwhile let's get username from initial-config-primitive
8734 if not username and initial_config_primitive_list:
8735 for config_primitive in initial_config_primitive_list:
8736 for param in config_primitive.get("parameter", ()):
8737 if param["name"] == "ssh-username":
8738 username = param["value"]
8739 break
8740 if not username:
8741 raise LcmException(
8742 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8743 "'config-access.ssh-access.default-user'"
8744 )
8745 credentials["username"] = username
8746
8747 # n2vc_redesign STEP 3.2
8748 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8749 self._write_configuration_status(
8750 nsr_id=nsr_id,
8751 vca_index=vca_index,
8752 status="REGISTERING",
8753 element_under_configuration=element_under_configuration,
8754 element_type=element_type,
8755 )
8756
8757 step = "register execution environment {}".format(credentials)
8758 self.logger.debug(logging_text + step)
8759 ee_id = await self.vca_map[vca_type].register_execution_environment(
8760 credentials=credentials,
8761 namespace=namespace,
8762 db_dict=db_dict,
8763 vca_id=vca_id,
8764 )
8765
8766 # update ee_id en db
8767 db_dict_ee_id = {
8768 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8769 }
8770 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8771
8772 # for compatibility with MON/POL modules, the need model and application name at database
8773 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8774 # Not sure if this need to be done when healing
8775 """
8776 ee_id_parts = ee_id.split(".")
8777 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8778 if len(ee_id_parts) >= 2:
8779 model_name = ee_id_parts[0]
8780 application_name = ee_id_parts[1]
8781 db_nsr_update[db_update_entry + "model"] = model_name
8782 db_nsr_update[db_update_entry + "application"] = application_name
8783 """
8784
8785 # n2vc_redesign STEP 3.3
8786 # Install configuration software. Only for native charms.
8787 step = "Install configuration Software"
8788
8789 self._write_configuration_status(
8790 nsr_id=nsr_id,
8791 vca_index=vca_index,
8792 status="INSTALLING SW",
8793 element_under_configuration=element_under_configuration,
8794 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008795 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008796 other_update=None,
8797 )
8798
8799 # TODO check if already done
8800 self.logger.debug(logging_text + step)
8801 config = None
8802 if vca_type == "native_charm":
8803 config_primitive = next(
8804 (p for p in initial_config_primitive_list if p["name"] == "config"),
8805 None,
8806 )
8807 if config_primitive:
8808 config = self._map_primitive_params(
8809 config_primitive, {}, deploy_params
8810 )
8811 await self.vca_map[vca_type].install_configuration_sw(
8812 ee_id=ee_id,
8813 artifact_path=artifact_path,
8814 db_dict=db_dict,
8815 config=config,
8816 num_units=1,
8817 vca_id=vca_id,
8818 vca_type=vca_type,
8819 )
8820
8821 # write in db flag of configuration_sw already installed
8822 self.update_db_2(
8823 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8824 )
8825
8826 # Not sure if this need to be done when healing
8827 """
8828 # add relations for this VCA (wait for other peers related with this VCA)
8829 await self._add_vca_relations(
8830 logging_text=logging_text,
8831 nsr_id=nsr_id,
8832 vca_type=vca_type,
8833 vca_index=vca_index,
8834 )
8835 """
8836
8837 # if SSH access is required, then get execution environment SSH public
8838 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00008839 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008840 pub_key = None
8841 user = None
8842 # self.logger.debug("get ssh key block")
8843 if deep_get(
8844 config_descriptor, ("config-access", "ssh-access", "required")
8845 ):
8846 # self.logger.debug("ssh key needed")
8847 # Needed to inject a ssh key
8848 user = deep_get(
8849 config_descriptor,
8850 ("config-access", "ssh-access", "default-user"),
8851 )
8852 step = "Install configuration Software, getting public ssh key"
8853 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8854 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8855 )
8856
8857 step = "Insert public key into VM user={} ssh_key={}".format(
8858 user, pub_key
8859 )
8860 else:
8861 # self.logger.debug("no need to get ssh key")
8862 step = "Waiting to VM being up and getting IP address"
8863 self.logger.debug(logging_text + step)
8864
8865 # n2vc_redesign STEP 5.1
8866 # wait for RO (ip-address) Insert pub_key into VM
8867 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008868 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008869 if vnfr_id:
8870 if kdu_name:
8871 rw_mgmt_ip = await self.wait_kdu_up(
8872 logging_text, nsr_id, vnfr_id, kdu_name
8873 )
8874 else:
8875 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8876 logging_text,
8877 nsr_id,
8878 vnfr_id,
8879 vdu_id,
8880 vdu_index,
8881 user=user,
8882 pub_key=pub_key,
8883 )
8884 else:
8885 rw_mgmt_ip = None # This is for a NS configuration
8886
8887 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8888
8889 # store rw_mgmt_ip in deploy params for later replacement
8890 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8891
8892 # Day1 operations.
8893 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008894 runDay1 = deploy_params.get("run-day1", False)
8895 self.logger.debug(
8896 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8897 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008898 if runDay1:
8899 # n2vc_redesign STEP 6 Execute initial config primitive
8900 step = "execute initial config primitive"
8901
8902 # wait for dependent primitives execution (NS -> VNF -> VDU)
8903 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008904 await self._wait_dependent_n2vc(
8905 nsr_id, vca_deployed_list, vca_index
8906 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008907
8908 # stage, in function of element type: vdu, kdu, vnf or ns
8909 my_vca = vca_deployed_list[vca_index]
8910 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8911 # VDU or KDU
8912 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8913 elif my_vca.get("member-vnf-index"):
8914 # VNF
8915 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8916 else:
8917 # NS
8918 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8919
8920 self._write_configuration_status(
8921 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8922 )
8923
8924 self._write_op_status(op_id=nslcmop_id, stage=stage)
8925
8926 check_if_terminated_needed = True
8927 for initial_config_primitive in initial_config_primitive_list:
8928 # adding information on the vca_deployed if it is a NS execution environment
8929 if not vca_deployed["member-vnf-index"]:
8930 deploy_params["ns_config_info"] = json.dumps(
8931 self._get_ns_config_info(nsr_id)
8932 )
8933 # TODO check if already done
8934 primitive_params_ = self._map_primitive_params(
8935 initial_config_primitive, {}, deploy_params
8936 )
8937
8938 step = "execute primitive '{}' params '{}'".format(
8939 initial_config_primitive["name"], primitive_params_
8940 )
8941 self.logger.debug(logging_text + step)
8942 await self.vca_map[vca_type].exec_primitive(
8943 ee_id=ee_id,
8944 primitive_name=initial_config_primitive["name"],
8945 params_dict=primitive_params_,
8946 db_dict=db_dict,
8947 vca_id=vca_id,
8948 vca_type=vca_type,
8949 )
8950 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8951 if check_if_terminated_needed:
8952 if config_descriptor.get("terminate-config-primitive"):
8953 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008954 "nsrs",
8955 nsr_id,
8956 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008957 )
8958 check_if_terminated_needed = False
8959
8960 # TODO register in database that primitive is done
8961
8962 # STEP 7 Configure metrics
8963 # Not sure if this need to be done when healing
8964 """
8965 if vca_type == "helm" or vca_type == "helm-v3":
8966 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8967 ee_id=ee_id,
8968 artifact_path=artifact_path,
8969 ee_config_descriptor=ee_config_descriptor,
8970 vnfr_id=vnfr_id,
8971 nsr_id=nsr_id,
8972 target_ip=rw_mgmt_ip,
8973 )
8974 if prometheus_jobs:
8975 self.update_db_2(
8976 "nsrs",
8977 nsr_id,
8978 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8979 )
8980
8981 for job in prometheus_jobs:
8982 self.db.set_one(
8983 "prometheus_jobs",
8984 {"job_name": job["job_name"]},
8985 job,
8986 upsert=True,
8987 fail_on_empty=False,
8988 )
8989
8990 """
8991 step = "instantiated at VCA"
8992 self.logger.debug(logging_text + step)
8993
8994 self._write_configuration_status(
8995 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8996 )
8997
8998 except Exception as e: # TODO not use Exception but N2VC exception
8999 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
9000 if not isinstance(
9001 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
9002 ):
9003 self.logger.error(
9004 "Exception while {} : {}".format(step, e), exc_info=True
9005 )
9006 self._write_configuration_status(
9007 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
9008 )
9009 raise LcmException("{} {}".format(step, e)) from e
9010
9011 async def _wait_heal_ro(
9012 self,
9013 nsr_id,
9014 timeout=600,
9015 ):
9016 start_time = time()
9017 while time() <= start_time + timeout:
9018 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009019 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9020 "operational-status"
9021 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009022 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9023 if operational_status_ro != "healing":
9024 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009025 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009026 else: # timeout_ns_deploy
9027 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309028
9029 async def vertical_scale(self, nsr_id, nslcmop_id):
9030 """
9031 Vertical Scale the VDUs in a NS
9032
9033 :param: nsr_id: NS Instance ID
9034 :param: nslcmop_id: nslcmop ID of migrate
9035
9036 """
govindarajul4ff4b512022-05-02 20:02:41 +05309037 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05309038 self.logger.info(logging_text + "Enter")
9039 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05309040 # get all needed from database
9041 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05309042 db_nsr_update = {}
9043 target = {}
9044 exc = None
9045 # in case of error, indicates what part of scale was failed to put nsr at error status
9046 start_deploy = time()
9047
9048 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05309049 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9050 operationParams = db_nslcmop.get("operationParams")
9051 vertical_scale_data = operationParams["verticalScaleVnf"]
9052 vnfd_id = vertical_scale_data["vnfdId"]
9053 count_index = vertical_scale_data["countIndex"]
9054 vdu_id_ref = vertical_scale_data["vduId"]
9055 vnfr_id = vertical_scale_data["vnfInstanceId"]
9056 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9057 db_flavor = db_nsr.get("flavor")
9058 db_flavor_index = str(len(db_flavor))
9059
9060 def set_flavor_refrence_to_vdur(diff=0):
9061 """
9062 Utility function to add and remove the
9063 ref to new ns-flavor-id to vdurs
9064 :param: diff: default 0
9065 """
9066 q_filter = {}
9067 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9068 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9069 if (
9070 vdur.get("count-index") == count_index
9071 and vdur.get("vdu-id-ref") == vdu_id_ref
9072 ):
9073 filter_text = {
9074 "_id": vnfr_id,
9075 "vdur.count-index": count_index,
9076 "vdur.vdu-id-ref": vdu_id_ref,
9077 }
9078 q_filter.update(filter_text)
9079 db_update = {}
9080 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9081 int(db_flavor_index) - diff
9082 )
9083 self.db.set_one(
9084 "vnfrs",
9085 q_filter=q_filter,
9086 update_dict=db_update,
9087 fail_on_empty=True,
9088 )
9089
govindarajul4ff4b512022-05-02 20:02:41 +05309090 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309091 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009092 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309093
9094 self._write_ns_status(
9095 nsr_id=nsr_id,
9096 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309097 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009098 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309099 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309100 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009101 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309102 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009103 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309104 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9105 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9106 virtual_compute = vnfd["virtual-compute-desc"][0]
9107 virtual_memory = round(
9108 float(virtual_compute["virtual-memory"]["size"]) * 1024
9109 )
9110 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9111 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009112 flavor_dict_update = {
9113 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309114 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009115 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309116 "storage-gb": str(virtual_storage),
9117 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009118 }
9119 db_flavor.append(flavor_dict_update)
9120 db_update = {}
9121 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309122 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009123 "_id": nsr_id,
9124 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309125 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009126 self.db.set_one(
9127 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309128 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009129 update_dict=db_update,
9130 fail_on_empty=True,
9131 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309132 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309133 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309134 new_operationParams = {
9135 "lcmOperationType": "verticalscale",
9136 "verticalScale": "CHANGE_VNFFLAVOR",
9137 "nsInstanceId": nsr_id,
9138 "changeVnfFlavorData": {
9139 "vnfInstanceId": vnfr_id,
9140 "additionalParams": {
9141 "vduid": vdu_id_ref,
9142 "vduCountIndex": count_index,
9143 "virtualMemory": virtual_memory,
9144 "numVirtualCpu": int(virtual_cpu),
9145 "sizeOfStorage": int(virtual_storage),
9146 },
9147 },
9148 }
9149 target.update(new_operationParams)
9150
9151 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9152 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9153 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309154 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309155 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309156 action_id = desc["action_id"]
9157 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009158 nsr_id,
9159 action_id,
9160 nslcmop_id,
9161 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009162 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009163 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309164 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009165 except (
9166 NgRoException,
9167 ROclient.ROClientException,
9168 DbException,
9169 LcmException,
9170 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309171 self.logger.error("Exit Exception {}".format(e))
9172 exc = e
9173 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309174 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309175 exc = "Operation was cancelled"
9176 except Exception as e:
9177 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009178 self.logger.critical(
9179 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9180 )
govindarajul4ff4b512022-05-02 20:02:41 +05309181 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309182 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009183 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309184 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009185 )
9186 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309187 "nsrs",
9188 {"_id": nsr_id},
9189 None,
9190 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009191 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309192 set_flavor_refrence_to_vdur(diff=1)
9193 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9194 else:
9195 return "COMPLETED", "Done"