blob: b2c1c084865cf01ed7eea581e280e7926b55d2c3 [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,
Isabel Lloret23aea8e2025-04-25 11:27:11 +0200220 "console": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200221 }
222
tierno2357f4e2020-10-19 16:38:59 +0000223 @staticmethod
224 def increment_ip_mac(ip_mac, vm_index=1):
225 if not isinstance(ip_mac, str):
226 return ip_mac
227 try:
rahul72d90d92023-08-30 14:48:01 +0530228 next_ipv6 = None
229 next_ipv4 = None
230 dual_ip = ip_mac.split(";")
231 if len(dual_ip) == 2:
232 for ip in dual_ip:
233 if ipaddress.ip_address(ip).version == 6:
234 ipv6 = ipaddress.IPv6Address(ip)
235 next_ipv6 = str(ipaddress.IPv6Address(int(ipv6) + 1))
236 elif ipaddress.ip_address(ip).version == 4:
237 ipv4 = ipaddress.IPv4Address(ip)
238 next_ipv4 = str(ipaddress.IPv4Address(int(ipv4) + 1))
239 return [next_ipv4, next_ipv6]
tierno2357f4e2020-10-19 16:38:59 +0000240 # try with ipv4 look for last dot
241 i = ip_mac.rfind(".")
242 if i > 0:
243 i += 1
244 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
245 # try with ipv6 or mac look for last colon. Operate in hex
246 i = ip_mac.rfind(":")
247 if i > 0:
248 i += 1
249 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100250 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
251 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
252 )
tierno2357f4e2020-10-19 16:38:59 +0000253 except Exception:
254 pass
255 return None
256
David Garciac1fe90a2021-03-31 19:12:02 +0200257 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000258 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100259 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000260 path = path[:-1]
261
quilesj3655ae02019-12-12 16:08:35 +0000262 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
263 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000264 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100265 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000266
267 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100268 nsr = self.db.get_one(table="nsrs", q_filter=filter)
269 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000270
3697083243632024-06-07 05:44:08 +0000271 # First, we need to verify if the current vcaStatus is null, because if that is the case,
272 # MongoDB will not be able to create the fields used within the update key in the database
273 if not nsr.get("vcaStatus"):
274 # Write an empty dictionary to the vcaStatus field, it its value is null
275 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
276
277 # Get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100278 status_dict = await self.n2vc.get_status(
279 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
280 )
quilesj3655ae02019-12-12 16:08:35 +0000281
3697083243632024-06-07 05:44:08 +0000282 # Update the vcaStatus
283 db_key = f"vcaStatus.{nsr_id}.VNF"
quilesj3655ae02019-12-12 16:08:35 +0000284 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000285
286 db_dict[db_key] = status_dict[nsr_id]
287 await self.n2vc.update_vca_status(db_dict[db_key], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000288
289 # update configurationStatus for this VCA
290 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100291 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000292
garciadeblas5697b8b2021-03-24 09:17:02 +0100293 vca_list = deep_get(
294 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
295 )
296 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000297
garciadeblas5697b8b2021-03-24 09:17:02 +0100298 configuration_status_list = nsr.get("configurationStatus")
299 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000300
garciadeblas5697b8b2021-03-24 09:17:02 +0100301 if config_status == "BROKEN" and vca_status != "failed":
302 db_dict["configurationStatus"][vca_index] = "READY"
303 elif config_status != "BROKEN" and vca_status == "failed":
304 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000305 except Exception as e:
306 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100307 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000308
309 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
310 # if nsState = 'DEGRADED' check if all is OK
311 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100312 if current_ns_status in ("READY", "DEGRADED"):
313 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000314 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100315 if status_dict.get("machines"):
316 for machine_id in status_dict.get("machines"):
317 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000318 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100319 if machine.get("agent-status"):
320 s = machine.get("agent-status").get("status")
321 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000322 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100323 error_description += (
324 "machine {} agent-status={} ; ".format(
325 machine_id, s
326 )
327 )
quilesj3655ae02019-12-12 16:08:35 +0000328 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100329 if machine.get("instance-status"):
330 s = machine.get("instance-status").get("status")
331 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000332 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100333 error_description += (
334 "machine {} instance-status={} ; ".format(
335 machine_id, s
336 )
337 )
quilesj3655ae02019-12-12 16:08:35 +0000338 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100339 if status_dict.get("applications"):
340 for app_id in status_dict.get("applications"):
341 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000342 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100343 if app.get("status"):
344 s = app.get("status").get("status")
345 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000346 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100347 error_description += (
348 "application {} status={} ; ".format(app_id, s)
349 )
quilesj3655ae02019-12-12 16:08:35 +0000350
351 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100352 db_dict["errorDescription"] = error_description
353 if current_ns_status == "READY" and is_degraded:
354 db_dict["nsState"] = "DEGRADED"
355 if current_ns_status == "DEGRADED" and not is_degraded:
356 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000357
358 # write to database
359 self.update_db_2("nsrs", nsr_id, db_dict)
360
tierno51183952020-04-03 15:48:18 +0000361 except (asyncio.CancelledError, asyncio.TimeoutError):
362 raise
quilesj3655ae02019-12-12 16:08:35 +0000363 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100364 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200365
garciadeblas5697b8b2021-03-24 09:17:02 +0100366 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100367 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100368 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530369 """
370 Updating vca status in NSR record
371 :param cluster_uuid: UUID of a k8s cluster
372 :param kdu_instance: The unique name of the KDU instance
373 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100374 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530375 :return: none
376 """
377
378 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
379 # .format(cluster_uuid, kdu_instance, filter))
380
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100381 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530382 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100383 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
384 cluster_uuid=cluster_uuid,
385 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200386 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100387 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200388 vca_id=vca_id,
389 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100390
3697083243632024-06-07 05:44:08 +0000391 # First, we need to verify if the current vcaStatus is null, because if that is the case,
392 # MongoDB will not be able to create the fields used within the update key in the database
393 nsr = self.db.get_one(table="nsrs", q_filter=filter)
394 if not nsr.get("vcaStatus"):
395 # Write an empty dictionary to the vcaStatus field, it its value is null
396 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
397
398 # Update the vcaStatus
399 db_key = f"vcaStatus.{nsr_id}.KNF"
ksaikiranr656b6dd2021-02-19 10:25:18 +0530400 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000401
402 db_dict[db_key] = vca_status
403
404 if cluster_type in ("juju-bundle", "juju"):
405 # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA
406 # status in a similar way between Juju Bundles and Helm Charts on this side
407 await self.k8sclusterjuju.update_vca_status(
408 db_dict[db_key],
409 kdu_instance,
410 vca_id=vca_id,
411 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530412
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100413 self.logger.debug(
414 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200415 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530416
417 # write to database
418 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530419 except (asyncio.CancelledError, asyncio.TimeoutError):
420 raise
421 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100422 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530423
tierno72ef84f2020-10-06 08:22:07 +0000424 @staticmethod
425 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
426 try:
garciadeblasef91e082022-08-02 15:12:18 +0200427 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000428 undefined=StrictUndefined,
429 autoescape=select_autoescape(default_for_string=True, default=True),
430 )
tierno72ef84f2020-10-06 08:22:07 +0000431 template = env.from_string(cloud_init_text)
432 return template.render(additional_params or {})
433 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100434 raise LcmException(
435 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
436 "file, must be provided in the instantiation parameters inside the "
437 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
438 )
tierno72ef84f2020-10-06 08:22:07 +0000439 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100440 raise LcmException(
441 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
442 vnfd_id, vdu_id, e
443 )
444 )
tierno72ef84f2020-10-06 08:22:07 +0000445
bravof922c4172020-11-24 21:21:43 -0300446 def _get_vdu_cloud_init_content(self, vdu, vnfd):
447 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000448 try:
tierno72ef84f2020-10-06 08:22:07 +0000449 if vdu.get("cloud-init-file"):
450 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300451 if base_folder["pkg-dir"]:
452 cloud_init_file = "{}/{}/cloud_init/{}".format(
453 base_folder["folder"],
454 base_folder["pkg-dir"],
455 vdu["cloud-init-file"],
456 )
457 else:
458 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
459 base_folder["folder"],
460 vdu["cloud-init-file"],
461 )
tierno72ef84f2020-10-06 08:22:07 +0000462 with self.fs.file_open(cloud_init_file, "r") as ci_file:
463 cloud_init_content = ci_file.read()
464 elif vdu.get("cloud-init"):
465 cloud_init_content = vdu["cloud-init"]
466
467 return cloud_init_content
468 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100469 raise LcmException(
470 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
471 vnfd["id"], vdu["id"], cloud_init_file, e
472 )
473 )
tierno72ef84f2020-10-06 08:22:07 +0000474
tierno72ef84f2020-10-06 08:22:07 +0000475 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100476 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300477 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100478 )
tierno72ef84f2020-10-06 08:22:07 +0000479 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300480 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000481
tierno2357f4e2020-10-19 16:38:59 +0000482 @staticmethod
483 def ip_profile_2_RO(ip_profile):
484 RO_ip_profile = deepcopy(ip_profile)
485 if "dns-server" in RO_ip_profile:
486 if isinstance(RO_ip_profile["dns-server"], list):
487 RO_ip_profile["dns-address"] = []
488 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100489 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000490 else:
491 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
492 if RO_ip_profile.get("ip-version") == "ipv4":
493 RO_ip_profile["ip-version"] = "IPv4"
494 if RO_ip_profile.get("ip-version") == "ipv6":
495 RO_ip_profile["ip-version"] = "IPv6"
496 if "dhcp-params" in RO_ip_profile:
497 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
498 return RO_ip_profile
499
tierno2357f4e2020-10-19 16:38:59 +0000500 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000501 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000502 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000503 db_update = {"_admin.modified": time()}
504 if vdu_create:
505 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100506 vdur = next(
507 (
508 vdur
509 for vdur in reversed(db_vnfr["vdur"])
510 if vdur["vdu-id-ref"] == vdu_id
511 ),
512 None,
513 )
tierno2357f4e2020-10-19 16:38:59 +0000514 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000515 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300516 self.logger.debug(
517 "No vdur in the database. Using the vdur-template to scale"
518 )
vegall8d625f12022-03-22 16:23:30 +0000519 vdur_template = db_vnfr.get("vdur-template")
520 if not vdur_template:
521 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300522 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
523 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000524 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100525 )
vegall8d625f12022-03-22 16:23:30 +0000526 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300527 # Delete a template from the database after using it
528 self.db.set_one(
529 "vnfrs",
530 {"_id": db_vnfr["_id"]},
531 None,
532 pull={"vdur-template": {"_id": vdur["_id"]}},
533 )
tierno2357f4e2020-10-19 16:38:59 +0000534 for count in range(vdu_count):
535 vdur_copy = deepcopy(vdur)
536 vdur_copy["status"] = "BUILD"
537 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100538 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000539 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000540 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100541 vdur_copy["id"] = "{}-{}".format(
542 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
543 )
tierno2357f4e2020-10-19 16:38:59 +0000544 vdur_copy.pop("vim_info", None)
545 for iface in vdur_copy["interfaces"]:
546 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100547 iface["ip-address"] = self.increment_ip_mac(
548 iface["ip-address"], count + 1
549 )
tierno2357f4e2020-10-19 16:38:59 +0000550 else:
551 iface.pop("ip-address", None)
552 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100553 iface["mac-address"] = self.increment_ip_mac(
554 iface["mac-address"], count + 1
555 )
tierno2357f4e2020-10-19 16:38:59 +0000556 else:
557 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000558 if db_vnfr["vdur"]:
559 iface.pop(
560 "mgmt_vnf", None
561 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000562 db_vdu_push_list.append(vdur_copy)
563 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200564 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000565 if len(db_vnfr["vdur"]) == 1:
566 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300567 self.logger.debug(
568 "Scaling to 0 !, creating the template with the last vdur"
569 )
vegall8d625f12022-03-22 16:23:30 +0000570 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000571 for vdu_id, vdu_count in vdu_delete.items():
572 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100573 indexes_to_delete = [
574 iv[0]
575 for iv in enumerate(db_vnfr["vdur"])
576 if iv[1]["vdu-id-ref"] == vdu_id
577 ]
578 db_update.update(
579 {
580 "vdur.{}.status".format(i): "DELETING"
581 for i in indexes_to_delete[-vdu_count:]
582 }
583 )
tierno2357f4e2020-10-19 16:38:59 +0000584 else:
585 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100586 vdus_to_delete = [
587 v
588 for v in reversed(db_vnfr["vdur"])
589 if v["vdu-id-ref"] == vdu_id
590 ]
tierno2357f4e2020-10-19 16:38:59 +0000591 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100592 self.db.set_one(
593 "vnfrs",
594 {"_id": db_vnfr["_id"]},
595 None,
596 pull={"vdur": {"_id": vdu["_id"]}},
597 )
vegall8d625f12022-03-22 16:23:30 +0000598 db_push = {}
599 if db_vdu_push_list:
600 db_push["vdur"] = db_vdu_push_list
601 if template_vdur:
602 db_push["vdur-template"] = template_vdur
603 if not db_push:
604 db_push = None
605 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000606 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
607 # modify passed dictionary db_vnfr
608 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
609 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200610
tiernof578e552018-11-08 19:07:20 +0100611 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
612 """
613 Updates database nsr with the RO info for the created vld
614 :param ns_update_nsr: dictionary to be filled with the updated info
615 :param db_nsr: content of db_nsr. This is also modified
616 :param nsr_desc_RO: nsr descriptor from RO
617 :return: Nothing, LcmException is raised on errors
618 """
619
620 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
621 for net_RO in get_iterable(nsr_desc_RO, "nets"):
622 if vld["id"] != net_RO.get("ns_net_osm_id"):
623 continue
624 vld["vim-id"] = net_RO.get("vim_net_id")
625 vld["name"] = net_RO.get("vim_name")
626 vld["status"] = net_RO.get("status")
627 vld["status-detailed"] = net_RO.get("error_msg")
628 ns_update_nsr["vld.{}".format(vld_index)] = vld
629 break
630 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100631 raise LcmException(
632 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
633 )
tiernof578e552018-11-08 19:07:20 +0100634
tiernoe876f672020-02-13 14:34:48 +0000635 def set_vnfr_at_error(self, db_vnfrs, error_text):
636 try:
637 for db_vnfr in db_vnfrs.values():
638 vnfr_update = {"status": "ERROR"}
639 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
640 if "status" not in vdur:
641 vdur["status"] = "ERROR"
642 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
643 if error_text:
644 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100645 vnfr_update[
646 "vdur.{}.status-detailed".format(vdu_index)
647 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000648 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
649 except DbException as e:
650 self.logger.error("Cannot update vnf. {}".format(e))
651
tierno5ee02052019-12-05 19:55:02 +0000652 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000653 """
654 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000655 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000656 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
657 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
658 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
659 """
tierno5ee02052019-12-05 19:55:02 +0000660 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
661 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000662 mapping = {}
663 ns_config_info = {"osm-config-mapping": mapping}
664 for vca in vca_deployed_list:
665 if not vca["member-vnf-index"]:
666 continue
667 if not vca["vdu_id"]:
668 mapping[vca["member-vnf-index"]] = vca["application"]
669 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100670 mapping[
671 "{}.{}.{}".format(
672 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
673 )
674 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000675 return ns_config_info
676
garciadeblas5697b8b2021-03-24 09:17:02 +0100677 async def _instantiate_ng_ro(
678 self,
679 logging_text,
680 nsr_id,
681 nsd,
682 db_nsr,
683 db_nslcmop,
684 db_vnfrs,
685 db_vnfds,
686 n2vc_key_list,
687 stage,
688 start_deploy,
689 timeout_ns_deploy,
690 ):
tierno2357f4e2020-10-19 16:38:59 +0000691 db_vims = {}
692
693 def get_vim_account(vim_account_id):
Anirudh Guptac2be9492025-05-13 05:53:38 +0000694 # nonlocal db_vims
tierno2357f4e2020-10-19 16:38:59 +0000695 if vim_account_id in db_vims:
696 return db_vims[vim_account_id]
697 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
698 db_vims[vim_account_id] = db_vim
699 return db_vim
700
701 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100702 def parse_vld_instantiation_params(
703 target_vim, target_vld, vld_params, target_sdn
704 ):
tierno2357f4e2020-10-19 16:38:59 +0000705 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500706 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
707 vld_params["ip-profile"]
708 )
tierno2357f4e2020-10-19 16:38:59 +0000709 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100710 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
711 "provider-network"
712 ]
tierno2357f4e2020-10-19 16:38:59 +0000713 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100714 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
715 "provider-network"
716 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000717
718 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
719 # if wim_account_id is specified in vld_params, validate if it is feasible.
720 wim_account_id, db_wim = select_feasible_wim_account(
721 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
722 )
723
724 if wim_account_id:
725 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
726 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
727 # update vld_params with correct WIM account Id
728 vld_params["wimAccountId"] = wim_account_id
729
730 target_wim = "wim:{}".format(wim_account_id)
731 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
732 sdn_ports = get_sdn_ports(vld_params, db_wim)
733 if len(sdn_ports) > 0:
734 target_vld["vim_info"][target_wim] = target_wim_attrs
735 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
736
737 self.logger.debug(
738 "Target VLD with WIM data: {:s}".format(str(target_vld))
739 )
740
tierno2357f4e2020-10-19 16:38:59 +0000741 for param in ("vim-network-name", "vim-network-id"):
742 if vld_params.get(param):
743 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300744 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300745 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100746 populate_dict(
747 target_vld["vim_info"],
748 (other_target_vim, param.replace("-", "_")),
749 vim_net,
750 )
tierno2357f4e2020-10-19 16:38:59 +0000751 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100752 target_vld["vim_info"][target_vim][
753 param.replace("-", "_")
754 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300755 if vld_params.get("common_id"):
756 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000757
aticig15db6142022-01-24 12:51:26 +0300758 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
759 def update_ns_vld_target(target, ns_params):
760 for vnf_params in ns_params.get("vnf", ()):
761 if vnf_params.get("vimAccountId"):
762 target_vnf = next(
763 (
764 vnfr
765 for vnfr in db_vnfrs.values()
766 if vnf_params["member-vnf-index"]
767 == vnfr["member-vnf-index-ref"]
768 ),
769 None,
770 )
771 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100772 if not vdur:
Pedro Escaleira556f5c72023-04-20 15:22:16 +0100773 continue
aticig15db6142022-01-24 12:51:26 +0300774 for a_index, a_vld in enumerate(target["ns"]["vld"]):
775 target_vld = find_in_list(
776 get_iterable(vdur, "interfaces"),
777 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
778 )
aticig84bd9a72022-06-14 03:01:36 +0300779
780 vld_params = find_in_list(
781 get_iterable(ns_params, "vld"),
782 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
783 )
aticig15db6142022-01-24 12:51:26 +0300784 if target_vld:
785 if vnf_params.get("vimAccountId") not in a_vld.get(
786 "vim_info", {}
787 ):
aticig84bd9a72022-06-14 03:01:36 +0300788 target_vim_network_list = [
789 v for _, v in a_vld.get("vim_info").items()
790 ]
791 target_vim_network_name = next(
792 (
793 item.get("vim_network_name", "")
794 for item in target_vim_network_list
795 ),
796 "",
797 )
798
aticig15db6142022-01-24 12:51:26 +0300799 target["ns"]["vld"][a_index].get("vim_info").update(
800 {
801 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300802 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300803 }
804 }
805 )
806
aticig84bd9a72022-06-14 03:01:36 +0300807 if vld_params:
808 for param in ("vim-network-name", "vim-network-id"):
809 if vld_params.get(param) and isinstance(
810 vld_params[param], dict
811 ):
812 for vim, vim_net in vld_params[
813 param
814 ].items():
815 other_target_vim = "vim:" + vim
816 populate_dict(
817 target["ns"]["vld"][a_index].get(
818 "vim_info"
819 ),
820 (
821 other_target_vim,
822 param.replace("-", "_"),
823 ),
824 vim_net,
825 )
826
tierno69f0d382020-05-07 13:08:09 +0000827 nslcmop_id = db_nslcmop["_id"]
828 target = {
829 "name": db_nsr["name"],
830 "ns": {"vld": []},
831 "vnf": [],
832 "image": deepcopy(db_nsr["image"]),
833 "flavor": deepcopy(db_nsr["flavor"]),
834 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000835 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000836 }
837 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000838 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000839 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000840 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000841 if db_nsr.get("shared-volumes"):
842 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
843 for shared_volumes in target["shared-volumes"]:
844 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100845 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100846 target["affinity-or-anti-affinity-group"] = deepcopy(
847 db_nsr["affinity-or-anti-affinity-group"]
848 )
849 for affinity_or_anti_affinity_group in target[
850 "affinity-or-anti-affinity-group"
851 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100852 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000853
tierno2357f4e2020-10-19 16:38:59 +0000854 if db_nslcmop.get("lcmOperationType") != "instantiate":
855 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100856 db_nslcmop_instantiate = self.db.get_list(
857 "nslcmops",
858 {
859 "nsInstanceId": db_nslcmop["nsInstanceId"],
860 "lcmOperationType": "instantiate",
861 },
862 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000863 ns_params = db_nslcmop_instantiate.get("operationParams")
864 else:
865 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300866 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
867 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000868
869 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000870 for vld_index, vld in enumerate(db_nsr.get("vld")):
871 target_vim = "vim:{}".format(ns_params["vimAccountId"])
872 target_vld = {
873 "id": vld["id"],
874 "name": vld["name"],
875 "mgmt-network": vld.get("mgmt-network", False),
876 "type": vld.get("type"),
877 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300878 target_vim: {
879 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100880 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -0300881 }
garciadeblas5697b8b2021-03-24 09:17:02 +0100882 },
tierno2357f4e2020-10-19 16:38:59 +0000883 }
884 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000885 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +0000886 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +0300887 if vim_config := db_vim.get("config"):
888 if sdnc_id := vim_config.get("sdn-controller"):
889 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
890 target_sdn = "sdn:{}".format(sdnc_id)
891 target_vld["vim_info"][target_sdn] = {
892 "sdn": True,
893 "target_vim": target_vim,
894 "vlds": [sdn_vld],
895 "type": vld.get("type"),
896 }
tierno2357f4e2020-10-19 16:38:59 +0000897
bravof922c4172020-11-24 21:21:43 -0300898 nsd_vnf_profiles = get_vnf_profiles(nsd)
899 for nsd_vnf_profile in nsd_vnf_profiles:
900 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
901 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100902 cp2target[
903 "member_vnf:{}.{}".format(
904 cp["constituent-cpd-id"][0][
905 "constituent-base-element-id"
906 ],
907 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
908 )
909 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000910
911 # check at nsd descriptor, if there is an ip-profile
912 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +0000913 nsd_vlp = find_in_list(
914 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100915 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
916 == vld["id"],
917 )
918 if (
919 nsd_vlp
920 and nsd_vlp.get("virtual-link-protocol-data")
921 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
922 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500923 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100924 "l3-protocol-data"
925 ]
bravof922c4172020-11-24 21:21:43 -0300926
tierno2357f4e2020-10-19 16:38:59 +0000927 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +0100928 vld_instantiation_params = find_in_list(
929 get_iterable(ns_params, "vld"),
930 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
931 )
tierno2357f4e2020-10-19 16:38:59 +0000932 if vld_instantiation_params:
933 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300934 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000935 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +0300936 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
937 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -0300938
tierno69f0d382020-05-07 13:08:09 +0000939 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +0100940 vnfd = find_in_list(
941 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
942 )
943 vnf_params = find_in_list(
944 get_iterable(ns_params, "vnf"),
945 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
946 )
tierno69f0d382020-05-07 13:08:09 +0000947 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000948 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000949 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000950 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +0100951 vnf_cp = find_in_list(
952 vnfd.get("int-virtual-link-desc", ()),
953 lambda cpd: cpd.get("id") == vld["id"],
954 )
tierno69f0d382020-05-07 13:08:09 +0000955 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +0100956 ns_cp = "member_vnf:{}.{}".format(
957 vnfr["member-vnf-index-ref"], vnf_cp["id"]
958 )
tierno69f0d382020-05-07 13:08:09 +0000959 if cp2target.get(ns_cp):
960 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300961
garciadeblas5697b8b2021-03-24 09:17:02 +0100962 vld["vim_info"] = {
963 target_vim: {"vim_network_name": vld.get("vim-network-name")}
964 }
tierno2357f4e2020-10-19 16:38:59 +0000965 # check if this network needs SDN assist
966 target_sdn = None
967 if vld.get("pci-interfaces"):
968 db_vim = get_vim_account(vnfr["vim-account-id"])
969 sdnc_id = db_vim["config"].get("sdn-controller")
970 if sdnc_id:
971 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
972 target_sdn = "sdn:{}".format(sdnc_id)
973 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +0100974 "sdn": True,
975 "target_vim": target_vim,
976 "vlds": [sdn_vld],
977 "type": vld.get("type"),
978 }
tierno69f0d382020-05-07 13:08:09 +0000979
tierno2357f4e2020-10-19 16:38:59 +0000980 # check at vnfd descriptor, if there is an ip-profile
981 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300982 vnfd_vlp = find_in_list(
983 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100984 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -0300985 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100986 if (
987 vnfd_vlp
988 and vnfd_vlp.get("virtual-link-protocol-data")
989 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
990 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500991 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100992 "l3-protocol-data"
993 ]
tierno2357f4e2020-10-19 16:38:59 +0000994 # update vld_params with instantiation params
995 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +0100996 vld_instantiation_params = find_in_list(
997 get_iterable(vnf_params, "internal-vld"),
998 lambda i_vld: i_vld["name"] == vld["id"],
999 )
tierno2357f4e2020-10-19 16:38:59 +00001000 if vld_instantiation_params:
1001 vld_params.update(vld_instantiation_params)
1002 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1003
1004 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001005 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001006 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1007 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001008 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001009
bravof922c4172020-11-24 21:21:43 -03001010 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1011
1012 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001013 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1014 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001015 if (
1016 vdu_configuration
1017 and vdu_configuration.get("config-access")
1018 and vdu_configuration.get("config-access").get("ssh-access")
1019 ):
bravof922c4172020-11-24 21:21:43 -03001020 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001021 vdur["ssh-access-required"] = vdu_configuration[
1022 "config-access"
1023 ]["ssh-access"]["required"]
1024 elif (
1025 vnf_configuration
1026 and vnf_configuration.get("config-access")
1027 and vnf_configuration.get("config-access").get("ssh-access")
1028 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1029 ):
bravof922c4172020-11-24 21:21:43 -03001030 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001031 vdur["ssh-access-required"] = vnf_configuration[
1032 "config-access"
1033 ]["ssh-access"]["required"]
1034 elif ssh_keys_instantiation and find_in_list(
1035 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1036 ):
bravof922c4172020-11-24 21:21:43 -03001037 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001038
bravof922c4172020-11-24 21:21:43 -03001039 self.logger.debug("NS > vdur > {}".format(vdur))
1040
1041 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001042 # cloud-init
1043 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001044 vdur["cloud-init"] = "{}:file:{}".format(
1045 vnfd["_id"], vdud.get("cloud-init-file")
1046 )
tierno2357f4e2020-10-19 16:38:59 +00001047 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1048 if vdur["cloud-init"] not in target["cloud_init_content"]:
1049 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001050 if base_folder["pkg-dir"]:
1051 cloud_init_file = "{}/{}/cloud_init/{}".format(
1052 base_folder["folder"],
1053 base_folder["pkg-dir"],
1054 vdud.get("cloud-init-file"),
1055 )
1056 else:
1057 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1058 base_folder["folder"],
1059 vdud.get("cloud-init-file"),
1060 )
tierno2357f4e2020-10-19 16:38:59 +00001061 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001062 target["cloud_init_content"][
1063 vdur["cloud-init"]
1064 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001065 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001066 vdur["cloud-init"] = "{}:vdu:{}".format(
1067 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1068 )
tierno2357f4e2020-10-19 16:38:59 +00001069 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001070 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1071 "cloud-init"
1072 ]
tierno2357f4e2020-10-19 16:38:59 +00001073 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001074 deploy_params_vdu = self._format_additional_params(
1075 vdur.get("additionalParams") or {}
1076 )
1077 deploy_params_vdu["OSM"] = get_osm_params(
1078 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1079 )
jegane74fa992024-04-01 10:54:53 +00001080 for vdu, value in deploy_params_vdu["OSM"]["vdu"].items():
1081 for interface, address in value["interfaces"].items():
1082 if address.get("mac_address"):
1083 address.pop("mac_address")
tierno2357f4e2020-10-19 16:38:59 +00001084 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001085
1086 # flavor
1087 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001088 if target_vim not in ns_flavor["vim_info"]:
1089 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001090
1091 # deal with images
1092 # in case alternative images are provided we must check if they should be applied
1093 # for the vim_type, modify the vim_type taking into account
1094 ns_image_id = int(vdur["ns-image-id"])
1095 if vdur.get("alt-image-ids"):
1096 db_vim = get_vim_account(vnfr["vim-account-id"])
1097 vim_type = db_vim["vim_type"]
1098 for alt_image_id in vdur.get("alt-image-ids"):
1099 ns_alt_image = target["image"][int(alt_image_id)]
1100 if vim_type == ns_alt_image.get("vim-type"):
1101 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001102 self.logger.debug(
1103 "use alternative image id: {}".format(alt_image_id)
1104 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001105 ns_image_id = alt_image_id
1106 vdur["ns-image-id"] = ns_image_id
1107 break
1108 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001109 if target_vim not in ns_image["vim_info"]:
1110 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001111
Alexis Romero305b5c42022-03-11 15:29:18 +01001112 # Affinity groups
1113 if vdur.get("affinity-or-anti-affinity-group-id"):
1114 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1115 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1116 if target_vim not in ns_ags["vim_info"]:
1117 ns_ags["vim_info"][target_vim] = {}
1118
vegall63162192023-03-06 14:19:16 +00001119 # shared-volumes
1120 if vdur.get("shared-volumes-id"):
1121 for sv_id in vdur["shared-volumes-id"]:
1122 ns_sv = find_in_list(
1123 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1124 )
1125 if ns_sv:
1126 ns_sv["vim_info"][target_vim] = {}
1127
tierno2357f4e2020-10-19 16:38:59 +00001128 vdur["vim_info"] = {target_vim: {}}
1129 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001130 if vnf_params:
1131 vdu_instantiation_params = find_in_list(
1132 get_iterable(vnf_params, "vdu"),
1133 lambda i_vdu: i_vdu["id"] == vdud["id"],
1134 )
1135 if vdu_instantiation_params:
1136 # Parse the vdu_volumes from the instantiation params
1137 vdu_volumes = get_volumes_from_instantiation_params(
1138 vdu_instantiation_params, vdud
1139 )
1140 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001141 vdur["additionalParams"]["OSM"][
1142 "vim_flavor_id"
1143 ] = vdu_instantiation_params.get("vim-flavor-id")
kayal20011028e362024-06-27 08:23:36 +05301144 vdur["additionalParams"]["OSM"][
kayal2001de102fe2024-11-28 10:51:52 +05301145 "vim_flavor_name"
1146 ] = vdu_instantiation_params.get("vim-flavor-name")
1147 vdur["additionalParams"]["OSM"][
kayal20011028e362024-06-27 08:23:36 +05301148 "instance_name"
1149 ] = vdu_instantiation_params.get("instance_name")
kayal2001ed6528c2024-11-28 11:31:56 +05301150 vdur["additionalParams"]["OSM"][
1151 "security-group-name"
1152 ] = vdu_instantiation_params.get("security-group-name")
tierno2357f4e2020-10-19 16:38:59 +00001153 vdur_list.append(vdur)
1154 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001155 target["vnf"].append(target_vnf)
1156
garciadeblas07f4e4c2022-06-09 09:42:58 +02001157 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001158 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001159 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001160 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001161 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001162 nsr_id,
1163 action_id,
1164 nslcmop_id,
1165 start_deploy,
1166 timeout_ns_deploy,
1167 stage,
1168 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001169 )
tierno69f0d382020-05-07 13:08:09 +00001170
1171 # Updating NSR
1172 db_nsr_update = {
1173 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001174 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001175 }
1176 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1177 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1178 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001179 self.logger.debug(
1180 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1181 )
tierno69f0d382020-05-07 13:08:09 +00001182 return
1183
garciadeblas5697b8b2021-03-24 09:17:02 +01001184 async def _wait_ng_ro(
1185 self,
1186 nsr_id,
1187 action_id,
1188 nslcmop_id=None,
1189 start_time=None,
1190 timeout=600,
1191 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001192 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001193 ):
tierno69f0d382020-05-07 13:08:09 +00001194 detailed_status_old = None
1195 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001196 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001197 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001198 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001199 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001200 if desc_status["status"] == "FAILED":
1201 raise NgRoException(desc_status["details"])
1202 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001203 if stage:
1204 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001205 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001206 if stage:
1207 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001208 break
1209 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001210 assert False, "ROclient.check_ns_status returns unknown {}".format(
1211 desc_status["status"]
1212 )
tierno2357f4e2020-10-19 16:38:59 +00001213 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001214 detailed_status_old = stage[2]
1215 db_nsr_update["detailed-status"] = " ".join(stage)
1216 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1217 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001218 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001219 else: # timeout_ns_deploy
1220 raise NgRoException("Timeout waiting ns to deploy")
1221
jegan976c06a2024-07-01 16:47:53 +00001222 def rollback_scaling(self, nsr_id, nslcmop_id):
1223 try:
1224 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
1225 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1226 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
1227 "scaleByStepData"
1228 ]["member-vnf-index"]
1229 db_vnfr = self.db.get_one(
1230 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
1231 )
1232 vim_id = "vim:{}".format(db_vnfr["vim-account-id"])
1233 db_vnfr_update = {"vdur": db_vnfr["vdur"]}
1234 counter = len(db_vnfr_update["vdur"])
1235 updated_db_vnfr = []
1236 for index, vdur in enumerate(db_vnfr_update["vdur"]):
1237 if vdur["vim_info"][vim_id].get("vim_status") == "ACTIVE":
1238 updated_db_vnfr.append(vdur)
1239 db_vnfr_update["vdur"] = updated_db_vnfr
1240 self.update_db_2("vnfrs", db_vnfr["_id"], db_vnfr_update)
1241 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
1242 "scaleByStepData"
1243 ]["scaling-group-descriptor"]
1244 counter -= len(updated_db_vnfr)
1245 db_nsr_update = {
1246 "_admin.scaling-group": db_nsr["_admin"].get("scaling-group")
1247 }
1248 if db_nsr["_admin"].get("scaling-group"):
1249 for index, group in enumerate(db_nsr_update["_admin.scaling-group"]):
1250 if (
1251 group["name"] == scaling_group
1252 and group["vnf_index"] == vnf_index
1253 ):
1254 group["nb-scale-op"] -= counter
1255 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1256 except Exception as e:
1257 self.logger.info(f"There is an error in updating the database. Error {e}")
1258
garciadeblas5697b8b2021-03-24 09:17:02 +01001259 async def _terminate_ng_ro(
1260 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1261 ):
tierno69f0d382020-05-07 13:08:09 +00001262 db_nsr_update = {}
1263 failed_detail = []
1264 action_id = None
1265 start_deploy = time()
1266 try:
1267 target = {
1268 "ns": {"vld": []},
1269 "vnf": [],
1270 "image": [],
1271 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001272 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001273 }
1274 desc = await self.RO.deploy(nsr_id, target)
1275 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001276 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001277 self.logger.debug(
1278 logging_text
1279 + "ns terminate action at RO. action_id={}".format(action_id)
1280 )
tierno69f0d382020-05-07 13:08:09 +00001281
1282 # wait until done
1283 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001284 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001285 nsr_id,
1286 action_id,
1287 nslcmop_id,
1288 start_deploy,
1289 delete_timeout,
1290 stage,
1291 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001292 )
tierno69f0d382020-05-07 13:08:09 +00001293 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1294 # delete all nsr
1295 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001296 except NgRoException as e:
1297 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001298 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1299 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001300 self.logger.debug(
1301 logging_text + "RO_action_id={} already deleted".format(action_id)
1302 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001303 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001304 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001305 self.logger.debug(
1306 logging_text
1307 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1308 )
tierno69f0d382020-05-07 13:08:09 +00001309 else:
1310 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001311 self.logger.error(
1312 logging_text
1313 + "RO_action_id={} delete error: {}".format(action_id, e)
1314 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001315 except Exception as e:
1316 failed_detail.append("delete error: {}".format(e))
1317 self.logger.error(
1318 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1319 )
tierno69f0d382020-05-07 13:08:09 +00001320
1321 if failed_detail:
1322 stage[2] = "Error deleting from VIM"
1323 else:
1324 stage[2] = "Deleted from VIM"
1325 db_nsr_update["detailed-status"] = " ".join(stage)
1326 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1327 self._write_op_status(nslcmop_id, stage)
1328
1329 if failed_detail:
1330 raise LcmException("; ".join(failed_detail))
1331 return
1332
garciadeblas5697b8b2021-03-24 09:17:02 +01001333 async def instantiate_RO(
1334 self,
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 ):
tiernoe95ed362020-04-23 08:24:57 +00001345 """
1346 Instantiate at RO
1347 :param logging_text: preffix text to use at logging
1348 :param nsr_id: nsr identity
1349 :param nsd: database content of ns descriptor
1350 :param db_nsr: database content of ns record
1351 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1352 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001353 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001354 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1355 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1356 :return: None or exception
1357 """
tiernoe876f672020-02-13 14:34:48 +00001358 try:
tiernoe876f672020-02-13 14:34:48 +00001359 start_deploy = time()
1360 ns_params = db_nslcmop.get("operationParams")
1361 if ns_params and ns_params.get("timeout_ns_deploy"):
1362 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1363 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001364 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001365
tiernoe876f672020-02-13 14:34:48 +00001366 # Check for and optionally request placement optimization. Database will be updated if placement activated
1367 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001368 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1369 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1370 for vnfr in db_vnfrs.values():
1371 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1372 break
1373 else:
1374 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001375
garciadeblas5697b8b2021-03-24 09:17:02 +01001376 return await self._instantiate_ng_ro(
1377 logging_text,
1378 nsr_id,
1379 nsd,
1380 db_nsr,
1381 db_nslcmop,
1382 db_vnfrs,
1383 db_vnfds,
1384 n2vc_key_list,
1385 stage,
1386 start_deploy,
1387 timeout_ns_deploy,
1388 )
tierno2357f4e2020-10-19 16:38:59 +00001389 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001390 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001391 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001392 self.logger.error(
1393 "Error deploying at VIM {}".format(e),
1394 exc_info=not isinstance(
1395 e,
1396 (
1397 ROclient.ROClientException,
1398 LcmException,
1399 DbException,
1400 NgRoException,
1401 ),
1402 ),
1403 )
tiernoe876f672020-02-13 14:34:48 +00001404 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001405
tierno7ecbc342020-09-21 14:05:39 +00001406 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1407 """
1408 Wait for kdu to be up, get ip address
1409 :param logging_text: prefix use for logging
1410 :param nsr_id:
1411 :param vnfr_id:
1412 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001413 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001414 """
1415
1416 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1417 nb_tries = 0
1418
1419 while nb_tries < 360:
1420 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001421 kdur = next(
1422 (
1423 x
1424 for x in get_iterable(db_vnfr, "kdur")
1425 if x.get("kdu-name") == kdu_name
1426 ),
1427 None,
1428 )
tierno7ecbc342020-09-21 14:05:39 +00001429 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001430 raise LcmException(
1431 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1432 )
tierno7ecbc342020-09-21 14:05:39 +00001433 if kdur.get("status"):
1434 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001435 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001436 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001437 raise LcmException(
1438 "target KDU={} is in error state".format(kdu_name)
1439 )
tierno7ecbc342020-09-21 14:05:39 +00001440
Gabriel Cubae7898982023-05-11 01:57:21 -05001441 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001442 nb_tries += 1
1443 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1444
garciadeblas5697b8b2021-03-24 09:17:02 +01001445 async def wait_vm_up_insert_key_ro(
1446 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1447 ):
tiernoa5088192019-11-26 16:12:53 +00001448 """
1449 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1450 :param logging_text: prefix use for logging
1451 :param nsr_id:
1452 :param vnfr_id:
1453 :param vdu_id:
1454 :param vdu_index:
1455 :param pub_key: public ssh key to inject, None to skip
1456 :param user: user to apply the public ssh key
1457 :return: IP address
1458 """
quilesj7e13aeb2019-10-08 13:34:55 +02001459
tierno2357f4e2020-10-19 16:38:59 +00001460 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001461 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001462 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001463 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001464
tiernod8323042019-08-09 11:32:23 +00001465 while True:
quilesj3149f262019-12-03 10:58:10 +00001466 ro_retries += 1
1467 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001468 raise LcmException(
1469 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1470 )
quilesj3149f262019-12-03 10:58:10 +00001471
Gabriel Cubae7898982023-05-11 01:57:21 -05001472 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001473
1474 # get ip address
tiernod8323042019-08-09 11:32:23 +00001475 if not target_vdu_id:
1476 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001477
1478 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001479 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001480 raise LcmException(
1481 "Cannot inject ssh-key because target VNF is in error state"
1482 )
tiernod8323042019-08-09 11:32:23 +00001483 ip_address = db_vnfr.get("ip-address")
1484 if not ip_address:
1485 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001486 vdur = next(
1487 (
1488 x
1489 for x in get_iterable(db_vnfr, "vdur")
1490 if x.get("ip-address") == ip_address
1491 ),
1492 None,
1493 )
quilesj3149f262019-12-03 10:58:10 +00001494 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001495 vdur = next(
1496 (
1497 x
1498 for x in get_iterable(db_vnfr, "vdur")
1499 if x.get("vdu-id-ref") == vdu_id
1500 and x.get("count-index") == vdu_index
1501 ),
1502 None,
1503 )
quilesj3149f262019-12-03 10:58:10 +00001504
garciadeblas5697b8b2021-03-24 09:17:02 +01001505 if (
1506 not vdur and len(db_vnfr.get("vdur", ())) == 1
1507 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001508 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001509 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001510 raise LcmException(
1511 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1512 vnfr_id, vdu_id, vdu_index
1513 )
1514 )
tierno2357f4e2020-10-19 16:38:59 +00001515 # New generation RO stores information at "vim_info"
1516 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001517 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001518 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001519 target_vim = next(
1520 t for t in vdur["vim_info"]
1521 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001522 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001523 if (
1524 vdur.get("pdu-type")
1525 or vdur.get("status") == "ACTIVE"
1526 or ng_ro_status == "ACTIVE"
1527 ):
quilesj3149f262019-12-03 10:58:10 +00001528 ip_address = vdur.get("ip-address")
1529 if not ip_address:
1530 continue
1531 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001532 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001533 raise LcmException(
1534 "Cannot inject ssh-key because target VM is in error state"
1535 )
quilesj3149f262019-12-03 10:58:10 +00001536
tiernod8323042019-08-09 11:32:23 +00001537 if not target_vdu_id:
1538 continue
tiernod8323042019-08-09 11:32:23 +00001539
quilesj7e13aeb2019-10-08 13:34:55 +02001540 # inject public key into machine
1541 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001542 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001543 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001544 if vdur.get("pdu-type"):
1545 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1546 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001547 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001548 target = {
1549 "action": {
1550 "action": "inject_ssh_key",
1551 "key": pub_key,
1552 "user": user,
1553 },
1554 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1555 }
1556 desc = await self.RO.deploy(nsr_id, target)
1557 action_id = desc["action_id"]
1558 await self._wait_ng_ro(
1559 nsr_id, action_id, timeout=600, operation="instantiation"
1560 )
1561 break
tierno69f0d382020-05-07 13:08:09 +00001562 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001563 raise LcmException(
1564 "Reaching max tries injecting key. Error: {}".format(e)
1565 )
quilesj7e13aeb2019-10-08 13:34:55 +02001566 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001567 break
1568
1569 return ip_address
1570
tierno5ee02052019-12-05 19:55:02 +00001571 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1572 """
1573 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1574 """
1575 my_vca = vca_deployed_list[vca_index]
1576 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001577 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001578 return
1579 timeout = 300
1580 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001581 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1582 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1583 configuration_status_list = db_nsr["configurationStatus"]
1584 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001585 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001586 # myself
tierno5ee02052019-12-05 19:55:02 +00001587 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001588 if not my_vca.get("member-vnf-index") or (
1589 vca_deployed.get("member-vnf-index")
1590 == my_vca.get("member-vnf-index")
1591 ):
quilesj3655ae02019-12-12 16:08:35 +00001592 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001593 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001594 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001595 elif internal_status == "BROKEN":
1596 raise LcmException(
1597 "Configuration aborted because dependent charm/s has failed"
1598 )
quilesj3655ae02019-12-12 16:08:35 +00001599 else:
1600 break
tierno5ee02052019-12-05 19:55:02 +00001601 else:
quilesj3655ae02019-12-12 16:08:35 +00001602 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001603 return
1604 await asyncio.sleep(10)
1605 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001606
1607 raise LcmException("Configuration aborted because dependent charm/s timeout")
1608
David Garciac1fe90a2021-03-31 19:12:02 +02001609 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001610 vca_id = None
1611 if db_vnfr:
1612 vca_id = deep_get(db_vnfr, ("vca-id",))
1613 elif db_nsr:
1614 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1615 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1616 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001617
garciadeblas5697b8b2021-03-24 09:17:02 +01001618 async def instantiate_N2VC(
1619 self,
1620 logging_text,
1621 vca_index,
1622 nsi_id,
1623 db_nsr,
1624 db_vnfr,
1625 vdu_id,
1626 kdu_name,
1627 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001628 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001629 config_descriptor,
1630 deploy_params,
1631 base_folder,
1632 nslcmop_id,
1633 stage,
1634 vca_type,
1635 vca_name,
1636 ee_config_descriptor,
1637 ):
tiernod8323042019-08-09 11:32:23 +00001638 nsr_id = db_nsr["_id"]
1639 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001640 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001641 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001642 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001643 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001644 "collection": "nsrs",
1645 "filter": {"_id": nsr_id},
1646 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001647 }
tiernod8323042019-08-09 11:32:23 +00001648 step = ""
1649 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001650 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001651 element_under_configuration = nsr_id
1652
tiernod8323042019-08-09 11:32:23 +00001653 vnfr_id = None
1654 if db_vnfr:
1655 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001656 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001657
garciadeblas5697b8b2021-03-24 09:17:02 +01001658 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001659
aktas98488ed2021-07-29 17:42:49 +03001660 if vca_type == "native_charm":
1661 index_number = 0
1662 else:
1663 index_number = vdu_index or 0
1664
tiernod8323042019-08-09 11:32:23 +00001665 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001666 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001667 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001668 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001669 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001670 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001671 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001672 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001673 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001674 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001675 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001676 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001677 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001678 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001679
1680 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001681 if base_folder["pkg-dir"]:
1682 artifact_path = "{}/{}/{}/{}".format(
1683 base_folder["folder"],
1684 base_folder["pkg-dir"],
1685 "charms"
aticig15db6142022-01-24 12:51:26 +03001686 if vca_type
1687 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001688 else "helm-charts",
1689 vca_name,
1690 )
1691 else:
1692 artifact_path = "{}/Scripts/{}/{}/".format(
1693 base_folder["folder"],
1694 "charms"
aticig15db6142022-01-24 12:51:26 +03001695 if vca_type
1696 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001697 else "helm-charts",
1698 vca_name,
1699 )
bravof922c4172020-11-24 21:21:43 -03001700
1701 self.logger.debug("Artifact path > {}".format(artifact_path))
1702
tiernoa278b842020-07-08 15:33:55 +00001703 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001704 initial_config_primitive_list = config_descriptor.get(
1705 "initial-config-primitive"
1706 )
tiernoa278b842020-07-08 15:33:55 +00001707
garciadeblas5697b8b2021-03-24 09:17:02 +01001708 self.logger.debug(
1709 "Initial config primitive list > {}".format(
1710 initial_config_primitive_list
1711 )
1712 )
bravof922c4172020-11-24 21:21:43 -03001713
tiernoa278b842020-07-08 15:33:55 +00001714 # add config if not present for NS charm
1715 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001716 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001717 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1718 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1719 )
tiernod8323042019-08-09 11:32:23 +00001720
garciadeblas5697b8b2021-03-24 09:17:02 +01001721 self.logger.debug(
1722 "Initial config primitive list #2 > {}".format(
1723 initial_config_primitive_list
1724 )
1725 )
tierno588547c2020-07-01 15:30:20 +00001726 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001727 # find old ee_id if exists
1728 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001729
David Garciac1fe90a2021-03-31 19:12:02 +02001730 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001731 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001732 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001733 self._write_configuration_status(
1734 nsr_id=nsr_id,
1735 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001736 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001737 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001738 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001739 )
tiernod8323042019-08-09 11:32:23 +00001740
tierno588547c2020-07-01 15:30:20 +00001741 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001742 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001743
1744 ee_id = None
1745 credentials = None
1746 if vca_type == "k8s_proxy_charm":
1747 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001748 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001749 namespace=namespace,
1750 artifact_path=artifact_path,
1751 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001752 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001753 )
Luis Vegae11384e2023-10-10 22:36:33 +00001754 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001755 ee_id, credentials = await self.vca_map[
1756 vca_type
1757 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001758 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001759 reuse_ee_id=ee_id,
1760 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001761 config=osm_config,
1762 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001763 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001764 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001765 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001766 else:
1767 ee_id, credentials = await self.vca_map[
1768 vca_type
1769 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001770 namespace=namespace,
1771 reuse_ee_id=ee_id,
1772 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001773 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001774 )
quilesj3655ae02019-12-12 16:08:35 +00001775
tierno588547c2020-07-01 15:30:20 +00001776 elif vca_type == "native_charm":
1777 step = "Waiting to VM being up and getting IP address"
1778 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001779 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1780 logging_text,
1781 nsr_id,
1782 vnfr_id,
1783 vdu_id,
1784 vdu_index,
1785 user=None,
1786 pub_key=None,
1787 )
tierno588547c2020-07-01 15:30:20 +00001788 credentials = {"hostname": rw_mgmt_ip}
1789 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001790 username = deep_get(
1791 config_descriptor, ("config-access", "ssh-access", "default-user")
1792 )
tierno588547c2020-07-01 15:30:20 +00001793 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1794 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001795 if not username and initial_config_primitive_list:
1796 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001797 for param in config_primitive.get("parameter", ()):
1798 if param["name"] == "ssh-username":
1799 username = param["value"]
1800 break
1801 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001802 raise LcmException(
1803 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1804 "'config-access.ssh-access.default-user'"
1805 )
tierno588547c2020-07-01 15:30:20 +00001806 credentials["username"] = username
1807 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001808
tierno588547c2020-07-01 15:30:20 +00001809 self._write_configuration_status(
1810 nsr_id=nsr_id,
1811 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001812 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001813 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001814 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001815 )
quilesj3655ae02019-12-12 16:08:35 +00001816
tierno588547c2020-07-01 15:30:20 +00001817 step = "register execution environment {}".format(credentials)
1818 self.logger.debug(logging_text + step)
1819 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001820 credentials=credentials,
1821 namespace=namespace,
1822 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001823 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001824 )
tierno3bedc9b2019-11-27 15:46:57 +00001825
tierno588547c2020-07-01 15:30:20 +00001826 # for compatibility with MON/POL modules, the need model and application name at database
1827 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001828 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001829 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1830 if len(ee_id_parts) >= 2:
1831 model_name = ee_id_parts[0]
1832 application_name = ee_id_parts[1]
1833 db_nsr_update[db_update_entry + "model"] = model_name
1834 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001835
1836 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001837 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001838
tiernoc231a872020-01-21 08:49:05 +00001839 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001840 nsr_id=nsr_id,
1841 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001842 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001843 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001844 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001845 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001846 )
1847
tierno3bedc9b2019-11-27 15:46:57 +00001848 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001849 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001850 config = None
tierno588547c2020-07-01 15:30:20 +00001851 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001852 config_primitive = next(
1853 (p for p in initial_config_primitive_list if p["name"] == "config"),
1854 None,
1855 )
tiernoa278b842020-07-08 15:33:55 +00001856 if config_primitive:
1857 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001858 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001859 )
tierno588547c2020-07-01 15:30:20 +00001860 num_units = 1
1861 if vca_type == "lxc_proxy_charm":
1862 if element_type == "NS":
1863 num_units = db_nsr.get("config-units") or 1
1864 elif element_type == "VNF":
1865 num_units = db_vnfr.get("config-units") or 1
1866 elif element_type == "VDU":
1867 for v in db_vnfr["vdur"]:
1868 if vdu_id == v["vdu-id-ref"]:
1869 num_units = v.get("config-units") or 1
1870 break
David Garciaaae391f2020-11-09 11:12:54 +01001871 if vca_type != "k8s_proxy_charm":
1872 await self.vca_map[vca_type].install_configuration_sw(
1873 ee_id=ee_id,
1874 artifact_path=artifact_path,
1875 db_dict=db_dict,
1876 config=config,
1877 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001878 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001879 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001880 )
quilesj7e13aeb2019-10-08 13:34:55 +02001881
quilesj63f90042020-01-17 09:53:55 +00001882 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001883 self.update_db_2(
1884 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1885 )
quilesj63f90042020-01-17 09:53:55 +00001886
1887 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001888 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001889 logging_text=logging_text,
1890 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001891 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001892 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001893 )
quilesj63f90042020-01-17 09:53:55 +00001894
Patricia Reinosob4312c02023-01-06 22:28:44 +00001895 if not is_relation_added:
1896 raise LcmException("Relations could not be added to VCA.")
1897
quilesj7e13aeb2019-10-08 13:34:55 +02001898 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001899 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001900 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001901 pub_key = None
1902 user = None
tierno588547c2020-07-01 15:30:20 +00001903 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001904 if deep_get(
1905 config_descriptor, ("config-access", "ssh-access", "required")
1906 ):
tierno588547c2020-07-01 15:30:20 +00001907 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001908 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001909 user = deep_get(
1910 config_descriptor,
1911 ("config-access", "ssh-access", "default-user"),
1912 )
tierno3bedc9b2019-11-27 15:46:57 +00001913 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001914 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001915 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001916 )
quilesj7e13aeb2019-10-08 13:34:55 +02001917
garciadeblas5697b8b2021-03-24 09:17:02 +01001918 step = "Insert public key into VM user={} ssh_key={}".format(
1919 user, pub_key
1920 )
tierno3bedc9b2019-11-27 15:46:57 +00001921 else:
tierno588547c2020-07-01 15:30:20 +00001922 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001923 step = "Waiting to VM being up and getting IP address"
1924 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001925
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001926 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1927 rw_mgmt_ip = None
1928
tierno3bedc9b2019-11-27 15:46:57 +00001929 # n2vc_redesign STEP 5.1
1930 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001931 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001932 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001933 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001934 logging_text, nsr_id, vnfr_id, kdu_name
1935 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001936 vnfd = self.db.get_one(
1937 "vnfds_revisions",
1938 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1939 )
1940 kdu = get_kdu(vnfd, kdu_name)
1941 kdu_services = [
1942 service["name"] for service in get_kdu_services(kdu)
1943 ]
1944 exposed_services = []
1945 for service in services:
1946 if any(s in service["name"] for s in kdu_services):
1947 exposed_services.append(service)
1948 await self.vca_map[vca_type].exec_primitive(
1949 ee_id=ee_id,
1950 primitive_name="config",
1951 params_dict={
1952 "osm-config": json.dumps(
1953 OsmConfigBuilder(
1954 k8s={"services": exposed_services}
1955 ).build()
1956 )
1957 },
1958 vca_id=vca_id,
1959 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001960
1961 # This verification is needed in order to avoid trying to add a public key
1962 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1963 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1964 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1965 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001966 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001967 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1968 logging_text,
1969 nsr_id,
1970 vnfr_id,
1971 vdu_id,
1972 vdu_index,
1973 user=user,
1974 pub_key=pub_key,
1975 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001976
garciadeblas5697b8b2021-03-24 09:17:02 +01001977 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001978
tiernoa5088192019-11-26 16:12:53 +00001979 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001980 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001981
1982 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001983 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001984
1985 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001986 if initial_config_primitive_list:
1987 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001988
1989 # stage, in function of element type: vdu, kdu, vnf or ns
1990 my_vca = vca_deployed_list[vca_index]
1991 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1992 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001993 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001994 elif my_vca.get("member-vnf-index"):
1995 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001996 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001997 else:
1998 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001999 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00002000
tiernoc231a872020-01-21 08:49:05 +00002001 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002002 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002003 )
2004
garciadeblas5697b8b2021-03-24 09:17:02 +01002005 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002006
tiernoe876f672020-02-13 14:34:48 +00002007 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002008 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002009 # adding information on the vca_deployed if it is a NS execution environment
2010 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002011 deploy_params["ns_config_info"] = json.dumps(
2012 self._get_ns_config_info(nsr_id)
2013 )
tiernod8323042019-08-09 11:32:23 +00002014 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002015 primitive_params_ = self._map_primitive_params(
2016 initial_config_primitive, {}, deploy_params
2017 )
tierno3bedc9b2019-11-27 15:46:57 +00002018
garciadeblas5697b8b2021-03-24 09:17:02 +01002019 step = "execute primitive '{}' params '{}'".format(
2020 initial_config_primitive["name"], primitive_params_
2021 )
tiernod8323042019-08-09 11:32:23 +00002022 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002023 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002024 ee_id=ee_id,
2025 primitive_name=initial_config_primitive["name"],
2026 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002027 db_dict=db_dict,
2028 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002029 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002030 )
tiernoe876f672020-02-13 14:34:48 +00002031 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2032 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002033 if config_descriptor.get("terminate-config-primitive"):
2034 self.update_db_2(
2035 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2036 )
tiernoe876f672020-02-13 14:34:48 +00002037 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002038
tiernod8323042019-08-09 11:32:23 +00002039 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002040
tiernob996d942020-07-03 14:52:28 +00002041 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00002042 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02002043 # TODO: review for those cases where the helm chart is a reference and
2044 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002045 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002046 ee_id=ee_id,
2047 artifact_path=artifact_path,
2048 ee_config_descriptor=ee_config_descriptor,
2049 vnfr_id=vnfr_id,
2050 nsr_id=nsr_id,
2051 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002052 element_type=element_type,
2053 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2054 vdu_id=vdu_id,
2055 vdu_index=vdu_index,
2056 kdu_name=kdu_name,
2057 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002058 )
2059 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002060 self.update_db_2(
2061 "nsrs",
2062 nsr_id,
2063 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2064 )
tiernob996d942020-07-03 14:52:28 +00002065
bravof73bac502021-05-11 07:38:47 -04002066 for job in prometheus_jobs:
2067 self.db.set_one(
2068 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002069 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002070 job,
2071 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002072 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002073 )
2074
quilesj7e13aeb2019-10-08 13:34:55 +02002075 step = "instantiated at VCA"
2076 self.logger.debug(logging_text + step)
2077
tiernoc231a872020-01-21 08:49:05 +00002078 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002079 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002080 )
2081
tiernod8323042019-08-09 11:32:23 +00002082 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002083 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002084 if not isinstance(
2085 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2086 ):
2087 self.logger.error(
2088 "Exception while {} : {}".format(step, e), exc_info=True
2089 )
tiernoc231a872020-01-21 08:49:05 +00002090 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002091 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002092 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002093 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002094
garciadeblas5697b8b2021-03-24 09:17:02 +01002095 def _write_ns_status(
2096 self,
2097 nsr_id: str,
2098 ns_state: str,
2099 current_operation: str,
2100 current_operation_id: str,
2101 error_description: str = None,
2102 error_detail: str = None,
2103 other_update: dict = None,
2104 ):
tiernoe876f672020-02-13 14:34:48 +00002105 """
2106 Update db_nsr fields.
2107 :param nsr_id:
2108 :param ns_state:
2109 :param current_operation:
2110 :param current_operation_id:
2111 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002112 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002113 :param other_update: Other required changes at database if provided, will be cleared
2114 :return:
2115 """
quilesj4cda56b2019-12-05 10:02:20 +00002116 try:
tiernoe876f672020-02-13 14:34:48 +00002117 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002118 db_dict[
2119 "_admin.nslcmop"
2120 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002121 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002122 db_dict["_admin.operation-type"] = (
2123 current_operation if current_operation != "IDLE" else None
2124 )
quilesj4cda56b2019-12-05 10:02:20 +00002125 db_dict["currentOperation"] = current_operation
2126 db_dict["currentOperationID"] = current_operation_id
2127 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002128 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002129
2130 if ns_state:
2131 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002132 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002133 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002134 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002135
garciadeblas5697b8b2021-03-24 09:17:02 +01002136 def _write_op_status(
2137 self,
2138 op_id: str,
2139 stage: list = None,
2140 error_message: str = None,
2141 queuePosition: int = 0,
2142 operation_state: str = None,
2143 other_update: dict = None,
2144 ):
quilesj3655ae02019-12-12 16:08:35 +00002145 try:
tiernoe876f672020-02-13 14:34:48 +00002146 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002147 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002148 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002149 db_dict["stage"] = stage[0]
2150 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002151 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002152 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002153
2154 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002155 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002156 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002157 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002158 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002159 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002160 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002161 self.logger.warn(
2162 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2163 )
quilesj3655ae02019-12-12 16:08:35 +00002164
tierno51183952020-04-03 15:48:18 +00002165 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002166 try:
tierno51183952020-04-03 15:48:18 +00002167 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002168 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002169 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002170 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002171 db_nsr_update = {
2172 "configurationStatus.{}.status".format(index): status
2173 for index, v in enumerate(config_status)
2174 if v
2175 }
quilesj3655ae02019-12-12 16:08:35 +00002176 # update status
tierno51183952020-04-03 15:48:18 +00002177 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002178
tiernoe876f672020-02-13 14:34:48 +00002179 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002180 self.logger.warn(
2181 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2182 )
quilesj3655ae02019-12-12 16:08:35 +00002183
garciadeblas5697b8b2021-03-24 09:17:02 +01002184 def _write_configuration_status(
2185 self,
2186 nsr_id: str,
2187 vca_index: int,
2188 status: str = None,
2189 element_under_configuration: str = None,
2190 element_type: str = None,
2191 other_update: dict = None,
2192 ):
quilesj3655ae02019-12-12 16:08:35 +00002193 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2194 # .format(vca_index, status))
2195
2196 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002197 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002198 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002199 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002200 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002201 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002202 db_dict[
2203 db_path + "elementUnderConfiguration"
2204 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002205 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002206 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002207 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002208 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002209 self.logger.warn(
2210 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2211 status, nsr_id, vca_index, e
2212 )
2213 )
quilesj4cda56b2019-12-05 10:02:20 +00002214
tierno38089af2020-04-16 07:56:58 +00002215 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2216 """
2217 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2218 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2219 Database is used because the result can be obtained from a different LCM worker in case of HA.
2220 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2221 :param db_nslcmop: database content of nslcmop
2222 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002223 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2224 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002225 """
tierno8790a3d2020-04-23 22:49:52 +00002226 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002227 nslcmop_id = db_nslcmop["_id"]
2228 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002229 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002230 self.logger.debug(
2231 logging_text + "Invoke and wait for placement optimization"
2232 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002233 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002234 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002235 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002236 pla_result = None
2237 while not pla_result and wait >= 0:
2238 await asyncio.sleep(db_poll_interval)
2239 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002240 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002241 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002242
2243 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002244 raise LcmException(
2245 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2246 )
magnussonle9198bb2020-01-21 13:00:51 +01002247
garciadeblas5697b8b2021-03-24 09:17:02 +01002248 for pla_vnf in pla_result["vnf"]:
2249 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2250 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002251 continue
tierno8790a3d2020-04-23 22:49:52 +00002252 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002253 self.db.set_one(
2254 "vnfrs",
2255 {"_id": vnfr["_id"]},
2256 {"vim-account-id": pla_vnf["vimAccountId"]},
2257 )
tierno38089af2020-04-16 07:56:58 +00002258 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002259 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002260 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002261
aguilard1ae3c562023-02-16 17:24:35 +00002262 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2263 alerts = []
2264 nsr_id = vnfr["nsr-id-ref"]
2265 df = vnfd.get("df", [{}])[0]
2266 # Checking for auto-healing configuration
2267 if "healing-aspect" in df:
2268 healing_aspects = df["healing-aspect"]
2269 for healing in healing_aspects:
2270 for healing_policy in healing.get("healing-policy", ()):
2271 vdu_id = healing_policy["vdu-id"]
2272 vdur = next(
2273 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2274 {},
2275 )
2276 if not vdur:
2277 continue
2278 metric_name = "vm_status"
2279 vdu_name = vdur.get("name")
2280 vnf_member_index = vnfr["member-vnf-index-ref"]
2281 uuid = str(uuid4())
2282 name = f"healing_{uuid}"
2283 action = healing_policy
2284 # action_on_recovery = healing.get("action-on-recovery")
2285 # cooldown_time = healing.get("cooldown-time")
2286 # day1 = healing.get("day1")
2287 alert = {
2288 "uuid": uuid,
2289 "name": name,
2290 "metric": metric_name,
2291 "tags": {
2292 "ns_id": nsr_id,
2293 "vnf_member_index": vnf_member_index,
2294 "vdu_name": vdu_name,
2295 },
2296 "alarm_status": "ok",
2297 "action_type": "healing",
2298 "action": action,
2299 }
2300 alerts.append(alert)
2301 return alerts
2302
2303 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2304 alerts = []
2305 nsr_id = vnfr["nsr-id-ref"]
2306 df = vnfd.get("df", [{}])[0]
2307 # Checking for auto-scaling configuration
2308 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002309 scaling_aspects = df["scaling-aspect"]
2310 all_vnfd_monitoring_params = {}
2311 for ivld in vnfd.get("int-virtual-link-desc", ()):
2312 for mp in ivld.get("monitoring-parameters", ()):
2313 all_vnfd_monitoring_params[mp.get("id")] = mp
2314 for vdu in vnfd.get("vdu", ()):
2315 for mp in vdu.get("monitoring-parameter", ()):
2316 all_vnfd_monitoring_params[mp.get("id")] = mp
2317 for df in vnfd.get("df", ()):
2318 for mp in df.get("monitoring-parameter", ()):
2319 all_vnfd_monitoring_params[mp.get("id")] = mp
2320 for scaling_aspect in scaling_aspects:
2321 scaling_group_name = scaling_aspect.get("name", "")
2322 # Get monitored VDUs
2323 all_monitored_vdus = set()
2324 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2325 "deltas", ()
2326 ):
2327 for vdu_delta in delta.get("vdu-delta", ()):
2328 all_monitored_vdus.add(vdu_delta.get("id"))
2329 monitored_vdurs = list(
2330 filter(
2331 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2332 vnfr["vdur"],
2333 )
2334 )
2335 if not monitored_vdurs:
2336 self.logger.error(
2337 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2338 )
2339 continue
2340 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2341 if scaling_policy["scaling-type"] != "automatic":
2342 continue
2343 threshold_time = scaling_policy.get("threshold-time", "1")
2344 cooldown_time = scaling_policy.get("cooldown-time", "0")
2345 for scaling_criteria in scaling_policy["scaling-criteria"]:
2346 monitoring_param_ref = scaling_criteria.get(
2347 "vnf-monitoring-param-ref"
2348 )
2349 vnf_monitoring_param = all_vnfd_monitoring_params[
2350 monitoring_param_ref
2351 ]
2352 for vdur in monitored_vdurs:
2353 vdu_id = vdur["vdu-id-ref"]
2354 metric_name = vnf_monitoring_param.get("performance-metric")
Rahul Kumar54671c52024-05-09 15:34:01 +05302355 if "exporters-endpoints" not in df:
2356 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002357 vnf_member_index = vnfr["member-vnf-index-ref"]
2358 scalein_threshold = scaling_criteria.get(
2359 "scale-in-threshold"
2360 )
2361 scaleout_threshold = scaling_criteria.get(
2362 "scale-out-threshold"
2363 )
2364 # Looking for min/max-number-of-instances
2365 instances_min_number = 1
2366 instances_max_number = 1
2367 vdu_profile = df["vdu-profile"]
2368 if vdu_profile:
2369 profile = next(
2370 item for item in vdu_profile if item["id"] == vdu_id
2371 )
2372 instances_min_number = profile.get(
2373 "min-number-of-instances", 1
2374 )
2375 instances_max_number = profile.get(
2376 "max-number-of-instances", 1
2377 )
2378
2379 if scalein_threshold:
2380 uuid = str(uuid4())
2381 name = f"scalein_{uuid}"
2382 operation = scaling_criteria[
2383 "scale-in-relational-operation"
2384 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002385 rel_operator = self.rel_operation_types.get(
2386 operation, "<="
2387 )
aguilard1ae3c562023-02-16 17:24:35 +00002388 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2389 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302390 if (
2391 "exporters-endpoints" in df
2392 and metric_name.startswith("kpi_")
2393 ):
2394 new_metric_name = (
2395 f'osm_{metric_name.replace("kpi_", "").strip()}'
2396 )
2397 metric_port = df["exporters-endpoints"].get(
2398 "metric-port", 9100
2399 )
2400 vdu_ip = vdur["ip-address"]
2401 ip_port = str(vdu_ip) + ":" + str(metric_port)
2402 metric_selector = (
2403 f'{new_metric_name}{{instance="{ip_port}"}}'
2404 )
2405 expression = f"({metric_selector} {rel_operator} {scalein_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002406 labels = {
2407 "ns_id": nsr_id,
2408 "vnf_member_index": vnf_member_index,
2409 "vdu_id": vdu_id,
2410 }
2411 prom_cfg = {
2412 "alert": name,
2413 "expr": expression,
2414 "for": str(threshold_time) + "m",
2415 "labels": labels,
2416 }
2417 action = scaling_policy
2418 action = {
2419 "scaling-group": scaling_group_name,
2420 "cooldown-time": cooldown_time,
2421 }
2422 alert = {
2423 "uuid": uuid,
2424 "name": name,
2425 "metric": metric_name,
2426 "tags": {
2427 "ns_id": nsr_id,
2428 "vnf_member_index": vnf_member_index,
2429 "vdu_id": vdu_id,
2430 },
2431 "alarm_status": "ok",
2432 "action_type": "scale_in",
2433 "action": action,
2434 "prometheus_config": prom_cfg,
2435 }
2436 alerts.append(alert)
2437
2438 if scaleout_threshold:
2439 uuid = str(uuid4())
2440 name = f"scaleout_{uuid}"
2441 operation = scaling_criteria[
2442 "scale-out-relational-operation"
2443 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002444 rel_operator = self.rel_operation_types.get(
2445 operation, "<="
2446 )
aguilard1ae3c562023-02-16 17:24:35 +00002447 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2448 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302449 if (
2450 "exporters-endpoints" in df
2451 and metric_name.startswith("kpi_")
2452 ):
2453 new_metric_name = (
2454 f'osm_{metric_name.replace("kpi_", "").strip()}'
2455 )
2456 metric_port = df["exporters-endpoints"].get(
2457 "metric-port", 9100
2458 )
2459 vdu_ip = vdur["ip-address"]
2460 ip_port = str(vdu_ip) + ":" + str(metric_port)
2461 metric_selector = (
2462 f'{new_metric_name}{{instance="{ip_port}"}}'
2463 )
2464 expression = f"({metric_selector} {rel_operator} {scaleout_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002465 labels = {
2466 "ns_id": nsr_id,
2467 "vnf_member_index": vnf_member_index,
2468 "vdu_id": vdu_id,
2469 }
2470 prom_cfg = {
2471 "alert": name,
2472 "expr": expression,
2473 "for": str(threshold_time) + "m",
2474 "labels": labels,
2475 }
2476 action = scaling_policy
2477 action = {
2478 "scaling-group": scaling_group_name,
2479 "cooldown-time": cooldown_time,
2480 }
2481 alert = {
2482 "uuid": uuid,
2483 "name": name,
2484 "metric": metric_name,
2485 "tags": {
2486 "ns_id": nsr_id,
2487 "vnf_member_index": vnf_member_index,
2488 "vdu_id": vdu_id,
2489 },
2490 "alarm_status": "ok",
2491 "action_type": "scale_out",
2492 "action": action,
2493 "prometheus_config": prom_cfg,
2494 }
2495 alerts.append(alert)
2496 return alerts
2497
garciadeblas9148fa82023-05-30 12:51:14 +02002498 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2499 alerts = []
2500 nsr_id = vnfr["nsr-id-ref"]
2501 vnf_member_index = vnfr["member-vnf-index-ref"]
2502
2503 # Checking for VNF alarm configuration
2504 for vdur in vnfr["vdur"]:
2505 vdu_id = vdur["vdu-id-ref"]
2506 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2507 if "alarm" in vdu:
2508 # Get VDU monitoring params, since alerts are based on them
2509 vdu_monitoring_params = {}
2510 for mp in vdu.get("monitoring-parameter", []):
2511 vdu_monitoring_params[mp.get("id")] = mp
2512 if not vdu_monitoring_params:
2513 self.logger.error(
2514 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2515 )
2516 continue
2517 # Get alarms in the VDU
2518 alarm_descriptors = vdu["alarm"]
2519 # Create VDU alarms for each alarm in the VDU
2520 for alarm_descriptor in alarm_descriptors:
2521 # Check that the VDU alarm refers to a proper monitoring param
2522 alarm_monitoring_param = alarm_descriptor.get(
2523 "vnf-monitoring-param-ref", ""
2524 )
2525 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2526 alarm_monitoring_param, {}
2527 )
2528 if not vdu_specific_monitoring_param:
2529 self.logger.error(
2530 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2531 )
2532 continue
2533 metric_name = vdu_specific_monitoring_param.get(
2534 "performance-metric"
2535 )
2536 if not metric_name:
2537 self.logger.error(
2538 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2539 )
2540 continue
2541 # Set params of the alarm to be created in Prometheus
2542 metric_name = f"osm_{metric_name}"
2543 metric_threshold = alarm_descriptor.get("value")
2544 uuid = str(uuid4())
2545 alert_name = f"vdu_alarm_{uuid}"
2546 operation = alarm_descriptor["operation"]
2547 rel_operator = self.rel_operation_types.get(operation, "<=")
2548 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 +00002549 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002550 labels = {
2551 "ns_id": nsr_id,
2552 "vnf_member_index": vnf_member_index,
2553 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002554 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002555 }
2556 prom_cfg = {
2557 "alert": alert_name,
2558 "expr": expression,
2559 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2560 "labels": labels,
2561 }
2562 alarm_action = dict()
2563 for action_type in ["ok", "insufficient-data", "alarm"]:
2564 if (
2565 "actions" in alarm_descriptor
2566 and action_type in alarm_descriptor["actions"]
2567 ):
aguilardeb076722023-05-31 09:45:00 +00002568 alarm_action[action_type] = alarm_descriptor["actions"][
2569 action_type
2570 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002571 alert = {
2572 "uuid": uuid,
2573 "name": alert_name,
2574 "metric": metric_name,
2575 "tags": {
2576 "ns_id": nsr_id,
2577 "vnf_member_index": vnf_member_index,
2578 "vdu_id": vdu_id,
2579 },
2580 "alarm_status": "ok",
2581 "action_type": "vdu_alarm",
2582 "action": alarm_action,
2583 "prometheus_config": prom_cfg,
2584 }
2585 alerts.append(alert)
2586 return alerts
2587
magnussonle9198bb2020-01-21 13:00:51 +01002588 def update_nsrs_with_pla_result(self, params):
2589 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002590 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2591 self.update_db_2(
2592 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2593 )
magnussonle9198bb2020-01-21 13:00:51 +01002594 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002595 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002596
tierno59d22d22018-09-25 18:10:19 +02002597 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002598 """
2599
2600 :param nsr_id: ns instance to deploy
2601 :param nslcmop_id: operation to run
2602 :return:
2603 """
kuused124bfe2019-06-18 12:09:24 +02002604
2605 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002606 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002607 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002608 self.logger.debug(
2609 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2610 )
kuused124bfe2019-06-18 12:09:24 +02002611 return
2612
tierno59d22d22018-09-25 18:10:19 +02002613 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2614 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002615
tierno59d22d22018-09-25 18:10:19 +02002616 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002617
2618 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002619 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002620
2621 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002622 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002623
2624 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002625 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002626 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002627 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002628
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002629 timeout_ns_deploy = self.timeout.ns_deploy
2630
tierno59d22d22018-09-25 18:10:19 +02002631 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002632 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002633 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002634 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002635 exc = None
tiernoe876f672020-02-13 14:34:48 +00002636 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002637 stage = [
2638 "Stage 1/5: preparation of the environment.",
2639 "Waiting for previous operations to terminate.",
2640 "",
2641 ]
tiernoe876f672020-02-13 14:34:48 +00002642 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002643 try:
kuused124bfe2019-06-18 12:09:24 +02002644 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002645 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002646
quilesj7e13aeb2019-10-08 13:34:55 +02002647 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002648 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002649 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002650 db_nsr_update["detailed-status"] = "creating"
2651 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002652 self._write_ns_status(
2653 nsr_id=nsr_id,
2654 ns_state="BUILDING",
2655 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002656 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002657 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002658 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002659 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002660
quilesj7e13aeb2019-10-08 13:34:55 +02002661 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002662 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002663 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002664 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2665 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2666 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2667 )
tierno744303e2020-01-13 16:46:31 +00002668 ns_params = db_nslcmop.get("operationParams")
2669 if ns_params and ns_params.get("timeout_ns_deploy"):
2670 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002671
2672 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002673 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002674 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002675 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002676 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002677 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002678 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002679 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002680 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002681 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002682
quilesj7e13aeb2019-10-08 13:34:55 +02002683 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002684 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002685 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002686 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002687
quilesj7e13aeb2019-10-08 13:34:55 +02002688 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002689 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002690
2691 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002692 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002693 if vnfr.get("kdur"):
2694 kdur_list = []
2695 for kdur in vnfr["kdur"]:
2696 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002697 kdur["additionalParams"] = json.loads(
2698 kdur["additionalParams"]
2699 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002700 kdur_list.append(kdur)
2701 vnfr["kdur"] = kdur_list
2702
bravof922c4172020-11-24 21:21:43 -03002703 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2704 vnfd_id = vnfr["vnfd-id"]
2705 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002706 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002707
quilesj7e13aeb2019-10-08 13:34:55 +02002708 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002709 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002710 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002711 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2712 vnfd_id, vnfd_ref
2713 )
tiernoe876f672020-02-13 14:34:48 +00002714 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002715 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002716
quilesj7e13aeb2019-10-08 13:34:55 +02002717 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002718 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002719
2720 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002721 vca_deployed_list = None
2722 if db_nsr["_admin"].get("deployed"):
2723 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2724 if vca_deployed_list is None:
2725 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002726 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002727 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002728 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002729 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002730 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002731 elif isinstance(vca_deployed_list, dict):
2732 # maintain backward compatibility. Change a dict to list at database
2733 vca_deployed_list = list(vca_deployed_list.values())
2734 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002735 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002736
garciadeblas5697b8b2021-03-24 09:17:02 +01002737 if not isinstance(
2738 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2739 ):
tiernoa009e552019-01-30 16:45:44 +00002740 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2741 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002742
tiernobaa51102018-12-14 13:16:18 +00002743 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2744 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2745 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002746 self.db.set_list(
2747 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2748 )
quilesj3655ae02019-12-12 16:08:35 +00002749
2750 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002751 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2752 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002753
tiernob5203912020-08-11 11:20:13 +00002754 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002755 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002756 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002757 await self.deploy_kdus(
2758 logging_text=logging_text,
2759 nsr_id=nsr_id,
2760 nslcmop_id=nslcmop_id,
2761 db_vnfrs=db_vnfrs,
2762 db_vnfds=db_vnfds,
2763 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002764 )
tiernoe876f672020-02-13 14:34:48 +00002765
2766 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002767 # n2vc_redesign STEP 1 Get VCA public ssh-key
2768 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002769 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002770 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002771 if self.vca_config.public_key:
2772 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002773
tiernoe876f672020-02-13 14:34:48 +00002774 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002775 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002776 self.instantiate_RO(
2777 logging_text=logging_text,
2778 nsr_id=nsr_id,
2779 nsd=nsd,
2780 db_nsr=db_nsr,
2781 db_nslcmop=db_nslcmop,
2782 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002783 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002784 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002785 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002786 )
tiernod8323042019-08-09 11:32:23 +00002787 )
2788 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002789 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002790
tiernod8323042019-08-09 11:32:23 +00002791 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002792 stage[1] = "Deploying Execution Environments."
2793 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002794
Gabriel Cuba1411a002022-10-07 11:38:23 -05002795 # create namespace and certificate if any helm based EE is present in the NS
2796 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002797 await self.vca_map["helm-v3"].setup_ns_namespace(
2798 name=nsr_id,
2799 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002800 # create TLS certificates
2801 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002802 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002803 dns_prefix="*",
2804 nsr_id=nsr_id,
2805 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002806 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002807 )
2808
tiernod8323042019-08-09 11:32:23 +00002809 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002810 for vnf_profile in get_vnf_profiles(nsd):
2811 vnfd_id = vnf_profile["vnfd-id"]
2812 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2813 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002814 db_vnfr = db_vnfrs[member_vnf_index]
2815 base_folder = vnfd["_admin"]["storage"]
2816 vdu_id = None
2817 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002818 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002819 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002820 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002821
tierno8a518872018-12-21 13:42:14 +00002822 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002823 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002824 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002825 deploy_params.update(
2826 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2827 )
tierno8a518872018-12-21 13:42:14 +00002828
bravofe5a31bc2021-02-17 19:09:12 -03002829 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002830 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002831 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002832 logging_text=logging_text
2833 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002834 db_nsr=db_nsr,
2835 db_vnfr=db_vnfr,
2836 nslcmop_id=nslcmop_id,
2837 nsr_id=nsr_id,
2838 nsi_id=nsi_id,
2839 vnfd_id=vnfd_id,
2840 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002841 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002842 member_vnf_index=member_vnf_index,
2843 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002844 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002845 vdu_name=vdu_name,
2846 deploy_params=deploy_params,
2847 descriptor_config=descriptor_config,
2848 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002849 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002850 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002851 )
tierno59d22d22018-09-25 18:10:19 +02002852
2853 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002854 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002855 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002856 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002857 vdur = find_in_list(
2858 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2859 )
bravof922c4172020-11-24 21:21:43 -03002860
tierno626e0152019-11-29 14:16:16 +00002861 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002862 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002863 else:
2864 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002865 deploy_params_vdu["OSM"] = get_osm_params(
2866 db_vnfr, vdu_id, vdu_count_index=0
2867 )
endika76ba9232021-06-21 18:55:07 +02002868 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002869
2870 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002871 self.logger.debug(
2872 "Descriptor config > {}".format(descriptor_config)
2873 )
tierno588547c2020-07-01 15:30:20 +00002874 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002875 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002876 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002877 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002878 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002879 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002880 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002881 logging_text=logging_text
2882 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2883 member_vnf_index, vdu_id, vdu_index
2884 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002885 db_nsr=db_nsr,
2886 db_vnfr=db_vnfr,
2887 nslcmop_id=nslcmop_id,
2888 nsr_id=nsr_id,
2889 nsi_id=nsi_id,
2890 vnfd_id=vnfd_id,
2891 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002892 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002893 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002894 member_vnf_index=member_vnf_index,
2895 vdu_index=vdu_index,
2896 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002897 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002898 descriptor_config=descriptor_config,
2899 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002900 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002901 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002902 )
bravof922c4172020-11-24 21:21:43 -03002903 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002904 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002905 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002906 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002907 vdu_id = None
2908 vdu_index = 0
2909 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002910 kdu_index, kdur = next(
2911 x
2912 for x in enumerate(db_vnfr["kdur"])
2913 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002914 )
bravof922c4172020-11-24 21:21:43 -03002915 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002916 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002917 deploy_params_kdu.update(
2918 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002919 )
tierno59d22d22018-09-25 18:10:19 +02002920
calvinosanch9f9c6f22019-11-04 13:37:39 +01002921 self._deploy_n2vc(
2922 logging_text=logging_text,
2923 db_nsr=db_nsr,
2924 db_vnfr=db_vnfr,
2925 nslcmop_id=nslcmop_id,
2926 nsr_id=nsr_id,
2927 nsi_id=nsi_id,
2928 vnfd_id=vnfd_id,
2929 vdu_id=vdu_id,
2930 kdu_name=kdu_name,
2931 member_vnf_index=member_vnf_index,
2932 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002933 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002934 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002935 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002936 descriptor_config=descriptor_config,
2937 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002938 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002939 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002940 )
tierno59d22d22018-09-25 18:10:19 +02002941
k4.rahul74944982023-04-19 17:00:52 +05302942 # Check if each vnf has exporter for metric collection if so update prometheus job records
2943 if "exporters-endpoints" in vnfd.get("df")[0]:
2944 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2945 self.logger.debug("exporter config :{}".format(exporter_config))
2946 artifact_path = "{}/{}/{}".format(
2947 base_folder["folder"],
2948 base_folder["pkg-dir"],
2949 "exporter-endpoint",
2950 )
2951 ee_id = None
2952 ee_config_descriptor = exporter_config
2953 vnfr_id = db_vnfr["id"]
2954 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2955 logging_text,
2956 nsr_id,
2957 vnfr_id,
2958 vdu_id=None,
2959 vdu_index=None,
2960 user=None,
2961 pub_key=None,
2962 )
2963 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2964 self.logger.debug("Artifact_path:{}".format(artifact_path))
2965 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2966 vdu_id_for_prom = None
2967 vdu_index_for_prom = None
2968 for x in get_iterable(db_vnfr, "vdur"):
2969 vdu_id_for_prom = x.get("vdu-id-ref")
2970 vdu_index_for_prom = x.get("count-index")
2971 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2972 ee_id=ee_id,
2973 artifact_path=artifact_path,
2974 ee_config_descriptor=ee_config_descriptor,
2975 vnfr_id=vnfr_id,
2976 nsr_id=nsr_id,
2977 target_ip=rw_mgmt_ip,
2978 element_type="VDU",
2979 vdu_id=vdu_id_for_prom,
2980 vdu_index=vdu_index_for_prom,
2981 )
2982
2983 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2984 if prometheus_jobs:
2985 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2986 self.update_db_2(
2987 "nsrs",
2988 nsr_id,
2989 db_nsr_update,
2990 )
2991
2992 for job in prometheus_jobs:
2993 self.db.set_one(
2994 "prometheus_jobs",
2995 {"job_name": job["job_name"]},
2996 job,
2997 upsert=True,
2998 fail_on_empty=False,
2999 )
3000
tierno1b633412019-02-25 16:48:23 +00003001 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00003002 descriptor_config = nsd.get("ns-configuration")
3003 if descriptor_config and descriptor_config.get("juju"):
3004 vnfd_id = None
3005 db_vnfr = None
3006 member_vnf_index = None
3007 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01003008 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01003009 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00003010 vdu_index = 0
3011 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00003012
tiernod8323042019-08-09 11:32:23 +00003013 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01003014 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00003015 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003016 deploy_params.update(
3017 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
3018 )
tiernod8323042019-08-09 11:32:23 +00003019 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02003020 self._deploy_n2vc(
3021 logging_text=logging_text,
3022 db_nsr=db_nsr,
3023 db_vnfr=db_vnfr,
3024 nslcmop_id=nslcmop_id,
3025 nsr_id=nsr_id,
3026 nsi_id=nsi_id,
3027 vnfd_id=vnfd_id,
3028 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01003029 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02003030 member_vnf_index=member_vnf_index,
3031 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003032 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02003033 vdu_name=vdu_name,
3034 deploy_params=deploy_params,
3035 descriptor_config=descriptor_config,
3036 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00003037 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01003038 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02003039 )
tierno1b633412019-02-25 16:48:23 +00003040
tiernoe876f672020-02-13 14:34:48 +00003041 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00003042
garciadeblas5697b8b2021-03-24 09:17:02 +01003043 except (
3044 ROclient.ROClientException,
3045 DbException,
3046 LcmException,
3047 N2VCException,
3048 ) as e:
3049 self.logger.error(
3050 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3051 )
tierno59d22d22018-09-25 18:10:19 +02003052 exc = e
3053 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003054 self.logger.error(
3055 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3056 )
tierno59d22d22018-09-25 18:10:19 +02003057 exc = "Operation was cancelled"
3058 except Exception as e:
3059 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003060 self.logger.critical(
3061 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3062 exc_info=True,
3063 )
tierno59d22d22018-09-25 18:10:19 +02003064 finally:
3065 if exc:
tiernoe876f672020-02-13 14:34:48 +00003066 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003067 try:
tiernoe876f672020-02-13 14:34:48 +00003068 # wait for pending tasks
3069 if tasks_dict_info:
3070 stage[1] = "Waiting for instantiate pending tasks."
3071 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003072 error_list += await self._wait_for_tasks(
3073 logging_text,
3074 tasks_dict_info,
3075 timeout_ns_deploy,
3076 stage,
3077 nslcmop_id,
3078 nsr_id=nsr_id,
3079 )
tiernoe876f672020-02-13 14:34:48 +00003080 stage[1] = stage[2] = ""
3081 except asyncio.CancelledError:
3082 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003083 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3084 await self._wait_for_tasks(
3085 logging_text,
3086 tasks_dict_info,
3087 timeout_ns_deploy,
3088 stage,
3089 nslcmop_id,
3090 nsr_id=nsr_id,
3091 )
tiernoe876f672020-02-13 14:34:48 +00003092 except Exception as exc:
3093 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003094
tiernoe876f672020-02-13 14:34:48 +00003095 # update operation-status
3096 db_nsr_update["operational-status"] = "running"
3097 # let's begin with VCA 'configured' status (later we can change it)
3098 db_nsr_update["config-status"] = "configured"
3099 for task, task_name in tasks_dict_info.items():
3100 if not task.done() or task.cancelled() or task.exception():
3101 if task_name.startswith(self.task_name_deploy_vca):
3102 # A N2VC task is pending
3103 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003104 else:
tiernoe876f672020-02-13 14:34:48 +00003105 # RO or KDU task is pending
3106 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003107
tiernoe876f672020-02-13 14:34:48 +00003108 # update status at database
3109 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003110 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003111 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003112 error_description_nslcmop = "{} Detail: {}".format(
3113 stage[0], error_detail
3114 )
3115 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3116 nslcmop_id, stage[0]
3117 )
quilesj3655ae02019-12-12 16:08:35 +00003118
garciadeblas5697b8b2021-03-24 09:17:02 +01003119 db_nsr_update["detailed-status"] = (
3120 error_description_nsr + " Detail: " + error_detail
3121 )
tiernoe876f672020-02-13 14:34:48 +00003122 db_nslcmop_update["detailed-status"] = error_detail
3123 nslcmop_operation_state = "FAILED"
3124 ns_state = "BROKEN"
3125 else:
tiernoa2143262020-03-27 16:20:40 +00003126 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003127 error_description_nsr = error_description_nslcmop = None
3128 ns_state = "READY"
3129 db_nsr_update["detailed-status"] = "Done"
3130 db_nslcmop_update["detailed-status"] = "Done"
3131 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003132 # Gather auto-healing and auto-scaling alerts for each vnfr
3133 healing_alerts = []
3134 scaling_alerts = []
3135 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3136 vnfd = next(
3137 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3138 )
3139 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3140 for alert in healing_alerts:
3141 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3142 self.db.create("alerts", alert)
3143
3144 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3145 for alert in scaling_alerts:
3146 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3147 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003148
garciadeblas9148fa82023-05-30 12:51:14 +02003149 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3150 for alert in alarm_alerts:
3151 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3152 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003153 if db_nsr:
3154 self._write_ns_status(
3155 nsr_id=nsr_id,
3156 ns_state=ns_state,
3157 current_operation="IDLE",
3158 current_operation_id=None,
3159 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003160 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003161 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003162 )
tiernoa17d4f42020-04-28 09:59:23 +00003163 self._write_op_status(
3164 op_id=nslcmop_id,
3165 stage="",
3166 error_message=error_description_nslcmop,
3167 operation_state=nslcmop_operation_state,
3168 other_update=db_nslcmop_update,
3169 )
quilesj3655ae02019-12-12 16:08:35 +00003170
tierno59d22d22018-09-25 18:10:19 +02003171 if nslcmop_operation_state:
3172 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003173 await self.msg.aiowrite(
3174 "ns",
3175 "instantiated",
3176 {
3177 "nsr_id": nsr_id,
3178 "nslcmop_id": nslcmop_id,
3179 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003180 "startTime": db_nslcmop["startTime"],
3181 "links": db_nslcmop["links"],
3182 "operationParams": {
3183 "nsInstanceId": nsr_id,
3184 "nsdId": db_nsr["nsd-id"],
3185 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003186 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003187 )
tierno59d22d22018-09-25 18:10:19 +02003188 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003189 self.logger.error(
3190 logging_text + "kafka_write notification Exception {}".format(e)
3191 )
tierno59d22d22018-09-25 18:10:19 +02003192
3193 self.logger.debug(logging_text + "Exit")
3194 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3195
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003196 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003197 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003198 cached_vnfds[vnfd_id] = self.db.get_one(
3199 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3200 )
David Garciab4ebcd02021-10-28 02:00:43 +02003201 return cached_vnfds[vnfd_id]
3202
3203 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3204 if vnf_profile_id not in cached_vnfrs:
3205 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3206 "vnfrs",
3207 {
3208 "member-vnf-index-ref": vnf_profile_id,
3209 "nsr-id-ref": nsr_id,
3210 },
3211 )
3212 return cached_vnfrs[vnf_profile_id]
3213
3214 def _is_deployed_vca_in_relation(
3215 self, vca: DeployedVCA, relation: Relation
3216 ) -> bool:
3217 found = False
3218 for endpoint in (relation.provider, relation.requirer):
3219 if endpoint["kdu-resource-profile-id"]:
3220 continue
3221 found = (
3222 vca.vnf_profile_id == endpoint.vnf_profile_id
3223 and vca.vdu_profile_id == endpoint.vdu_profile_id
3224 and vca.execution_environment_ref == endpoint.execution_environment_ref
3225 )
3226 if found:
3227 break
3228 return found
3229
3230 def _update_ee_relation_data_with_implicit_data(
3231 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3232 ):
3233 ee_relation_data = safe_get_ee_relation(
3234 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3235 )
3236 ee_relation_level = EELevel.get_level(ee_relation_data)
3237 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3238 "execution-environment-ref"
3239 ]:
3240 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3241 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003242 project = nsd["_admin"]["projects_read"][0]
3243 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003244 entity_id = (
3245 vnfd_id
3246 if ee_relation_level == EELevel.VNF
3247 else ee_relation_data["vdu-profile-id"]
3248 )
3249 ee = get_juju_ee_ref(db_vnfd, entity_id)
3250 if not ee:
3251 raise Exception(
3252 f"not execution environments found for ee_relation {ee_relation_data}"
3253 )
3254 ee_relation_data["execution-environment-ref"] = ee["id"]
3255 return ee_relation_data
3256
3257 def _get_ns_relations(
3258 self,
3259 nsr_id: str,
3260 nsd: Dict[str, Any],
3261 vca: DeployedVCA,
3262 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003263 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003264 relations = []
3265 db_ns_relations = get_ns_configuration_relation_list(nsd)
3266 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003267 provider_dict = None
3268 requirer_dict = None
3269 if all(key in r for key in ("provider", "requirer")):
3270 provider_dict = r["provider"]
3271 requirer_dict = r["requirer"]
3272 elif "entities" in r:
3273 provider_id = r["entities"][0]["id"]
3274 provider_dict = {
3275 "nsr-id": nsr_id,
3276 "endpoint": r["entities"][0]["endpoint"],
3277 }
3278 if provider_id != nsd["id"]:
3279 provider_dict["vnf-profile-id"] = provider_id
3280 requirer_id = r["entities"][1]["id"]
3281 requirer_dict = {
3282 "nsr-id": nsr_id,
3283 "endpoint": r["entities"][1]["endpoint"],
3284 }
3285 if requirer_id != nsd["id"]:
3286 requirer_dict["vnf-profile-id"] = requirer_id
3287 else:
aticig15db6142022-01-24 12:51:26 +03003288 raise Exception(
3289 "provider/requirer or entities must be included in the relation."
3290 )
David Garciab4ebcd02021-10-28 02:00:43 +02003291 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003292 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003293 )
3294 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003295 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003296 )
3297 provider = EERelation(relation_provider)
3298 requirer = EERelation(relation_requirer)
3299 relation = Relation(r["name"], provider, requirer)
3300 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3301 if vca_in_relation:
3302 relations.append(relation)
3303 return relations
3304
3305 def _get_vnf_relations(
3306 self,
3307 nsr_id: str,
3308 nsd: Dict[str, Any],
3309 vca: DeployedVCA,
3310 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003311 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003312 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003313 if vca.target_element == "ns":
3314 self.logger.debug("VCA is a NS charm, not a VNF.")
3315 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003316 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3317 vnf_profile_id = vnf_profile["id"]
3318 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003319 project = nsd["_admin"]["projects_read"][0]
3320 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003321 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3322 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003323 provider_dict = None
3324 requirer_dict = None
3325 if all(key in r for key in ("provider", "requirer")):
3326 provider_dict = r["provider"]
3327 requirer_dict = r["requirer"]
3328 elif "entities" in r:
3329 provider_id = r["entities"][0]["id"]
3330 provider_dict = {
3331 "nsr-id": nsr_id,
3332 "vnf-profile-id": vnf_profile_id,
3333 "endpoint": r["entities"][0]["endpoint"],
3334 }
3335 if provider_id != vnfd_id:
3336 provider_dict["vdu-profile-id"] = provider_id
3337 requirer_id = r["entities"][1]["id"]
3338 requirer_dict = {
3339 "nsr-id": nsr_id,
3340 "vnf-profile-id": vnf_profile_id,
3341 "endpoint": r["entities"][1]["endpoint"],
3342 }
3343 if requirer_id != vnfd_id:
3344 requirer_dict["vdu-profile-id"] = requirer_id
3345 else:
aticig15db6142022-01-24 12:51:26 +03003346 raise Exception(
3347 "provider/requirer or entities must be included in the relation."
3348 )
David Garciab4ebcd02021-10-28 02:00:43 +02003349 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003350 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003351 )
3352 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003353 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003354 )
3355 provider = EERelation(relation_provider)
3356 requirer = EERelation(relation_requirer)
3357 relation = Relation(r["name"], provider, requirer)
3358 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3359 if vca_in_relation:
3360 relations.append(relation)
3361 return relations
3362
3363 def _get_kdu_resource_data(
3364 self,
3365 ee_relation: EERelation,
3366 db_nsr: Dict[str, Any],
3367 cached_vnfds: Dict[str, Any],
3368 ) -> DeployedK8sResource:
3369 nsd = get_nsd(db_nsr)
3370 vnf_profiles = get_vnf_profiles(nsd)
3371 vnfd_id = find_in_list(
3372 vnf_profiles,
3373 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3374 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003375 project = nsd["_admin"]["projects_read"][0]
3376 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003377 kdu_resource_profile = get_kdu_resource_profile(
3378 db_vnfd, ee_relation.kdu_resource_profile_id
3379 )
3380 kdu_name = kdu_resource_profile["kdu-name"]
3381 deployed_kdu, _ = get_deployed_kdu(
3382 db_nsr.get("_admin", ()).get("deployed", ()),
3383 kdu_name,
3384 ee_relation.vnf_profile_id,
3385 )
3386 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3387 return deployed_kdu
3388
3389 def _get_deployed_component(
3390 self,
3391 ee_relation: EERelation,
3392 db_nsr: Dict[str, Any],
3393 cached_vnfds: Dict[str, Any],
3394 ) -> DeployedComponent:
3395 nsr_id = db_nsr["_id"]
3396 deployed_component = None
3397 ee_level = EELevel.get_level(ee_relation)
3398 if ee_level == EELevel.NS:
3399 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3400 if vca:
3401 deployed_component = DeployedVCA(nsr_id, vca)
3402 elif ee_level == EELevel.VNF:
3403 vca = get_deployed_vca(
3404 db_nsr,
3405 {
3406 "vdu_id": None,
3407 "member-vnf-index": ee_relation.vnf_profile_id,
3408 "ee_descriptor_id": ee_relation.execution_environment_ref,
3409 },
3410 )
3411 if vca:
3412 deployed_component = DeployedVCA(nsr_id, vca)
3413 elif ee_level == EELevel.VDU:
3414 vca = get_deployed_vca(
3415 db_nsr,
3416 {
3417 "vdu_id": ee_relation.vdu_profile_id,
3418 "member-vnf-index": ee_relation.vnf_profile_id,
3419 "ee_descriptor_id": ee_relation.execution_environment_ref,
3420 },
3421 )
3422 if vca:
3423 deployed_component = DeployedVCA(nsr_id, vca)
3424 elif ee_level == EELevel.KDU:
3425 kdu_resource_data = self._get_kdu_resource_data(
3426 ee_relation, db_nsr, cached_vnfds
3427 )
3428 if kdu_resource_data:
3429 deployed_component = DeployedK8sResource(kdu_resource_data)
3430 return deployed_component
3431
3432 async def _add_relation(
3433 self,
3434 relation: Relation,
3435 vca_type: str,
3436 db_nsr: Dict[str, Any],
3437 cached_vnfds: Dict[str, Any],
3438 cached_vnfrs: Dict[str, Any],
3439 ) -> bool:
3440 deployed_provider = self._get_deployed_component(
3441 relation.provider, db_nsr, cached_vnfds
3442 )
3443 deployed_requirer = self._get_deployed_component(
3444 relation.requirer, db_nsr, cached_vnfds
3445 )
3446 if (
3447 deployed_provider
3448 and deployed_requirer
3449 and deployed_provider.config_sw_installed
3450 and deployed_requirer.config_sw_installed
3451 ):
3452 provider_db_vnfr = (
3453 self._get_vnfr(
3454 relation.provider.nsr_id,
3455 relation.provider.vnf_profile_id,
3456 cached_vnfrs,
3457 )
3458 if relation.provider.vnf_profile_id
3459 else None
3460 )
3461 requirer_db_vnfr = (
3462 self._get_vnfr(
3463 relation.requirer.nsr_id,
3464 relation.requirer.vnf_profile_id,
3465 cached_vnfrs,
3466 )
3467 if relation.requirer.vnf_profile_id
3468 else None
3469 )
3470 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3471 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3472 provider_relation_endpoint = RelationEndpoint(
3473 deployed_provider.ee_id,
3474 provider_vca_id,
3475 relation.provider.endpoint,
3476 )
3477 requirer_relation_endpoint = RelationEndpoint(
3478 deployed_requirer.ee_id,
3479 requirer_vca_id,
3480 relation.requirer.endpoint,
3481 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003482 try:
3483 await self.vca_map[vca_type].add_relation(
3484 provider=provider_relation_endpoint,
3485 requirer=requirer_relation_endpoint,
3486 )
3487 except N2VCException as exception:
3488 self.logger.error(exception)
3489 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003490 return True
3491 return False
3492
David Garciac1fe90a2021-03-31 19:12:02 +02003493 async def _add_vca_relations(
3494 self,
3495 logging_text,
3496 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003497 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003498 vca_index: int,
3499 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003500 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003501 # steps:
3502 # 1. find all relations for this VCA
3503 # 2. wait for other peers related
3504 # 3. add relations
3505
3506 try:
quilesj63f90042020-01-17 09:53:55 +00003507 # STEP 1: find all relations for this VCA
3508
3509 # read nsr record
3510 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003511 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003512
3513 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003514 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3515 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003516
David Garciab4ebcd02021-10-28 02:00:43 +02003517 cached_vnfds = {}
3518 cached_vnfrs = {}
3519 relations = []
3520 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3521 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003522
3523 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003524 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003525 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003526 return True
3527
David Garciab4ebcd02021-10-28 02:00:43 +02003528 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003529
3530 # add all relations
3531 start = time()
3532 while True:
3533 # check timeout
3534 now = time()
3535 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003536 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003537 return False
3538
David Garciab4ebcd02021-10-28 02:00:43 +02003539 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003540 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3541
David Garciab4ebcd02021-10-28 02:00:43 +02003542 # for each relation, find the VCA's related
3543 for relation in relations.copy():
3544 added = await self._add_relation(
3545 relation,
3546 vca_type,
3547 db_nsr,
3548 cached_vnfds,
3549 cached_vnfrs,
3550 )
3551 if added:
3552 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003553
David Garciab4ebcd02021-10-28 02:00:43 +02003554 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003555 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003556 break
David Garciab4ebcd02021-10-28 02:00:43 +02003557 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003558
3559 return True
3560
3561 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003562 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003563 return False
3564
garciadeblas5697b8b2021-03-24 09:17:02 +01003565 async def _install_kdu(
3566 self,
3567 nsr_id: str,
3568 nsr_db_path: str,
3569 vnfr_data: dict,
3570 kdu_index: int,
3571 kdud: dict,
3572 vnfd: dict,
3573 k8s_instance_info: dict,
3574 k8params: dict = None,
3575 timeout: int = 600,
3576 vca_id: str = None,
3577 ):
tiernob9018152020-04-16 14:18:24 +00003578 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003579 k8sclustertype = k8s_instance_info["k8scluster-type"]
3580 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003581 db_dict_install = {
3582 "collection": "nsrs",
3583 "filter": {"_id": nsr_id},
3584 "path": nsr_db_path,
3585 }
lloretgalleg7c121132020-07-08 07:53:22 +00003586
romeromonser4554a702021-05-28 12:00:08 +02003587 if k8s_instance_info.get("kdu-deployment-name"):
3588 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3589 else:
3590 kdu_instance = self.k8scluster_map[
3591 k8sclustertype
3592 ].generate_kdu_instance_name(
3593 db_dict=db_dict_install,
3594 kdu_model=k8s_instance_info["kdu-model"],
3595 kdu_name=k8s_instance_info["kdu-name"],
3596 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003597
3598 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003599 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003600 item="nsrs",
3601 _id=nsr_id,
3602 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003603 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003604
3605 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3606 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3607 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3608 # namespace, this first verification could be removed, and the next step would be done for any kind
3609 # of KNF.
3610 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3611 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3612 if k8sclustertype in ("juju", "juju-bundle"):
3613 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3614 # that the user passed a namespace which he wants its KDU to be deployed in)
3615 if (
3616 self.db.count(
3617 table="nsrs",
3618 q_filter={
3619 "_id": nsr_id,
3620 "_admin.projects_write": k8s_instance_info["namespace"],
3621 "_admin.projects_read": k8s_instance_info["namespace"],
3622 },
3623 )
3624 > 0
3625 ):
3626 self.logger.debug(
3627 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3628 )
3629 self.update_db_2(
3630 item="nsrs",
3631 _id=nsr_id,
3632 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3633 )
3634 k8s_instance_info["namespace"] = kdu_instance
3635
David Garciad64e2742021-02-25 20:19:18 +01003636 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003637 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3638 kdu_model=k8s_instance_info["kdu-model"],
3639 atomic=True,
3640 params=k8params,
3641 db_dict=db_dict_install,
3642 timeout=timeout,
3643 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003644 namespace=k8s_instance_info["namespace"],
3645 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003646 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003647 )
lloretgalleg7c121132020-07-08 07:53:22 +00003648
3649 # Obtain services to obtain management service ip
3650 services = await self.k8scluster_map[k8sclustertype].get_services(
3651 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3652 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003653 namespace=k8s_instance_info["namespace"],
3654 )
lloretgalleg7c121132020-07-08 07:53:22 +00003655
3656 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003657 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003658 kdu_config = get_configuration(vnfd, kdud["name"])
3659 if kdu_config:
3660 target_ee_list = kdu_config.get("execution-environment-list", [])
3661 else:
3662 target_ee_list = []
3663
lloretgalleg7c121132020-07-08 07:53:22 +00003664 if services:
tierno7ecbc342020-09-21 14:05:39 +00003665 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003666 mgmt_services = [
3667 service
3668 for service in kdud.get("service", [])
3669 if service.get("mgmt-service")
3670 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003671 for mgmt_service in mgmt_services:
3672 for service in services:
3673 if service["name"].startswith(mgmt_service["name"]):
3674 # Mgmt service found, Obtain service ip
3675 ip = service.get("external_ip", service.get("cluster_ip"))
3676 if isinstance(ip, list) and len(ip) == 1:
3677 ip = ip[0]
3678
garciadeblas5697b8b2021-03-24 09:17:02 +01003679 vnfr_update_dict[
3680 "kdur.{}.ip-address".format(kdu_index)
3681 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003682
3683 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003684 service_external_cp = mgmt_service.get(
3685 "external-connection-point-ref"
3686 )
lloretgalleg7c121132020-07-08 07:53:22 +00003687 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003688 if (
3689 deep_get(vnfd, ("mgmt-interface", "cp"))
3690 == service_external_cp
3691 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003692 vnfr_update_dict["ip-address"] = ip
3693
bravof6ec62b72021-02-25 17:20:35 -03003694 if find_in_list(
3695 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003696 lambda ee: ee.get(
3697 "external-connection-point-ref", ""
3698 )
3699 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003700 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003701 vnfr_update_dict[
3702 "kdur.{}.ip-address".format(kdu_index)
3703 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003704 break
3705 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003706 self.logger.warn(
3707 "Mgmt service name: {} not found".format(
3708 mgmt_service["name"]
3709 )
3710 )
lloretgalleg7c121132020-07-08 07:53:22 +00003711
tierno7ecbc342020-09-21 14:05:39 +00003712 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3713 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003714
bravof9a256db2021-02-22 18:02:07 -03003715 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003716 if (
3717 kdu_config
3718 and kdu_config.get("initial-config-primitive")
3719 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
jegan99448902024-12-06 07:19:34 +00003720 and get_helm_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
garciadeblas5697b8b2021-03-24 09:17:02 +01003721 ):
3722 initial_config_primitive_list = kdu_config.get(
3723 "initial-config-primitive"
3724 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003725 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3726
3727 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003728 primitive_params_ = self._map_primitive_params(
3729 initial_config_primitive, {}, {}
3730 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003731
3732 await asyncio.wait_for(
3733 self.k8scluster_map[k8sclustertype].exec_primitive(
3734 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3735 kdu_instance=kdu_instance,
3736 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003737 params=primitive_params_,
3738 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003739 vca_id=vca_id,
3740 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003741 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003742 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003743
tiernob9018152020-04-16 14:18:24 +00003744 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003745 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003746 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003747 self.update_db_2(
3748 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3749 )
3750 self.update_db_2(
3751 "vnfrs",
3752 vnfr_data.get("_id"),
3753 {"kdur.{}.status".format(kdu_index): "ERROR"},
3754 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003755 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003756 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003757 self.logger.warning(
3758 f"An exception occurred while updating DB: {str(error)}"
3759 )
lloretgalleg7c121132020-07-08 07:53:22 +00003760 # reraise original error
3761 raise
3762
3763 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003764
garciadeblas5697b8b2021-03-24 09:17:02 +01003765 async def deploy_kdus(
3766 self,
3767 logging_text,
3768 nsr_id,
3769 nslcmop_id,
3770 db_vnfrs,
3771 db_vnfds,
3772 task_instantiation_info,
3773 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003774 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003775
garciadeblas5697b8b2021-03-24 09:17:02 +01003776 k8scluster_id_2_uuic = {
3777 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003778 "juju-bundle": {},
3779 }
tierno626e0152019-11-29 14:16:16 +00003780
tierno16f4a4e2020-07-20 09:05:51 +00003781 async def _get_cluster_id(cluster_id, cluster_type):
Anirudh Guptac2be9492025-05-13 05:53:38 +00003782 # nonlocal k8scluster_id_2_uuic
tierno626e0152019-11-29 14:16:16 +00003783 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3784 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3785
tierno16f4a4e2020-07-20 09:05:51 +00003786 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003787 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3788 "k8scluster", cluster_id
3789 )
tierno16f4a4e2020-07-20 09:05:51 +00003790 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003791 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3792 task_name, cluster_id
3793 )
tierno16f4a4e2020-07-20 09:05:51 +00003794 self.logger.debug(logging_text + text)
3795 await asyncio.wait(task_dependency, timeout=3600)
3796
garciadeblas5697b8b2021-03-24 09:17:02 +01003797 db_k8scluster = self.db.get_one(
3798 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3799 )
tierno626e0152019-11-29 14:16:16 +00003800 if not db_k8scluster:
3801 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003802
tierno626e0152019-11-29 14:16:16 +00003803 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3804 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003805 if cluster_type == "helm-chart-v3":
3806 try:
3807 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003808 k8s_credentials = yaml.safe_dump(
3809 db_k8scluster.get("credentials")
3810 )
3811 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3812 k8s_credentials, reuse_cluster_uuid=cluster_id
3813 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003814 db_k8scluster_update = {}
3815 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3816 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003817 db_k8scluster_update[
3818 "_admin.helm-chart-v3.created"
3819 ] = uninstall_sw
3820 db_k8scluster_update[
3821 "_admin.helm-chart-v3.operationalState"
3822 ] = "ENABLED"
3823 self.update_db_2(
3824 "k8sclusters", cluster_id, db_k8scluster_update
3825 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003826 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003827 self.logger.error(
3828 logging_text
3829 + "error initializing helm-v3 cluster: {}".format(str(e))
3830 )
3831 raise LcmException(
3832 "K8s cluster '{}' has not been initialized for '{}'".format(
3833 cluster_id, cluster_type
3834 )
3835 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003836 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003837 raise LcmException(
3838 "K8s cluster '{}' has not been initialized for '{}'".format(
3839 cluster_id, cluster_type
3840 )
3841 )
tierno626e0152019-11-29 14:16:16 +00003842 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3843 return k8s_id
3844
3845 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003846 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003847 try:
tierno626e0152019-11-29 14:16:16 +00003848 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003849 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003850
tierno626e0152019-11-29 14:16:16 +00003851 index = 0
tiernoe876f672020-02-13 14:34:48 +00003852 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003853 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003854
tierno626e0152019-11-29 14:16:16 +00003855 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003856 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003857 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3858 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003859 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003860 vnfd_id = vnfr_data.get("vnfd-id")
3861 vnfd_with_id = find_in_list(
3862 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3863 )
3864 kdud = next(
3865 kdud
3866 for kdud in vnfd_with_id["kdu"]
3867 if kdud["name"] == kdur["kdu-name"]
3868 )
tiernode1584f2020-04-07 09:07:33 +00003869 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003870 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003871 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003872 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003873 # Default version: helm3, if helm-version is v2 assign v2
3874 k8sclustertype = "helm-chart-v3"
3875 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003876 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003877 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003878 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003879 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003880 raise LcmException(
3881 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3882 "juju-bundle. Maybe an old NBI version is running".format(
3883 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3884 )
3885 )
quilesjacde94f2020-01-23 10:07:08 +00003886 # check if kdumodel is a file and exists
3887 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003888 vnfd_with_id = find_in_list(
3889 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3890 )
3891 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003892 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003893 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003894 if storage["pkg-dir"]:
3895 filename = "{}/{}/{}s/{}".format(
3896 storage["folder"],
3897 storage["pkg-dir"],
3898 k8sclustertype,
3899 kdumodel,
3900 )
3901 else:
3902 filename = "{}/Scripts/{}s/{}".format(
3903 storage["folder"],
3904 k8sclustertype,
3905 kdumodel,
3906 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003907 if self.fs.file_exists(
3908 filename, mode="file"
3909 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003910 kdumodel = self.fs.path + filename
3911 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003912 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003913 except Exception as e: # it is not a file
3914 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003915
tiernoe876f672020-02-13 14:34:48 +00003916 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003917 step = "Synchronize repos for k8s cluster '{}'".format(
3918 k8s_cluster_id
3919 )
tierno16f4a4e2020-07-20 09:05:51 +00003920 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003921
lloretgalleg7c121132020-07-08 07:53:22 +00003922 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003923 if (
3924 k8sclustertype == "helm-chart"
3925 and cluster_uuid not in updated_cluster_list
3926 ) or (
3927 k8sclustertype == "helm-chart-v3"
3928 and cluster_uuid not in updated_v3_cluster_list
3929 ):
tiernoe876f672020-02-13 14:34:48 +00003930 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003931 self.k8scluster_map[k8sclustertype].synchronize_repos(
3932 cluster_uuid=cluster_uuid
3933 )
3934 )
tiernoe876f672020-02-13 14:34:48 +00003935 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003936 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003937 unset = {
3938 "_admin.helm_charts_added." + item: None
3939 for item in del_repo_list
3940 }
3941 updated = {
3942 "_admin.helm_charts_added." + item: name
3943 for item, name in added_repo_dict.items()
3944 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003945 updated_cluster_list.append(cluster_uuid)
3946 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003947 unset = {
3948 "_admin.helm_charts_v3_added." + item: None
3949 for item in del_repo_list
3950 }
3951 updated = {
3952 "_admin.helm_charts_v3_added." + item: name
3953 for item, name in added_repo_dict.items()
3954 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003955 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003956 self.logger.debug(
3957 logging_text + "repos synchronized on k8s cluster "
3958 "'{}' to_delete: {}, to_add: {}".format(
3959 k8s_cluster_id, del_repo_list, added_repo_dict
3960 )
3961 )
3962 self.db.set_one(
3963 "k8sclusters",
3964 {"_id": k8s_cluster_id},
3965 updated,
3966 unset=unset,
3967 )
lloretgallegedc5f332020-02-20 11:50:50 +01003968
lloretgalleg7c121132020-07-08 07:53:22 +00003969 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003970 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3971 vnfr_data["member-vnf-index-ref"],
3972 kdur["kdu-name"],
3973 k8s_cluster_id,
3974 )
3975 k8s_instance_info = {
3976 "kdu-instance": None,
3977 "k8scluster-uuid": cluster_uuid,
3978 "k8scluster-type": k8sclustertype,
3979 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3980 "kdu-name": kdur["kdu-name"],
3981 "kdu-model": kdumodel,
3982 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003983 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003984 }
tiernob9018152020-04-16 14:18:24 +00003985 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003986 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003987 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003988 vnfd_with_id = find_in_list(
3989 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3990 )
tiernoa2143262020-03-27 16:20:40 +00003991 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003992 self._install_kdu(
3993 nsr_id,
3994 db_path,
3995 vnfr_data,
3996 kdu_index,
3997 kdud,
3998 vnfd_with_id,
3999 k8s_instance_info,
4000 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02004001 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01004002 vca_id=vca_id,
4003 )
4004 )
4005 self.lcm_tasks.register(
4006 "ns",
4007 nsr_id,
4008 nslcmop_id,
4009 "instantiate_KDU-{}".format(index),
4010 task,
4011 )
4012 task_instantiation_info[task] = "Deploying KDU {}".format(
4013 kdur["kdu-name"]
4014 )
tiernoe876f672020-02-13 14:34:48 +00004015
tierno626e0152019-11-29 14:16:16 +00004016 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00004017
tiernoe876f672020-02-13 14:34:48 +00004018 except (LcmException, asyncio.CancelledError):
4019 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01004020 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00004021 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
4022 if isinstance(e, (N2VCException, DbException)):
4023 self.logger.error(logging_text + msg)
4024 else:
4025 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00004026 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01004027 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01004028 if db_nsr_update:
4029 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00004030
garciadeblas5697b8b2021-03-24 09:17:02 +01004031 def _deploy_n2vc(
4032 self,
4033 logging_text,
4034 db_nsr,
4035 db_vnfr,
4036 nslcmop_id,
4037 nsr_id,
4038 nsi_id,
4039 vnfd_id,
4040 vdu_id,
4041 kdu_name,
4042 member_vnf_index,
4043 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004044 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004045 vdu_name,
4046 deploy_params,
4047 descriptor_config,
4048 base_folder,
4049 task_instantiation_info,
4050 stage,
4051 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004052 # launch instantiate_N2VC in a asyncio task and register task object
4053 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4054 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004055 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004056
garciadeblas5697b8b2021-03-24 09:17:02 +01004057 self.logger.debug(
4058 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4059 )
aticig9bc63ac2022-07-27 09:32:06 +03004060
4061 charm_name = ""
4062 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004063 if "execution-environment-list" in descriptor_config:
4064 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004065 elif "juju" in descriptor_config:
4066 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004067 if "execution-environment-list" not in descriptor_config:
4068 # charm name is only required for ns charms
4069 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004070 else: # other types as script are not supported
4071 ee_list = []
4072
4073 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004074 self.logger.debug(
4075 logging_text
4076 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4077 ee_item.get("juju"), ee_item.get("helm-chart")
4078 )
4079 )
tiernoa278b842020-07-08 15:33:55 +00004080 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05004081 vca_name, charm_name, vca_type = self.get_vca_info(
4082 ee_item, db_nsr, get_charm_name
4083 )
4084 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004085 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004086 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004087 )
quilesj7e13aeb2019-10-08 13:34:55 +02004088 continue
quilesj3655ae02019-12-12 16:08:35 +00004089
tierno588547c2020-07-01 15:30:20 +00004090 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004091 for vca_index, vca_deployed in enumerate(
4092 db_nsr["_admin"]["deployed"]["VCA"]
4093 ):
tierno588547c2020-07-01 15:30:20 +00004094 if not vca_deployed:
4095 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004096 if (
4097 vca_deployed.get("member-vnf-index") == member_vnf_index
4098 and vca_deployed.get("vdu_id") == vdu_id
4099 and vca_deployed.get("kdu_name") == kdu_name
4100 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4101 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4102 ):
tierno588547c2020-07-01 15:30:20 +00004103 break
4104 else:
4105 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004106 target = (
4107 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4108 )
tiernoa278b842020-07-08 15:33:55 +00004109 if vdu_id:
4110 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4111 elif kdu_name:
4112 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004113 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004114 "target_element": target,
4115 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004116 "member-vnf-index": member_vnf_index,
4117 "vdu_id": vdu_id,
4118 "kdu_name": kdu_name,
4119 "vdu_count_index": vdu_index,
4120 "operational-status": "init", # TODO revise
4121 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004122 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004123 "vnfd_id": vnfd_id,
4124 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004125 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004126 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004127 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004128 }
4129 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004130
tierno588547c2020-07-01 15:30:20 +00004131 # create VCA and configurationStatus in db
4132 db_dict = {
4133 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004134 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004135 }
4136 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004137
tierno588547c2020-07-01 15:30:20 +00004138 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4139
bravof922c4172020-11-24 21:21:43 -03004140 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4141 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4142 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4143
tierno588547c2020-07-01 15:30:20 +00004144 # Launch task
4145 task_n2vc = asyncio.ensure_future(
4146 self.instantiate_N2VC(
4147 logging_text=logging_text,
4148 vca_index=vca_index,
4149 nsi_id=nsi_id,
4150 db_nsr=db_nsr,
4151 db_vnfr=db_vnfr,
4152 vdu_id=vdu_id,
4153 kdu_name=kdu_name,
4154 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004155 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004156 deploy_params=deploy_params,
4157 config_descriptor=descriptor_config,
4158 base_folder=base_folder,
4159 nslcmop_id=nslcmop_id,
4160 stage=stage,
4161 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004162 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004163 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004164 )
quilesj7e13aeb2019-10-08 13:34:55 +02004165 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004166 self.lcm_tasks.register(
4167 "ns",
4168 nsr_id,
4169 nslcmop_id,
4170 "instantiate_N2VC-{}".format(vca_index),
4171 task_n2vc,
4172 )
4173 task_instantiation_info[
4174 task_n2vc
4175 ] = self.task_name_deploy_vca + " {}.{}".format(
4176 member_vnf_index or "", vdu_id or ""
4177 )
tiernobaa51102018-12-14 13:16:18 +00004178
calvinosanch9f9c6f22019-11-04 13:37:39 +01004179 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004180 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004181 for key, value in params.items():
4182 if str(value).startswith("!!yaml "):
4183 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004184 return params
4185
kuuse8b998e42019-07-30 15:22:16 +02004186 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004187 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004188 primitive_params = {}
4189 params = {
4190 "member_vnf_index": vnf_index,
4191 "primitive": primitive,
4192 "primitive_params": primitive_params,
4193 }
4194 desc_params = {}
4195 return self._map_primitive_params(seq, params, desc_params)
4196
kuuseac3a8882019-10-03 10:48:06 +02004197 # sub-operations
4198
tierno51183952020-04-03 15:48:18 +00004199 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004200 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4201 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004202 # b. Skip sub-operation
4203 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4204 return self.SUBOPERATION_STATUS_SKIP
4205 else:
tierno7c4e24c2020-05-13 08:41:35 +00004206 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004207 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004208 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004209 operationState = "PROCESSING"
4210 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004211 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004212 db_nslcmop, op_index, operationState, detailed_status
4213 )
kuuseac3a8882019-10-03 10:48:06 +02004214 # Return the sub-operation index
4215 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4216 # with arguments extracted from the sub-operation
4217 return op_index
4218
4219 # Find a sub-operation where all keys in a matching dictionary must match
4220 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4221 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004222 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004223 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004224 for i, op in enumerate(op_list):
4225 if all(op.get(k) == match[k] for k in match):
4226 return i
4227 return self.SUBOPERATION_STATUS_NOT_FOUND
4228
4229 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004230 def _update_suboperation_status(
4231 self, db_nslcmop, op_index, operationState, detailed_status
4232 ):
kuuseac3a8882019-10-03 10:48:06 +02004233 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004234 q_filter = {"_id": db_nslcmop["_id"]}
4235 update_dict = {
4236 "_admin.operations.{}.operationState".format(op_index): operationState,
4237 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4238 }
4239 self.db.set_one(
4240 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4241 )
kuuseac3a8882019-10-03 10:48:06 +02004242
4243 # Add sub-operation, return the index of the added sub-operation
4244 # Optionally, set operationState, detailed-status, and operationType
4245 # Status and type are currently set for 'scale' sub-operations:
4246 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4247 # 'detailed-status' : status message
4248 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4249 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004250 def _add_suboperation(
4251 self,
4252 db_nslcmop,
4253 vnf_index,
4254 vdu_id,
4255 vdu_count_index,
4256 vdu_name,
4257 primitive,
4258 mapped_primitive_params,
4259 operationState=None,
4260 detailed_status=None,
4261 operationType=None,
4262 RO_nsr_id=None,
4263 RO_scaling_info=None,
4264 ):
tiernoe876f672020-02-13 14:34:48 +00004265 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004266 return self.SUBOPERATION_STATUS_NOT_FOUND
4267 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004268 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4269 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004270 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004271 new_op = {
4272 "member_vnf_index": vnf_index,
4273 "vdu_id": vdu_id,
4274 "vdu_count_index": vdu_count_index,
4275 "primitive": primitive,
4276 "primitive_params": mapped_primitive_params,
4277 }
kuuseac3a8882019-10-03 10:48:06 +02004278 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004279 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004280 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004281 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004282 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004283 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004284 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004285 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004286 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004287 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004288 if not op_list:
4289 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004290 db_nslcmop_admin.update({"operations": [new_op]})
4291 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004292 else:
4293 # Existing operations, append operation to list
4294 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004295
garciadeblas5697b8b2021-03-24 09:17:02 +01004296 db_nslcmop_update = {"_admin.operations": op_list}
4297 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004298 op_index = len(op_list) - 1
4299 return op_index
4300
4301 # Helper methods for scale() sub-operations
4302
4303 # pre-scale/post-scale:
4304 # Check for 3 different cases:
4305 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4306 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004307 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004308 def _check_or_add_scale_suboperation(
4309 self,
4310 db_nslcmop,
4311 vnf_index,
4312 vnf_config_primitive,
4313 primitive_params,
4314 operationType,
4315 RO_nsr_id=None,
4316 RO_scaling_info=None,
4317 ):
kuuseac3a8882019-10-03 10:48:06 +02004318 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004319 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004320 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004321 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004322 "member_vnf_index": vnf_index,
4323 "RO_nsr_id": RO_nsr_id,
4324 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004325 }
4326 else:
4327 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004328 "member_vnf_index": vnf_index,
4329 "primitive": vnf_config_primitive,
4330 "primitive_params": primitive_params,
4331 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004332 }
4333 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004334 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004335 # a. New sub-operation
4336 # The sub-operation does not exist, add it.
4337 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4338 # The following parameters are set to None for all kind of scaling:
4339 vdu_id = None
4340 vdu_count_index = None
4341 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004342 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004343 vnf_config_primitive = None
4344 primitive_params = None
4345 else:
4346 RO_nsr_id = None
4347 RO_scaling_info = None
4348 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004349 operationState = "PROCESSING"
4350 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004351 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004352 self._add_suboperation(
4353 db_nslcmop,
4354 vnf_index,
4355 vdu_id,
4356 vdu_count_index,
4357 vdu_name,
4358 vnf_config_primitive,
4359 primitive_params,
4360 operationState,
4361 detailed_status,
4362 operationType,
4363 RO_nsr_id,
4364 RO_scaling_info,
4365 )
kuuseac3a8882019-10-03 10:48:06 +02004366 return self.SUBOPERATION_STATUS_NEW
4367 else:
4368 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4369 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004370 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004371
preethika.pdf7d8e02019-12-10 13:10:48 +00004372 # Function to return execution_environment id
4373
David Garciac1fe90a2021-03-31 19:12:02 +02004374 async def destroy_N2VC(
4375 self,
4376 logging_text,
4377 db_nslcmop,
4378 vca_deployed,
4379 config_descriptor,
4380 vca_index,
4381 destroy_ee=True,
4382 exec_primitives=True,
4383 scaling_in=False,
4384 vca_id: str = None,
4385 ):
tiernoe876f672020-02-13 14:34:48 +00004386 """
4387 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4388 :param logging_text:
4389 :param db_nslcmop:
4390 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4391 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4392 :param vca_index: index in the database _admin.deployed.VCA
4393 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004394 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4395 not executed properly
aktas13251562021-02-12 22:19:10 +03004396 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004397 :return: None or exception
4398 """
tiernoe876f672020-02-13 14:34:48 +00004399
tierno588547c2020-07-01 15:30:20 +00004400 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004401 logging_text
4402 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004403 vca_index, vca_deployed, config_descriptor, destroy_ee
4404 )
4405 )
4406
4407 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4408
4409 # execute terminate_primitives
4410 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004411 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004412 config_descriptor.get("terminate-config-primitive"),
4413 vca_deployed.get("ee_descriptor_id"),
4414 )
tierno588547c2020-07-01 15:30:20 +00004415 vdu_id = vca_deployed.get("vdu_id")
4416 vdu_count_index = vca_deployed.get("vdu_count_index")
4417 vdu_name = vca_deployed.get("vdu_name")
4418 vnf_index = vca_deployed.get("member-vnf-index")
4419 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004420 for seq in terminate_primitives:
4421 # For each sequence in list, get primitive and call _ns_execute_primitive()
4422 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004423 vnf_index, seq.get("name")
4424 )
tierno588547c2020-07-01 15:30:20 +00004425 self.logger.debug(logging_text + step)
4426 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004427 primitive = seq.get("name")
4428 mapped_primitive_params = self._get_terminate_primitive_params(
4429 seq, vnf_index
4430 )
tierno588547c2020-07-01 15:30:20 +00004431
4432 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004433 self._add_suboperation(
4434 db_nslcmop,
4435 vnf_index,
4436 vdu_id,
4437 vdu_count_index,
4438 vdu_name,
4439 primitive,
4440 mapped_primitive_params,
4441 )
tierno588547c2020-07-01 15:30:20 +00004442 # Sub-operations: Call _ns_execute_primitive() instead of action()
4443 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004444 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004445 vca_deployed["ee_id"],
4446 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004447 mapped_primitive_params,
4448 vca_type=vca_type,
4449 vca_id=vca_id,
4450 )
tierno588547c2020-07-01 15:30:20 +00004451 except LcmException:
4452 # this happens when VCA is not deployed. In this case it is not needed to terminate
4453 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004454 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004455 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004456 raise LcmException(
4457 "terminate_primitive {} for vnf_member_index={} fails with "
4458 "error {}".format(seq.get("name"), vnf_index, result_detail)
4459 )
tierno588547c2020-07-01 15:30:20 +00004460 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004461 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4462 vca_index
4463 )
4464 self.update_db_2(
4465 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4466 )
tiernoe876f672020-02-13 14:34:48 +00004467
bravof73bac502021-05-11 07:38:47 -04004468 # Delete Prometheus Jobs if any
4469 # This uses NSR_ID, so it will destroy any jobs under this index
4470 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004471
tiernoe876f672020-02-13 14:34:48 +00004472 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004473 await self.vca_map[vca_type].delete_execution_environment(
4474 vca_deployed["ee_id"],
4475 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004476 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004477 vca_id=vca_id,
4478 )
kuuse0ca67472019-05-13 15:59:27 +02004479
David Garciac1fe90a2021-03-31 19:12:02 +02004480 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004481 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004482 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004483 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004484 await self.n2vc.delete_namespace(
4485 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004486 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004487 vca_id=vca_id,
4488 )
tiernof59ad6c2020-04-08 12:50:52 +00004489 except N2VCNotFound: # already deleted. Skip
4490 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004491 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004492
tiernoe876f672020-02-13 14:34:48 +00004493 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004494 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004495 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004496 if not task_is_locked_by_me:
4497 return
4498
tierno59d22d22018-09-25 18:10:19 +02004499 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4500 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004501 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004502 db_nsr = None
4503 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004504 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004505 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004506 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004507 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004508 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004509 tasks_dict_info = {}
4510 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004511 stage = [
4512 "Stage 1/3: Preparing task.",
4513 "Waiting for previous operations to terminate.",
4514 "",
4515 ]
tiernoe876f672020-02-13 14:34:48 +00004516 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004517 try:
kuused124bfe2019-06-18 12:09:24 +02004518 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004519 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004520
tiernoe876f672020-02-13 14:34:48 +00004521 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4522 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4523 operation_params = db_nslcmop.get("operationParams") or {}
4524 if operation_params.get("timeout_ns_terminate"):
4525 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4526 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4527 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4528
4529 db_nsr_update["operational-status"] = "terminating"
4530 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004531 self._write_ns_status(
4532 nsr_id=nsr_id,
4533 ns_state="TERMINATING",
4534 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004535 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004536 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004537 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004538 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004539 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004540 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4541 return
tierno59d22d22018-09-25 18:10:19 +02004542
tiernoe876f672020-02-13 14:34:48 +00004543 stage[1] = "Getting vnf descriptors from db."
4544 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004545 db_vnfrs_dict = {
4546 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4547 }
tiernoe876f672020-02-13 14:34:48 +00004548 db_vnfds_from_id = {}
4549 db_vnfds_from_member_index = {}
4550 # Loop over VNFRs
4551 for vnfr in db_vnfrs_list:
4552 vnfd_id = vnfr["vnfd-id"]
4553 if vnfd_id not in db_vnfds_from_id:
4554 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4555 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004556 db_vnfds_from_member_index[
4557 vnfr["member-vnf-index-ref"]
4558 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004559
tiernoe876f672020-02-13 14:34:48 +00004560 # Destroy individual execution environments when there are terminating primitives.
4561 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004562 # TODO - check before calling _destroy_N2VC
4563 # if not operation_params.get("skip_terminate_primitives"):#
4564 # or not vca.get("needed_terminate"):
4565 stage[0] = "Stage 2/3 execute terminating primitives."
4566 self.logger.debug(logging_text + stage[0])
4567 stage[1] = "Looking execution environment that needs terminate."
4568 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004569
tierno588547c2020-07-01 15:30:20 +00004570 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004571 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004572 vca_member_vnf_index = vca.get("member-vnf-index")
4573 vca_id = self.get_vca_id(
4574 db_vnfrs_dict.get(vca_member_vnf_index)
4575 if vca_member_vnf_index
4576 else None,
4577 db_nsr,
4578 )
tierno588547c2020-07-01 15:30:20 +00004579 if not vca or not vca.get("ee_id"):
4580 continue
4581 if not vca.get("member-vnf-index"):
4582 # ns
4583 config_descriptor = db_nsr.get("ns-configuration")
4584 elif vca.get("vdu_id"):
4585 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004586 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004587 elif vca.get("kdu_name"):
4588 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004589 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004590 else:
bravofe5a31bc2021-02-17 19:09:12 -03004591 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004592 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004593 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004594 exec_terminate_primitives = not operation_params.get(
4595 "skip_terminate_primitives"
4596 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004597 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4598 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004599 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004600 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4601 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004602 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004603 self.destroy_N2VC(
4604 logging_text,
4605 db_nslcmop,
4606 vca,
4607 config_descriptor,
4608 vca_index,
4609 destroy_ee,
4610 exec_terminate_primitives,
4611 vca_id=vca_id,
4612 )
4613 )
tierno588547c2020-07-01 15:30:20 +00004614 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004615
tierno588547c2020-07-01 15:30:20 +00004616 # wait for pending tasks of terminate primitives
4617 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004618 self.logger.debug(
4619 logging_text
4620 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4621 )
4622 error_list = await self._wait_for_tasks(
4623 logging_text,
4624 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004625 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004626 stage,
4627 nslcmop_id,
4628 )
tierno86e33612020-09-16 14:13:06 +00004629 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004630 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004631 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004632
tiernoe876f672020-02-13 14:34:48 +00004633 # remove All execution environments at once
4634 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004635
tierno49676be2020-04-07 16:34:35 +00004636 if nsr_deployed.get("VCA"):
4637 stage[1] = "Deleting all execution environments."
4638 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004639 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4640 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004641 # Delete Namespace and Certificates
4642 await self.vca_map["helm-v3"].delete_tls_certificate(
4643 namespace=db_nslcmop["nsInstanceId"],
4644 certificate_name=self.EE_TLS_NAME,
4645 )
4646 await self.vca_map["helm-v3"].delete_namespace(
4647 namespace=db_nslcmop["nsInstanceId"],
4648 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004649 else:
4650 vca_id = self.get_vca_id({}, db_nsr)
4651 task_delete_ee = asyncio.ensure_future(
4652 asyncio.wait_for(
4653 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4654 timeout=self.timeout.charm_delete,
4655 )
4656 )
4657 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004658
tiernoe876f672020-02-13 14:34:48 +00004659 # Delete from k8scluster
4660 stage[1] = "Deleting KDUs."
4661 self.logger.debug(logging_text + stage[1])
4662 # print(nsr_deployed)
4663 for kdu in get_iterable(nsr_deployed, "K8s"):
4664 if not kdu or not kdu.get("kdu-instance"):
4665 continue
4666 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004667 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004668 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4669 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004670 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004671 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4672 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004673 kdu_instance=kdu_instance,
4674 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004675 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004676 )
4677 )
tiernoe876f672020-02-13 14:34:48 +00004678 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004679 self.logger.error(
4680 logging_text
4681 + "Unknown k8s deployment type {}".format(
4682 kdu.get("k8scluster-type")
4683 )
4684 )
tiernoe876f672020-02-13 14:34:48 +00004685 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004686 tasks_dict_info[
4687 task_delete_kdu_instance
4688 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004689
4690 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004691 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004692 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004693 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004694 self._terminate_ng_ro(
4695 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4696 )
4697 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004698 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004699
tiernoe876f672020-02-13 14:34:48 +00004700 # rest of staff will be done at finally
4701
garciadeblas5697b8b2021-03-24 09:17:02 +01004702 except (
4703 ROclient.ROClientException,
4704 DbException,
4705 LcmException,
4706 N2VCException,
4707 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004708 self.logger.error(logging_text + "Exit Exception {}".format(e))
4709 exc = e
4710 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004711 self.logger.error(
4712 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4713 )
tiernoe876f672020-02-13 14:34:48 +00004714 exc = "Operation was cancelled"
4715 except Exception as e:
4716 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004717 self.logger.critical(
4718 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4719 exc_info=True,
4720 )
tiernoe876f672020-02-13 14:34:48 +00004721 finally:
4722 if exc:
4723 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004724 try:
tiernoe876f672020-02-13 14:34:48 +00004725 # wait for pending tasks
4726 if tasks_dict_info:
4727 stage[1] = "Waiting for terminate pending tasks."
4728 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004729 error_list += await self._wait_for_tasks(
4730 logging_text,
4731 tasks_dict_info,
4732 timeout_ns_terminate,
4733 stage,
4734 nslcmop_id,
4735 )
tiernoe876f672020-02-13 14:34:48 +00004736 stage[1] = stage[2] = ""
4737 except asyncio.CancelledError:
4738 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004739 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4740 await self._wait_for_tasks(
4741 logging_text,
4742 tasks_dict_info,
4743 timeout_ns_terminate,
4744 stage,
4745 nslcmop_id,
4746 )
tiernoe876f672020-02-13 14:34:48 +00004747 except Exception as exc:
4748 error_list.append(str(exc))
4749 # update status at database
4750 if error_list:
4751 error_detail = "; ".join(error_list)
4752 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004753 error_description_nslcmop = "{} Detail: {}".format(
4754 stage[0], error_detail
4755 )
4756 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4757 nslcmop_id, stage[0]
4758 )
tierno59d22d22018-09-25 18:10:19 +02004759
tierno59d22d22018-09-25 18:10:19 +02004760 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004761 db_nsr_update["detailed-status"] = (
4762 error_description_nsr + " Detail: " + error_detail
4763 )
tiernoe876f672020-02-13 14:34:48 +00004764 db_nslcmop_update["detailed-status"] = error_detail
4765 nslcmop_operation_state = "FAILED"
4766 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004767 else:
tiernoa2143262020-03-27 16:20:40 +00004768 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004769 error_description_nsr = error_description_nslcmop = None
4770 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004771 db_nsr_update["operational-status"] = "terminated"
4772 db_nsr_update["detailed-status"] = "Done"
4773 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4774 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004775 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004776
tiernoe876f672020-02-13 14:34:48 +00004777 if db_nsr:
4778 self._write_ns_status(
4779 nsr_id=nsr_id,
4780 ns_state=ns_state,
4781 current_operation="IDLE",
4782 current_operation_id=None,
4783 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004784 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004785 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004786 )
tiernoa17d4f42020-04-28 09:59:23 +00004787 self._write_op_status(
4788 op_id=nslcmop_id,
4789 stage="",
4790 error_message=error_description_nslcmop,
4791 operation_state=nslcmop_operation_state,
4792 other_update=db_nslcmop_update,
4793 )
Rahul Kumar54671c52024-05-09 15:34:01 +05304794 if nslcmop_operation_state == "COMPLETED":
4795 self.db.del_list("prometheus_jobs", {"nsr_id": nsr_id})
lloretgalleg6d488782020-07-22 10:13:46 +00004796 if ns_state == "NOT_INSTANTIATED":
4797 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004798 self.db.set_list(
4799 "vnfrs",
4800 {"nsr-id-ref": nsr_id},
4801 {"_admin.nsState": "NOT_INSTANTIATED"},
4802 )
lloretgalleg6d488782020-07-22 10:13:46 +00004803 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004804 self.logger.warn(
4805 logging_text
4806 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4807 nsr_id, e
4808 )
4809 )
tiernoa17d4f42020-04-28 09:59:23 +00004810 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004811 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004812 if nslcmop_operation_state:
4813 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004814 await self.msg.aiowrite(
4815 "ns",
4816 "terminated",
4817 {
4818 "nsr_id": nsr_id,
4819 "nslcmop_id": nslcmop_id,
4820 "operationState": nslcmop_operation_state,
4821 "autoremove": autoremove,
4822 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004823 )
tierno59d22d22018-09-25 18:10:19 +02004824 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004825 self.logger.error(
4826 logging_text + "kafka_write notification Exception {}".format(e)
4827 )
aguilard1ae3c562023-02-16 17:24:35 +00004828 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4829 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004830
tierno59d22d22018-09-25 18:10:19 +02004831 self.logger.debug(logging_text + "Exit")
4832 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4833
garciadeblas5697b8b2021-03-24 09:17:02 +01004834 async def _wait_for_tasks(
4835 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4836 ):
tiernoe876f672020-02-13 14:34:48 +00004837 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004838 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004839 error_list = []
4840 pending_tasks = list(created_tasks_info.keys())
4841 num_tasks = len(pending_tasks)
4842 num_done = 0
4843 stage[1] = "{}/{}.".format(num_done, num_tasks)
4844 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004845 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004846 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004847 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004848 done, pending_tasks = await asyncio.wait(
4849 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4850 )
tiernoe876f672020-02-13 14:34:48 +00004851 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004852 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004853 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004854 new_error = created_tasks_info[task] + ": Timeout"
4855 error_detail_list.append(new_error)
4856 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004857 break
4858 for task in done:
4859 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004860 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004861 else:
4862 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004863 if exc:
4864 if isinstance(exc, asyncio.TimeoutError):
4865 exc = "Timeout"
4866 new_error = created_tasks_info[task] + ": {}".format(exc)
4867 error_list.append(created_tasks_info[task])
4868 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004869 if isinstance(
4870 exc,
4871 (
4872 str,
4873 DbException,
4874 N2VCException,
4875 ROclient.ROClientException,
4876 LcmException,
4877 K8sException,
4878 NgRoException,
4879 ),
4880 ):
tierno067e04a2020-03-31 12:53:13 +00004881 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004882 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004883 exc_traceback = "".join(
4884 traceback.format_exception(None, exc, exc.__traceback__)
4885 )
4886 self.logger.error(
4887 logging_text
4888 + created_tasks_info[task]
4889 + " "
4890 + exc_traceback
4891 )
tierno067e04a2020-03-31 12:53:13 +00004892 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004893 self.logger.debug(
4894 logging_text + created_tasks_info[task] + ": Done"
4895 )
tiernoe876f672020-02-13 14:34:48 +00004896 stage[1] = "{}/{}.".format(num_done, num_tasks)
4897 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004898 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004899 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004900 self.update_db_2(
4901 "nsrs",
4902 nsr_id,
4903 {
4904 "errorDescription": "Error at: " + ", ".join(error_list),
4905 "errorDetail": ". ".join(error_detail_list),
4906 },
4907 )
tiernoe876f672020-02-13 14:34:48 +00004908 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004909 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004910
Gabriel Cubab6049d32023-10-30 13:44:49 -05004911 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4912 for task, name in created_tasks_info.items():
4913 self.logger.debug(logging_text + "Cancelling task: " + name)
4914 task.cancel()
4915
tiernoda1ff8c2020-10-22 14:12:46 +00004916 @staticmethod
4917 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004918 """
4919 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4920 The default-value is used. If it is between < > it look for a value at instantiation_params
4921 :param primitive_desc: portion of VNFD/NSD that describes primitive
4922 :param params: Params provided by user
4923 :param instantiation_params: Instantiation params provided by user
4924 :return: a dictionary with the calculated params
4925 """
4926 calculated_params = {}
4927 for parameter in primitive_desc.get("parameter", ()):
4928 param_name = parameter["name"]
4929 if param_name in params:
4930 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004931 elif "default-value" in parameter or "value" in parameter:
4932 if "value" in parameter:
4933 calculated_params[param_name] = parameter["value"]
4934 else:
4935 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004936 if (
4937 isinstance(calculated_params[param_name], str)
4938 and calculated_params[param_name].startswith("<")
4939 and calculated_params[param_name].endswith(">")
4940 ):
tierno98ad6ea2019-05-30 17:16:28 +00004941 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004942 calculated_params[param_name] = instantiation_params[
4943 calculated_params[param_name][1:-1]
4944 ]
tiernoda964822019-01-14 15:53:47 +00004945 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004946 raise LcmException(
4947 "Parameter {} needed to execute primitive {} not provided".format(
4948 calculated_params[param_name], primitive_desc["name"]
4949 )
4950 )
tiernoda964822019-01-14 15:53:47 +00004951 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004952 raise LcmException(
4953 "Parameter {} needed to execute primitive {} not provided".format(
4954 param_name, primitive_desc["name"]
4955 )
4956 )
tierno59d22d22018-09-25 18:10:19 +02004957
tiernoda964822019-01-14 15:53:47 +00004958 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004959 calculated_params[param_name] = yaml.safe_dump(
4960 calculated_params[param_name], default_flow_style=True, width=256
4961 )
4962 elif isinstance(calculated_params[param_name], str) and calculated_params[
4963 param_name
4964 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004965 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004966 if parameter.get("data-type") == "INTEGER":
4967 try:
4968 calculated_params[param_name] = int(calculated_params[param_name])
4969 except ValueError: # error converting string to int
4970 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004971 "Parameter {} of primitive {} must be integer".format(
4972 param_name, primitive_desc["name"]
4973 )
4974 )
tiernofa40e692020-10-14 14:59:36 +00004975 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004976 calculated_params[param_name] = not (
4977 (str(calculated_params[param_name])).lower() == "false"
4978 )
tiernoc3f2a822019-11-05 13:45:04 +00004979
4980 # add always ns_config_info if primitive name is config
4981 if primitive_desc["name"] == "config":
4982 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004983 calculated_params["ns_config_info"] = instantiation_params[
4984 "ns_config_info"
4985 ]
tiernoda964822019-01-14 15:53:47 +00004986 return calculated_params
4987
garciadeblas5697b8b2021-03-24 09:17:02 +01004988 def _look_for_deployed_vca(
4989 self,
4990 deployed_vca,
4991 member_vnf_index,
4992 vdu_id,
4993 vdu_count_index,
4994 kdu_name=None,
4995 ee_descriptor_id=None,
4996 ):
tiernoe876f672020-02-13 14:34:48 +00004997 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4998 for vca in deployed_vca:
4999 if not vca:
5000 continue
5001 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
5002 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01005003 if (
5004 vdu_count_index is not None
5005 and vdu_count_index != vca["vdu_count_index"]
5006 ):
tiernoe876f672020-02-13 14:34:48 +00005007 continue
5008 if kdu_name and kdu_name != vca["kdu_name"]:
5009 continue
tiernoa278b842020-07-08 15:33:55 +00005010 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
5011 continue
tiernoe876f672020-02-13 14:34:48 +00005012 break
5013 else:
5014 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01005015 raise LcmException(
5016 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
5017 " is not deployed".format(
5018 member_vnf_index,
5019 vdu_id,
5020 vdu_count_index,
5021 kdu_name,
5022 ee_descriptor_id,
5023 )
5024 )
tiernoe876f672020-02-13 14:34:48 +00005025 # get ee_id
5026 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01005027 vca_type = vca.get(
5028 "type", "lxc_proxy_charm"
5029 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00005030 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005031 raise LcmException(
5032 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
5033 "execution environment".format(
5034 member_vnf_index, vdu_id, kdu_name, vdu_count_index
5035 )
5036 )
tierno588547c2020-07-01 15:30:20 +00005037 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00005038
David Garciac1fe90a2021-03-31 19:12:02 +02005039 async def _ns_execute_primitive(
5040 self,
5041 ee_id,
5042 primitive,
5043 primitive_params,
5044 retries=0,
5045 retries_interval=30,
5046 timeout=None,
5047 vca_type=None,
5048 db_dict=None,
5049 vca_id: str = None,
5050 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005051 try:
tierno98ad6ea2019-05-30 17:16:28 +00005052 if primitive == "config":
5053 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005054
tierno588547c2020-07-01 15:30:20 +00005055 vca_type = vca_type or "lxc_proxy_charm"
5056
quilesj7e13aeb2019-10-08 13:34:55 +02005057 while retries >= 0:
5058 try:
tierno067e04a2020-03-31 12:53:13 +00005059 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005060 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005061 ee_id=ee_id,
5062 primitive_name=primitive,
5063 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005064 progress_timeout=self.timeout.progress_primitive,
5065 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005066 db_dict=db_dict,
5067 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005068 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005069 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005070 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005071 )
quilesj7e13aeb2019-10-08 13:34:55 +02005072 # execution was OK
5073 break
tierno067e04a2020-03-31 12:53:13 +00005074 except asyncio.CancelledError:
5075 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005076 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005077 retries -= 1
5078 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005079 self.logger.debug(
5080 "Error executing action {} on {} -> {}".format(
5081 primitive, ee_id, e
5082 )
5083 )
quilesj7e13aeb2019-10-08 13:34:55 +02005084 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005085 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005086 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005087 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005088 e = N2VCException(
5089 message="Timed out waiting for action to complete"
5090 )
5091 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005092
garciadeblas5697b8b2021-03-24 09:17:02 +01005093 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005094
tierno067e04a2020-03-31 12:53:13 +00005095 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005096 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005097 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005098 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005099
ksaikiranr3fde2c72021-03-15 10:39:06 +05305100 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5101 """
5102 Updating the vca_status with latest juju information in nsrs record
5103 :param: nsr_id: Id of the nsr
5104 :param: nslcmop_id: Id of the nslcmop
5105 :return: None
5106 """
5107
5108 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5109 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005110 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005111 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005112 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5113 cluster_uuid, kdu_instance, cluster_type = (
5114 k8s["k8scluster-uuid"],
5115 k8s["kdu-instance"],
5116 k8s["k8scluster-type"],
5117 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005118 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005119 cluster_uuid=cluster_uuid,
5120 kdu_instance=kdu_instance,
5121 filter={"_id": nsr_id},
5122 vca_id=vca_id,
5123 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005124 )
3697083243632024-06-07 05:44:08 +00005125 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005126 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305127 table, filter = "nsrs", {"_id": nsr_id}
5128 path = "_admin.deployed.VCA.{}.".format(vca_index)
5129 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305130
5131 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5132 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5133
tierno59d22d22018-09-25 18:10:19 +02005134 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005135 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005136 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005137 if not task_is_locked_by_me:
5138 return
5139
tierno59d22d22018-09-25 18:10:19 +02005140 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5141 self.logger.debug(logging_text + "Enter")
5142 # get all needed from database
5143 db_nsr = None
5144 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005145 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005146 db_nslcmop_update = {}
5147 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005148 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005149 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005150 step = ""
tierno59d22d22018-09-25 18:10:19 +02005151 try:
kuused124bfe2019-06-18 12:09:24 +02005152 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005153 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005154 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005155
quilesj4cda56b2019-12-05 10:02:20 +00005156 self._write_ns_status(
5157 nsr_id=nsr_id,
5158 ns_state=None,
5159 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005160 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005161 )
5162
tierno59d22d22018-09-25 18:10:19 +02005163 step = "Getting information from database"
5164 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5165 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005166 if db_nslcmop["operationParams"].get("primitive_params"):
5167 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5168 db_nslcmop["operationParams"]["primitive_params"]
5169 )
tiernoda964822019-01-14 15:53:47 +00005170
tiernoe4f7e6c2018-11-27 14:55:30 +00005171 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005172 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005173 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005174 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005175 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005176 primitive = db_nslcmop["operationParams"]["primitive"]
5177 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005178 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005179 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005180 )
tierno59d22d22018-09-25 18:10:19 +02005181
tierno1b633412019-02-25 16:48:23 +00005182 if vnf_index:
5183 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005184 db_vnfr = self.db.get_one(
5185 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5186 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005187 if db_vnfr.get("kdur"):
5188 kdur_list = []
5189 for kdur in db_vnfr["kdur"]:
5190 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005191 kdur["additionalParams"] = json.loads(
5192 kdur["additionalParams"]
5193 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005194 kdur_list.append(kdur)
5195 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005196 step = "Getting vnfd from database"
5197 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005198
5199 # Sync filesystem before running a primitive
5200 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005201 else:
tierno067e04a2020-03-31 12:53:13 +00005202 step = "Getting nsd from database"
5203 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005204
David Garciac1fe90a2021-03-31 19:12:02 +02005205 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005206 # for backward compatibility
5207 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5208 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5209 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5210 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5211
tiernoda964822019-01-14 15:53:47 +00005212 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005213 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005214 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005215 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005216 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005217 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005218 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005219 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005220 else:
tiernoa278b842020-07-08 15:33:55 +00005221 descriptor_configuration = db_nsd.get("ns-configuration")
5222
garciadeblas5697b8b2021-03-24 09:17:02 +01005223 if descriptor_configuration and descriptor_configuration.get(
5224 "config-primitive"
5225 ):
tiernoa278b842020-07-08 15:33:55 +00005226 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005227 if config_primitive["name"] == primitive:
5228 config_primitive_desc = config_primitive
5229 break
tiernoda964822019-01-14 15:53:47 +00005230
garciadeblas6bed6b32020-07-20 11:05:42 +00005231 if not config_primitive_desc:
5232 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005233 raise LcmException(
5234 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5235 primitive
5236 )
5237 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005238 primitive_name = primitive
5239 ee_descriptor_id = None
5240 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005241 primitive_name = config_primitive_desc.get(
5242 "execution-environment-primitive", primitive
5243 )
5244 ee_descriptor_id = config_primitive_desc.get(
5245 "execution-environment-ref"
5246 )
tierno1b633412019-02-25 16:48:23 +00005247
tierno1b633412019-02-25 16:48:23 +00005248 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005249 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005250 vdur = next(
5251 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5252 )
bravof922c4172020-11-24 21:21:43 -03005253 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005254 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005255 kdur = next(
5256 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5257 )
bravof922c4172020-11-24 21:21:43 -03005258 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005259 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005260 desc_params = parse_yaml_strings(
5261 db_vnfr.get("additionalParamsForVnf")
5262 )
tierno1b633412019-02-25 16:48:23 +00005263 else:
bravof922c4172020-11-24 21:21:43 -03005264 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005265 if kdu_name and get_configuration(db_vnfd, kdu_name):
5266 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005267 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005268 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005269 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005270 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005271 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005272 kdu = find_in_list(
5273 nsr_deployed["K8s"],
5274 lambda kdu: kdu_name == kdu["kdu-name"]
5275 and kdu["member-vnf-index"] == vnf_index,
5276 )
5277 kdu_action = (
5278 True
5279 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005280 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005281 else False
5282 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005283
tiernoda964822019-01-14 15:53:47 +00005284 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005285 if kdu_name and (
5286 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5287 ):
tierno067e04a2020-03-31 12:53:13 +00005288 # TODO Check if we will need something at vnf level
5289 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005290 if (
5291 kdu_name == kdu["kdu-name"]
5292 and kdu["member-vnf-index"] == vnf_index
5293 ):
tierno067e04a2020-03-31 12:53:13 +00005294 break
5295 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005296 raise LcmException(
5297 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5298 )
quilesj7e13aeb2019-10-08 13:34:55 +02005299
tierno067e04a2020-03-31 12:53:13 +00005300 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005301 msg = "unknown k8scluster-type '{}'".format(
5302 kdu.get("k8scluster-type")
5303 )
tierno067e04a2020-03-31 12:53:13 +00005304 raise LcmException(msg)
5305
garciadeblas5697b8b2021-03-24 09:17:02 +01005306 db_dict = {
5307 "collection": "nsrs",
5308 "filter": {"_id": nsr_id},
5309 "path": "_admin.deployed.K8s.{}".format(index),
5310 }
5311 self.logger.debug(
5312 logging_text
5313 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5314 )
tiernoa278b842020-07-08 15:33:55 +00005315 step = "Executing kdu {}".format(primitive_name)
garciadeblas8eb84d52024-07-19 12:08:07 +02005316 if primitive_name == "upgrade" and primitive_params:
5317 if primitive_params.get("kdu_model"):
5318 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005319 else:
5320 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005321 if kdu_model.count("/") < 2: # helm chart is not embedded
5322 parts = kdu_model.split(sep=":")
5323 if len(parts) == 2:
5324 kdu_model = parts[0]
garciadeblas8eb84d52024-07-19 12:08:07 +02005325 if primitive_params.get("kdu_atomic_upgrade"):
5326 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005327 "kdu_atomic_upgrade"
5328 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005329 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005330 else:
5331 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005332 # Type of upgrade: reset, reuse, reset_then_reuse
5333 reset_values = False
5334 reuse_values = False
5335 reset_then_reuse_values = False
5336 # If no option is specified, default behaviour is reuse_values
5337 # Otherwise, options will be parsed and used
5338 if (
garciadeblas8eb84d52024-07-19 12:08:07 +02005339 ("kdu_reset_values" not in primitive_params)
5340 and ("kdu_reuse_values" not in primitive_params)
5341 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasb891d382024-02-08 14:11:51 +01005342 ):
5343 reuse_values = True
5344 else:
garciadeblas8eb84d52024-07-19 12:08:07 +02005345 if primitive_params.get("kdu_reset_values"):
5346 reset_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005347 "kdu_reset_values"
5348 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005349 if primitive_params.get("kdu_reuse_values"):
5350 reuse_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005351 "kdu_reuse_values"
5352 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005353 if primitive_params.get("kdu_reset_then_reuse_values"):
5354 reset_then_reuse_values = primitive_params.get(
garciadeblasb891d382024-02-08 14:11:51 +01005355 "kdu_reset_then_reuse_values"
5356 ).lower() in ("yes", "true", "1")
5357 # Two true options are not possible
5358 if (
5359 sum([reset_values, reuse_values, reset_then_reuse_values])
5360 >= 2
5361 ):
5362 raise LcmException(
5363 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5364 )
garciadeblas8eb84d52024-07-19 12:08:07 +02005365 # kdur and desc_params already set from before
5366 if reset_values:
5367 desc_params = primitive_params
5368 else:
5369 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005370 detailed_status = await asyncio.wait_for(
5371 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5372 cluster_uuid=kdu.get("k8scluster-uuid"),
5373 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005374 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005375 reset_values=reset_values,
5376 reuse_values=reuse_values,
5377 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005378 kdu_model=kdu_model,
5379 params=desc_params,
5380 db_dict=db_dict,
5381 timeout=timeout_ns_action,
5382 ),
5383 timeout=timeout_ns_action + 10,
5384 )
5385 self.logger.debug(
5386 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5387 )
tiernoa278b842020-07-08 15:33:55 +00005388 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005389 detailed_status = await asyncio.wait_for(
5390 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5391 cluster_uuid=kdu.get("k8scluster-uuid"),
5392 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005393 db_dict=db_dict,
5394 ),
5395 timeout=timeout_ns_action,
5396 )
tiernoa278b842020-07-08 15:33:55 +00005397 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005398 detailed_status = await asyncio.wait_for(
5399 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5400 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005401 kdu_instance=kdu.get("kdu-instance"),
5402 vca_id=vca_id,
5403 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005404 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005405 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005406 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005407 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5408 kdu["kdu-name"], nsr_id
5409 )
5410 params = self._map_primitive_params(
5411 config_primitive_desc, primitive_params, desc_params
5412 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005413
5414 detailed_status = await asyncio.wait_for(
5415 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5416 cluster_uuid=kdu.get("k8scluster-uuid"),
5417 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005418 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005419 params=params,
5420 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005421 timeout=timeout_ns_action,
5422 vca_id=vca_id,
5423 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005424 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005425 )
tierno067e04a2020-03-31 12:53:13 +00005426
5427 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005428 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005429 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005430 detailed_status = ""
5431 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005432 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005433 ee_id, vca_type = self._look_for_deployed_vca(
5434 nsr_deployed["VCA"],
5435 member_vnf_index=vnf_index,
5436 vdu_id=vdu_id,
5437 vdu_count_index=vdu_count_index,
5438 ee_descriptor_id=ee_descriptor_id,
5439 )
5440 for vca_index, vca_deployed in enumerate(
5441 db_nsr["_admin"]["deployed"]["VCA"]
5442 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305443 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005444 db_dict = {
5445 "collection": "nsrs",
5446 "filter": {"_id": nsr_id},
5447 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5448 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305449 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005450 (
5451 nslcmop_operation_state,
5452 detailed_status,
5453 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005454 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005455 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005456 primitive_params=self._map_primitive_params(
5457 config_primitive_desc, primitive_params, desc_params
5458 ),
tierno588547c2020-07-01 15:30:20 +00005459 timeout=timeout_ns_action,
5460 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005461 db_dict=db_dict,
5462 vca_id=vca_id,
5463 )
tierno067e04a2020-03-31 12:53:13 +00005464
5465 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005466 error_description_nslcmop = (
5467 detailed_status if nslcmop_operation_state == "FAILED" else ""
5468 )
5469 self.logger.debug(
5470 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005471 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005472 nslcmop_operation_state, detailed_status
5473 )
5474 )
tierno59d22d22018-09-25 18:10:19 +02005475 return # database update is called inside finally
5476
tiernof59ad6c2020-04-08 12:50:52 +00005477 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005478 self.logger.error(logging_text + "Exit Exception {}".format(e))
5479 exc = e
5480 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005481 self.logger.error(
5482 logging_text + "Cancelled Exception while '{}'".format(step)
5483 )
tierno59d22d22018-09-25 18:10:19 +02005484 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005485 except asyncio.TimeoutError:
5486 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5487 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005488 except Exception as e:
5489 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005490 self.logger.critical(
5491 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5492 exc_info=True,
5493 )
tierno59d22d22018-09-25 18:10:19 +02005494 finally:
tierno067e04a2020-03-31 12:53:13 +00005495 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005496 db_nslcmop_update[
5497 "detailed-status"
5498 ] = (
5499 detailed_status
5500 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005501 nslcmop_operation_state = "FAILED"
5502 if db_nsr:
5503 self._write_ns_status(
5504 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005505 ns_state=db_nsr[
5506 "nsState"
5507 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005508 current_operation="IDLE",
5509 current_operation_id=None,
5510 # error_description=error_description_nsr,
5511 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005512 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005513 )
5514
garciadeblas5697b8b2021-03-24 09:17:02 +01005515 self._write_op_status(
5516 op_id=nslcmop_id,
5517 stage="",
5518 error_message=error_description_nslcmop,
5519 operation_state=nslcmop_operation_state,
5520 other_update=db_nslcmop_update,
5521 )
tierno067e04a2020-03-31 12:53:13 +00005522
tierno59d22d22018-09-25 18:10:19 +02005523 if nslcmop_operation_state:
5524 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005525 await self.msg.aiowrite(
5526 "ns",
5527 "actioned",
5528 {
5529 "nsr_id": nsr_id,
5530 "nslcmop_id": nslcmop_id,
5531 "operationState": nslcmop_operation_state,
5532 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005533 )
tierno59d22d22018-09-25 18:10:19 +02005534 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005535 self.logger.error(
5536 logging_text + "kafka_write notification Exception {}".format(e)
5537 )
tierno59d22d22018-09-25 18:10:19 +02005538 self.logger.debug(logging_text + "Exit")
5539 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005540 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005541
elumalaica7ece02022-04-12 12:47:32 +05305542 async def terminate_vdus(
5543 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5544 ):
5545 """This method terminates VDUs
5546
5547 Args:
5548 db_vnfr: VNF instance record
5549 member_vnf_index: VNF index to identify the VDUs to be removed
5550 db_nsr: NS instance record
5551 update_db_nslcmops: Nslcmop update record
5552 """
5553 vca_scaling_info = []
5554 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5555 scaling_info["scaling_direction"] = "IN"
5556 scaling_info["vdu-delete"] = {}
5557 scaling_info["kdu-delete"] = {}
5558 db_vdur = db_vnfr.get("vdur")
5559 vdur_list = copy(db_vdur)
5560 count_index = 0
5561 for index, vdu in enumerate(vdur_list):
5562 vca_scaling_info.append(
5563 {
5564 "osm_vdu_id": vdu["vdu-id-ref"],
5565 "member-vnf-index": member_vnf_index,
5566 "type": "delete",
5567 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005568 }
5569 )
elumalaica7ece02022-04-12 12:47:32 +05305570 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5571 scaling_info["vdu"].append(
5572 {
5573 "name": vdu.get("name") or vdu.get("vdu-name"),
5574 "vdu_id": vdu["vdu-id-ref"],
5575 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005576 }
5577 )
elumalaica7ece02022-04-12 12:47:32 +05305578 for interface in vdu["interfaces"]:
5579 scaling_info["vdu"][index]["interface"].append(
5580 {
5581 "name": interface["name"],
5582 "ip_address": interface["ip-address"],
5583 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005584 }
5585 )
elumalaica7ece02022-04-12 12:47:32 +05305586 self.logger.info("NS update scaling info{}".format(scaling_info))
5587 stage[2] = "Terminating VDUs"
5588 if scaling_info.get("vdu-delete"):
5589 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005590 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305591 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005592 logging_text,
5593 db_nsr,
5594 update_db_nslcmops,
5595 db_vnfr,
5596 scaling_info,
5597 stage,
elumalaica7ece02022-04-12 12:47:32 +05305598 )
5599
preethika.p28b0bf82022-09-23 07:36:28 +00005600 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305601 """This method is to Remove VNF instances from NS.
5602
5603 Args:
5604 nsr_id: NS instance id
5605 nslcmop_id: nslcmop id of update
5606 vnf_instance_id: id of the VNF instance to be removed
5607
5608 Returns:
5609 result: (str, str) COMPLETED/FAILED, details
5610 """
5611 try:
5612 db_nsr_update = {}
5613 logging_text = "Task ns={} update ".format(nsr_id)
5614 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5615 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5616 if check_vnfr_count > 1:
5617 stage = ["", "", ""]
5618 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005619 self.logger.debug(
5620 step + " after having waited for previous tasks to be completed"
5621 )
elumalaica7ece02022-04-12 12:47:32 +05305622 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5623 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5624 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5625 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5626 """ db_vnfr = self.db.get_one(
5627 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5628
5629 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005630 await self.terminate_vdus(
5631 db_vnfr,
5632 member_vnf_index,
5633 db_nsr,
5634 update_db_nslcmops,
5635 stage,
5636 logging_text,
5637 )
elumalaica7ece02022-04-12 12:47:32 +05305638
5639 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5640 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005641 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5642 "constituent-vnfr-ref"
5643 )
elumalaica7ece02022-04-12 12:47:32 +05305644 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5645 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5646 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5647 return "COMPLETED", "Done"
5648 else:
5649 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005650 raise LcmException(
5651 "{} Cannot terminate the last VNF in this NS.".format(
5652 vnf_instance_id
5653 )
5654 )
elumalaica7ece02022-04-12 12:47:32 +05305655 except (LcmException, asyncio.CancelledError):
5656 raise
5657 except Exception as e:
5658 self.logger.debug("Error removing VNF {}".format(e))
5659 return "FAILED", "Error removing VNF {}".format(e)
5660
elumalaib9e357c2022-04-27 09:58:38 +05305661 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005662 self,
5663 nsr_id,
5664 nslcmop_id,
5665 db_vnfd,
5666 db_vnfr,
5667 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305668 ):
5669 """This method updates and redeploys VNF instances
5670
5671 Args:
5672 nsr_id: NS instance id
5673 nslcmop_id: nslcmop id
5674 db_vnfd: VNF descriptor
5675 db_vnfr: VNF instance record
5676 db_nsr: NS instance record
5677
5678 Returns:
5679 result: (str, str) COMPLETED/FAILED, details
5680 """
5681 try:
5682 count_index = 0
5683 stage = ["", "", ""]
5684 logging_text = "Task ns={} update ".format(nsr_id)
5685 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5686 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5687
5688 # Terminate old VNF resources
5689 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005690 await self.terminate_vdus(
5691 db_vnfr,
5692 member_vnf_index,
5693 db_nsr,
5694 update_db_nslcmops,
5695 stage,
5696 logging_text,
5697 )
elumalaib9e357c2022-04-27 09:58:38 +05305698
5699 # old_vnfd_id = db_vnfr["vnfd-id"]
5700 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5701 new_db_vnfd = db_vnfd
5702 # new_vnfd_ref = new_db_vnfd["id"]
5703 # new_vnfd_id = vnfd_id
5704
5705 # Create VDUR
5706 new_vnfr_cp = []
5707 for cp in new_db_vnfd.get("ext-cpd", ()):
5708 vnf_cp = {
5709 "name": cp.get("id"),
5710 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5711 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5712 "id": cp.get("id"),
5713 }
5714 new_vnfr_cp.append(vnf_cp)
5715 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5716 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5717 # 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 +00005718 new_vnfr_update = {
5719 "revision": latest_vnfd_revision,
5720 "connection-point": new_vnfr_cp,
5721 "vdur": new_vdur,
5722 "ip-address": "",
5723 }
elumalaib9e357c2022-04-27 09:58:38 +05305724 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5725 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005726 "vnfrs",
5727 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305728 )
5729
5730 # Instantiate new VNF resources
5731 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5732 vca_scaling_info = []
5733 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5734 scaling_info["scaling_direction"] = "OUT"
5735 scaling_info["vdu-create"] = {}
5736 scaling_info["kdu-create"] = {}
5737 vdud_instantiate_list = db_vnfd["vdu"]
5738 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005739 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305740 if cloud_init_text:
5741 additional_params = (
5742 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5743 or {}
5744 )
5745 cloud_init_list = []
5746 if cloud_init_text:
5747 # TODO Information of its own ip is not available because db_vnfr is not updated.
5748 additional_params["OSM"] = get_osm_params(
5749 updated_db_vnfr, vdud["id"], 1
5750 )
5751 cloud_init_list.append(
5752 self._parse_cloud_init(
5753 cloud_init_text,
5754 additional_params,
5755 db_vnfd["id"],
5756 vdud["id"],
5757 )
5758 )
5759 vca_scaling_info.append(
5760 {
5761 "osm_vdu_id": vdud["id"],
5762 "member-vnf-index": member_vnf_index,
5763 "type": "create",
5764 "vdu_index": count_index,
5765 }
5766 )
5767 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005768 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305769 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005770 "New Resources to be deployed: {}".format(scaling_info)
5771 )
elumalaib9e357c2022-04-27 09:58:38 +05305772 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005773 logging_text,
5774 db_nsr,
5775 update_db_nslcmops,
5776 updated_db_vnfr,
5777 scaling_info,
5778 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305779 )
5780 return "COMPLETED", "Done"
5781 except (LcmException, asyncio.CancelledError):
5782 raise
5783 except Exception as e:
5784 self.logger.debug("Error updating VNF {}".format(e))
5785 return "FAILED", "Error updating VNF {}".format(e)
5786
aticigdffa6212022-04-12 15:27:53 +03005787 async def _ns_charm_upgrade(
5788 self,
5789 ee_id,
5790 charm_id,
5791 charm_type,
5792 path,
5793 timeout: float = None,
5794 ) -> (str, str):
5795 """This method upgrade charms in VNF instances
5796
5797 Args:
5798 ee_id: Execution environment id
5799 path: Local path to the charm
5800 charm_id: charm-id
5801 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5802 timeout: (Float) Timeout for the ns update operation
5803
5804 Returns:
5805 result: (str, str) COMPLETED/FAILED, details
5806 """
5807 try:
5808 charm_type = charm_type or "lxc_proxy_charm"
5809 output = await self.vca_map[charm_type].upgrade_charm(
5810 ee_id=ee_id,
5811 path=path,
5812 charm_id=charm_id,
5813 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005814 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005815 )
5816
5817 if output:
5818 return "COMPLETED", output
5819
5820 except (LcmException, asyncio.CancelledError):
5821 raise
5822
5823 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005824 self.logger.debug("Error upgrading charm {}".format(path))
5825
5826 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5827
5828 async def update(self, nsr_id, nslcmop_id):
5829 """Update NS according to different update types
5830
5831 This method performs upgrade of VNF instances then updates the revision
5832 number in VNF record
5833
5834 Args:
5835 nsr_id: Network service will be updated
5836 nslcmop_id: ns lcm operation id
5837
5838 Returns:
5839 It may raise DbException, LcmException, N2VCException, K8sException
5840
5841 """
5842 # Try to lock HA task here
5843 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5844 if not task_is_locked_by_me:
5845 return
5846
5847 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5848 self.logger.debug(logging_text + "Enter")
5849
5850 # Set the required variables to be filled up later
5851 db_nsr = None
5852 db_nslcmop_update = {}
5853 vnfr_update = {}
5854 nslcmop_operation_state = None
5855 db_nsr_update = {}
5856 error_description_nslcmop = ""
5857 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305858 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005859 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005860 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005861
5862 try:
5863 # wait for any previous tasks in process
5864 step = "Waiting for previous operations to terminate"
5865 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5866 self._write_ns_status(
5867 nsr_id=nsr_id,
5868 ns_state=None,
5869 current_operation="UPDATING",
5870 current_operation_id=nslcmop_id,
5871 )
5872
5873 step = "Getting nslcmop from database"
5874 db_nslcmop = self.db.get_one(
5875 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5876 )
5877 update_type = db_nslcmop["operationParams"]["updateType"]
5878
5879 step = "Getting nsr from database"
5880 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5881 old_operational_status = db_nsr["operational-status"]
5882 db_nsr_update["operational-status"] = "updating"
5883 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5884 nsr_deployed = db_nsr["_admin"].get("deployed")
5885
5886 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005887 # Get the input parameters given through update request
5888 vnf_instance_id = db_nslcmop["operationParams"][
5889 "changeVnfPackageData"
5890 ].get("vnfInstanceId")
5891
5892 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5893 "vnfdId"
5894 )
5895 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5896
5897 step = "Getting vnfr from database"
5898 db_vnfr = self.db.get_one(
5899 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5900 )
5901
5902 step = "Getting vnfds from database"
5903 # Latest VNFD
5904 latest_vnfd = self.db.get_one(
5905 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5906 )
5907 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5908
5909 # Current VNFD
5910 current_vnf_revision = db_vnfr.get("revision", 1)
5911 current_vnfd = self.db.get_one(
5912 "vnfds_revisions",
5913 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5914 fail_on_empty=False,
5915 )
5916 # Charm artifact paths will be filled up later
5917 (
5918 current_charm_artifact_path,
5919 target_charm_artifact_path,
5920 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005921 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005922 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005923
5924 step = "Checking if revision has changed in VNFD"
5925 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305926 change_type = "policy_updated"
5927
aticigdffa6212022-04-12 15:27:53 +03005928 # There is new revision of VNFD, update operation is required
5929 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005930 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005931
5932 step = "Removing the VNFD packages if they exist in the local path"
5933 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5934 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5935
5936 step = "Get the VNFD packages from FSMongo"
5937 self.fs.sync(from_path=latest_vnfd_path)
5938 self.fs.sync(from_path=current_vnfd_path)
5939
5940 step = (
5941 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5942 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005943 current_base_folder = current_vnfd["_admin"]["storage"]
5944 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005945
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005946 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005947 get_iterable(nsr_deployed, "VCA")
5948 ):
5949 vnf_index = db_vnfr.get("member-vnf-index-ref")
5950
5951 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005952 if vca_deployed.get("member-vnf-index") == vnf_index:
5953 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5954 vca_type = vca_deployed.get("type")
5955 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005956
5957 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005958 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005959
5960 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005961 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005962 search_key = "kdu_name"
5963 else:
5964 search_key = "vnfd_id"
5965
5966 entity_id = vca_deployed.get(search_key)
5967
aticigdffa6212022-04-12 15:27:53 +03005968 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005969 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005970 )
5971
5972 if "execution-environment-list" in descriptor_config:
5973 ee_list = descriptor_config.get(
5974 "execution-environment-list", []
5975 )
5976 else:
5977 ee_list = []
5978
5979 # There could be several charm used in the same VNF
5980 for ee_item in ee_list:
5981 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005982 step = "Getting charm name"
5983 charm_name = ee_item["juju"].get("charm")
5984
5985 step = "Setting Charm artifact paths"
5986 current_charm_artifact_path.append(
5987 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005988 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005989 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005990 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005991 current_vnf_revision,
5992 )
5993 )
5994 target_charm_artifact_path.append(
5995 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005996 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005997 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005998 vca_type,
aticigd7083542022-05-30 20:45:55 +03005999 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03006000 )
6001 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006002 elif ee_item.get("helm-chart"):
6003 # add chart to list and all parameters
6004 step = "Getting helm chart name"
6005 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00006006 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006007 step = "Setting Helm chart artifact paths"
6008
garciadeblasfb1e25f2022-11-18 14:36:22 +01006009 helm_artifacts.append(
6010 {
6011 "current_artifact_path": get_charm_artifact_path(
6012 current_base_folder,
6013 chart_name,
6014 vca_type,
6015 current_vnf_revision,
6016 ),
6017 "target_artifact_path": get_charm_artifact_path(
6018 latest_base_folder,
6019 chart_name,
6020 vca_type,
6021 latest_vnfd_revision,
6022 ),
6023 "ee_id": ee_id,
6024 "vca_index": vca_index,
6025 "vdu_index": vdu_count_index,
6026 }
6027 )
aticigdffa6212022-04-12 15:27:53 +03006028
6029 charm_artifact_paths = zip(
6030 current_charm_artifact_path, target_charm_artifact_path
6031 )
6032
6033 step = "Checking if software version has changed in VNFD"
6034 if find_software_version(current_vnfd) != find_software_version(
6035 latest_vnfd
6036 ):
aticigdffa6212022-04-12 15:27:53 +03006037 step = "Checking if existing VNF has charm"
6038 for current_charm_path, target_charm_path in list(
6039 charm_artifact_paths
6040 ):
6041 if current_charm_path:
6042 raise LcmException(
6043 "Software version change is not supported as VNF instance {} has charm.".format(
6044 vnf_instance_id
6045 )
6046 )
6047
kayal20010cd8af32024-03-13 10:23:16 +05306048 step = "Checking whether the descriptor has SFC"
6049 if db_nsr.get("nsd", {}).get("vnffgd"):
6050 raise LcmException(
6051 "Ns update is not allowed for NS with SFC"
6052 )
6053
aticigdffa6212022-04-12 15:27:53 +03006054 # There is no change in the charm package, then redeploy the VNF
6055 # based on new descriptor
6056 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306057 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006058 (result, detailed_status) = await self._ns_redeploy_vnf(
6059 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306060 )
6061 if result == "FAILED":
6062 nslcmop_operation_state = result
6063 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306064 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306065 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306066 db_nsr_update["detailed-status"] = detailed_status
6067 scaling_aspect = get_scaling_aspect(latest_vnfd)
6068 scaling_group_desc = db_nsr.get("_admin").get(
6069 "scaling-group", None
6070 )
6071 if scaling_group_desc:
6072 for aspect in scaling_aspect:
6073 scaling_group_id = aspect.get("id")
6074 for scale_index, scaling_group in enumerate(
6075 scaling_group_desc
6076 ):
6077 if scaling_group.get("name") == scaling_group_id:
6078 db_nsr_update[
6079 "_admin.scaling-group.{}.nb-scale-op".format(
6080 scale_index
6081 )
6082 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306083 self.logger.debug(
6084 logging_text
6085 + " step {} Done with result {} {}".format(
6086 step, nslcmop_operation_state, detailed_status
6087 )
6088 )
aticigdffa6212022-04-12 15:27:53 +03006089
6090 else:
6091 step = "Checking if any charm package has changed or not"
6092 for current_charm_path, target_charm_path in list(
6093 charm_artifact_paths
6094 ):
6095 if (
6096 current_charm_path
6097 and target_charm_path
6098 and self.check_charm_hash_changed(
6099 current_charm_path, target_charm_path
6100 )
6101 ):
aticigdffa6212022-04-12 15:27:53 +03006102 step = "Checking whether VNF uses juju bundle"
6103 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006104 raise LcmException(
6105 "Charm upgrade is not supported for the instance which"
6106 " uses juju-bundle: {}".format(
6107 check_juju_bundle_existence(current_vnfd)
6108 )
6109 )
6110
6111 step = "Upgrading Charm"
6112 (
6113 result,
6114 detailed_status,
6115 ) = await self._ns_charm_upgrade(
6116 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006117 charm_id=vca_id,
6118 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006119 path=self.fs.path + target_charm_path,
6120 timeout=timeout_seconds,
6121 )
6122
6123 if result == "FAILED":
6124 nslcmop_operation_state = result
6125 error_description_nslcmop = detailed_status
6126
6127 db_nslcmop_update["detailed-status"] = detailed_status
6128 self.logger.debug(
6129 logging_text
6130 + " step {} Done with result {} {}".format(
6131 step, nslcmop_operation_state, detailed_status
6132 )
6133 )
6134
6135 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306136 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6137 result = "COMPLETED"
6138 detailed_status = "Done"
6139 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006140
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006141 # helm base EE
6142 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006143 if not (
6144 item["current_artifact_path"]
6145 and item["target_artifact_path"]
6146 and self.check_charm_hash_changed(
6147 item["current_artifact_path"],
6148 item["target_artifact_path"],
6149 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006150 ):
6151 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006152 db_update_entry = "_admin.deployed.VCA.{}.".format(
6153 item["vca_index"]
6154 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006155 vnfr_id = db_vnfr["_id"]
6156 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6157 db_dict = {
6158 "collection": "nsrs",
6159 "filter": {"_id": nsr_id},
6160 "path": db_update_entry,
6161 }
6162 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006163 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006164 namespace=namespace,
6165 helm_id=helm_id,
6166 db_dict=db_dict,
6167 config=osm_config,
6168 artifact_path=item["target_artifact_path"],
6169 vca_type=vca_type,
6170 )
6171 vnf_id = db_vnfr.get("vnfd-ref")
6172 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6173 self.logger.debug("get ssh key block")
6174 rw_mgmt_ip = None
6175 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006176 config_descriptor,
6177 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006178 ):
6179 # Needed to inject a ssh key
6180 user = deep_get(
6181 config_descriptor,
6182 ("config-access", "ssh-access", "default-user"),
6183 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006184 step = (
6185 "Install configuration Software, getting public ssh key"
6186 )
6187 pub_key = await self.vca_map[
6188 vca_type
6189 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006190 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6191 )
6192
garciadeblasfb1e25f2022-11-18 14:36:22 +01006193 step = (
6194 "Insert public key into VM user={} ssh_key={}".format(
6195 user, pub_key
6196 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006197 )
6198 self.logger.debug(logging_text + step)
6199
6200 # wait for RO (ip-address) Insert pub_key into VM
6201 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6202 logging_text,
6203 nsr_id,
6204 vnfr_id,
6205 None,
6206 item["vdu_index"],
6207 user=user,
6208 pub_key=pub_key,
6209 )
6210
6211 initial_config_primitive_list = config_descriptor.get(
6212 "initial-config-primitive"
6213 )
6214 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006215 (
6216 p
6217 for p in initial_config_primitive_list
6218 if p["name"] == "config"
6219 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006220 None,
6221 )
6222 if not config_primitive:
6223 continue
6224
6225 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6226 if rw_mgmt_ip:
6227 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6228 if db_vnfr.get("additionalParamsForVnf"):
6229 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006230 parse_yaml_strings(
6231 db_vnfr["additionalParamsForVnf"].copy()
6232 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006233 )
6234 primitive_params_ = self._map_primitive_params(
6235 config_primitive, {}, deploy_params
6236 )
6237
6238 step = "execute primitive '{}' params '{}'".format(
6239 config_primitive["name"], primitive_params_
6240 )
6241 self.logger.debug(logging_text + step)
6242 await self.vca_map[vca_type].exec_primitive(
6243 ee_id=ee_id,
6244 primitive_name=config_primitive["name"],
6245 params_dict=primitive_params_,
6246 db_dict=db_dict,
6247 vca_id=vca_id,
6248 vca_type=vca_type,
6249 )
6250
6251 step = "Updating policies"
6252 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6253 detailed_status = "Done"
6254 db_nslcmop_update["detailed-status"] = "Done"
6255
aticigdffa6212022-04-12 15:27:53 +03006256 # If nslcmop_operation_state is None, so any operation is not failed.
6257 if not nslcmop_operation_state:
6258 nslcmop_operation_state = "COMPLETED"
6259
6260 # If update CHANGE_VNFPKG nslcmop_operation is successful
6261 # vnf revision need to be updated
6262 vnfr_update["revision"] = latest_vnfd_revision
6263 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6264
6265 self.logger.debug(
6266 logging_text
6267 + " task Done with result {} {}".format(
6268 nslcmop_operation_state, detailed_status
6269 )
6270 )
6271 elif update_type == "REMOVE_VNF":
6272 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306273 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6274 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6275 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6276 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006277 (result, detailed_status) = await self.remove_vnf(
6278 nsr_id, nslcmop_id, vnf_instance_id
6279 )
elumalaica7ece02022-04-12 12:47:32 +05306280 if result == "FAILED":
6281 nslcmop_operation_state = result
6282 error_description_nslcmop = detailed_status
6283 db_nslcmop_update["detailed-status"] = detailed_status
6284 change_type = "vnf_terminated"
6285 if not nslcmop_operation_state:
6286 nslcmop_operation_state = "COMPLETED"
6287 self.logger.debug(
6288 logging_text
6289 + " task Done with result {} {}".format(
6290 nslcmop_operation_state, detailed_status
6291 )
6292 )
aticigdffa6212022-04-12 15:27:53 +03006293
k4.rahulb827de92022-05-02 16:35:02 +00006294 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006295 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6296 "vnfInstanceId"
6297 ]
6298 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6299 "changeStateTo"
6300 ]
6301 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6302 "additionalParam"
6303 ]
Isabel Lloret23aea8e2025-04-25 11:27:11 +02006304 self.logger.debug(
6305 "Operate VNF, operation_type: %s, params: %s",
6306 operation_type,
6307 additional_param,
6308 )
6309 (
6310 result,
6311 detailed_status,
6312 operation_result_data,
6313 ) = await self.process_operate_vnf(
k4.rahulb827de92022-05-02 16:35:02 +00006314 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006315 )
Isabel Lloret23aea8e2025-04-25 11:27:11 +02006316 self.logger.debug("operation_result_data: %s", operation_result_data)
6317 # In case the operation has a result store it in the ddbb
6318 if operation_result_data:
6319 db_nslcmop_update["operationResultData"] = operation_result_data
6320
k4.rahulb827de92022-05-02 16:35:02 +00006321 if result == "FAILED":
6322 nslcmop_operation_state = result
6323 error_description_nslcmop = detailed_status
6324 db_nslcmop_update["detailed-status"] = detailed_status
6325 if not nslcmop_operation_state:
6326 nslcmop_operation_state = "COMPLETED"
6327 self.logger.debug(
6328 logging_text
6329 + " task Done with result {} {}".format(
6330 nslcmop_operation_state, detailed_status
6331 )
6332 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306333 elif update_type == "VERTICAL_SCALE":
6334 self.logger.debug(
6335 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6336 )
6337 # Get the input parameters given through update request
6338 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6339 "vnfInstanceId"
6340 )
6341
6342 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6343 "vnfdId"
6344 )
6345 step = "Getting vnfr from database"
6346 db_vnfr = self.db.get_one(
6347 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6348 )
6349 self.logger.debug(step)
6350 step = "Getting vnfds from database"
6351 self.logger.debug("Start" + step)
6352 # Latest VNFD
6353 latest_vnfd = self.db.get_one(
6354 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6355 )
6356 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6357 # Current VNFD
6358 current_vnf_revision = db_vnfr.get("revision", 1)
6359 current_vnfd = self.db.get_one(
6360 "vnfds_revisions",
6361 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6362 fail_on_empty=False,
6363 )
6364 self.logger.debug("End" + step)
6365 # verify flavor changes
6366 step = "Checking for flavor change"
6367 if find_software_version(current_vnfd) != find_software_version(
6368 latest_vnfd
6369 ):
6370 self.logger.debug("Start" + step)
6371 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6372 "virtual-compute-desc"
6373 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6374 "virtual-storage-desc"
6375 ):
6376 raise LcmException(
6377 "No change in flavor check vnfd {}".format(vnfd_id)
6378 )
6379 else:
6380 raise LcmException(
6381 "No change in software_version of vnfd {}".format(vnfd_id)
6382 )
6383
6384 self.logger.debug("End" + step)
6385
6386 (result, detailed_status) = await self.vertical_scale(
6387 nsr_id, nslcmop_id
6388 )
6389 self.logger.debug(
6390 "vertical_scale result: {} detailed_status :{}".format(
6391 result, detailed_status
6392 )
6393 )
6394 if result == "FAILED":
6395 nslcmop_operation_state = result
6396 error_description_nslcmop = detailed_status
6397 db_nslcmop_update["detailed-status"] = detailed_status
6398 if not nslcmop_operation_state:
6399 nslcmop_operation_state = "COMPLETED"
6400 self.logger.debug(
6401 logging_text
6402 + " task Done with result {} {}".format(
6403 nslcmop_operation_state, detailed_status
6404 )
6405 )
k4.rahulb827de92022-05-02 16:35:02 +00006406
aticigdffa6212022-04-12 15:27:53 +03006407 # If nslcmop_operation_state is None, so any operation is not failed.
6408 # All operations are executed in overall.
6409 if not nslcmop_operation_state:
6410 nslcmop_operation_state = "COMPLETED"
6411 db_nsr_update["operational-status"] = old_operational_status
6412
6413 except (DbException, LcmException, N2VCException, K8sException) as e:
6414 self.logger.error(logging_text + "Exit Exception {}".format(e))
6415 exc = e
6416 except asyncio.CancelledError:
6417 self.logger.error(
6418 logging_text + "Cancelled Exception while '{}'".format(step)
6419 )
6420 exc = "Operation was cancelled"
6421 except asyncio.TimeoutError:
6422 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6423 exc = "Timeout"
6424 except Exception as e:
6425 exc = traceback.format_exc()
6426 self.logger.critical(
6427 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6428 exc_info=True,
6429 )
6430 finally:
6431 if exc:
6432 db_nslcmop_update[
6433 "detailed-status"
6434 ] = (
6435 detailed_status
6436 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6437 nslcmop_operation_state = "FAILED"
6438 db_nsr_update["operational-status"] = old_operational_status
6439 if db_nsr:
6440 self._write_ns_status(
6441 nsr_id=nsr_id,
6442 ns_state=db_nsr["nsState"],
6443 current_operation="IDLE",
6444 current_operation_id=None,
6445 other_update=db_nsr_update,
6446 )
6447
6448 self._write_op_status(
6449 op_id=nslcmop_id,
6450 stage="",
6451 error_message=error_description_nslcmop,
6452 operation_state=nslcmop_operation_state,
6453 other_update=db_nslcmop_update,
6454 )
6455
6456 if nslcmop_operation_state:
6457 try:
elumalaica7ece02022-04-12 12:47:32 +05306458 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306459 "nsr_id": nsr_id,
6460 "nslcmop_id": nslcmop_id,
6461 "operationState": nslcmop_operation_state,
6462 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006463 if (
6464 change_type in ("vnf_terminated", "policy_updated")
6465 and member_vnf_index
6466 ):
elumalaica7ece02022-04-12 12:47:32 +05306467 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006468 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006469 except Exception as e:
6470 self.logger.error(
6471 logging_text + "kafka_write notification Exception {}".format(e)
6472 )
6473 self.logger.debug(logging_text + "Exit")
6474 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6475 return nslcmop_operation_state, detailed_status
6476
tierno59d22d22018-09-25 18:10:19 +02006477 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006478 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006479 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006480 if not task_is_locked_by_me:
6481 return
6482
tierno59d22d22018-09-25 18:10:19 +02006483 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006484 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006485 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006486 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006487 self.logger.debug(logging_text + "Enter")
6488 # get all needed from database
6489 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006490 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006491 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006492 exc = None
tierno9ab95942018-10-10 16:44:22 +02006493 # in case of error, indicates what part of scale was failed to put nsr at error status
6494 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006495 old_operational_status = ""
6496 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006497 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006498 prom_job_name = ""
jegan976c06a2024-07-01 16:47:53 +00006499 exe = None
6500 nb_scale_op_update = False
tierno59d22d22018-09-25 18:10:19 +02006501 try:
kuused124bfe2019-06-18 12:09:24 +02006502 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006503 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006504 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6505 self._write_ns_status(
6506 nsr_id=nsr_id,
6507 ns_state=None,
6508 current_operation="SCALING",
6509 current_operation_id=nslcmop_id,
6510 )
quilesj4cda56b2019-12-05 10:02:20 +00006511
ikalyvas02d9e7b2019-05-27 18:16:01 +03006512 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006513 self.logger.debug(
6514 step + " after having waited for previous tasks to be completed"
6515 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006516 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006517
ikalyvas02d9e7b2019-05-27 18:16:01 +03006518 step = "Getting nsr from database"
6519 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006520 old_operational_status = db_nsr["operational-status"]
6521 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006522
kayal20010cd8af32024-03-13 10:23:16 +05306523 step = "Checking whether the descriptor has SFC"
6524 if db_nsr.get("nsd", {}).get("vnffgd"):
6525 raise LcmException("Scaling is not allowed for NS with SFC")
6526
tierno59d22d22018-09-25 18:10:19 +02006527 step = "Parsing scaling parameters"
6528 db_nsr_update["operational-status"] = "scaling"
6529 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006530 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006531
garciadeblas5697b8b2021-03-24 09:17:02 +01006532 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6533 "scaleByStepData"
6534 ]["member-vnf-index"]
6535 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6536 "scaleByStepData"
6537 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006538 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006539 # for backward compatibility
6540 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6541 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6542 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6543 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6544
tierno59d22d22018-09-25 18:10:19 +02006545 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006546 db_vnfr = self.db.get_one(
6547 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6548 )
bravof922c4172020-11-24 21:21:43 -03006549
David Garciac1fe90a2021-03-31 19:12:02 +02006550 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6551
tierno59d22d22018-09-25 18:10:19 +02006552 step = "Getting vnfd from database"
6553 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006554
aktas13251562021-02-12 22:19:10 +03006555 base_folder = db_vnfd["_admin"]["storage"]
6556
tierno59d22d22018-09-25 18:10:19 +02006557 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006558 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006559 get_scaling_aspect(db_vnfd),
6560 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006561 )
6562 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006563 raise LcmException(
6564 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6565 "at vnfd:scaling-group-descriptor".format(scaling_group)
6566 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006567
tierno15b1cf12019-08-29 13:21:40 +00006568 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006569 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006570 nb_scale_op = 0
6571 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006572 self.update_db_2(
6573 "nsrs",
6574 nsr_id,
6575 {
6576 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006577 {
6578 "name": scaling_group,
6579 "vnf_index": vnf_index,
6580 "nb-scale-op": 0,
6581 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006582 ]
6583 },
6584 )
tierno59d22d22018-09-25 18:10:19 +02006585 admin_scale_index = 0
6586 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006587 for admin_scale_index, admin_scale_info in enumerate(
6588 db_nsr["_admin"]["scaling-group"]
6589 ):
36970ef037852024-04-01 15:41:31 +00006590 if (
6591 admin_scale_info["name"] == scaling_group
6592 and admin_scale_info["vnf_index"] == vnf_index
6593 ):
tierno59d22d22018-09-25 18:10:19 +02006594 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6595 break
tierno9ab95942018-10-10 16:44:22 +02006596 else: # not found, set index one plus last element and add new entry with the name
6597 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006598 db_nsr_update[
6599 "_admin.scaling-group.{}.name".format(admin_scale_index)
6600 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006601 db_nsr_update[
6602 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6603 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006604
6605 vca_scaling_info = []
6606 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006607 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006608 if "aspect-delta-details" not in scaling_descriptor:
6609 raise LcmException(
6610 "Aspect delta details not fount in scaling descriptor {}".format(
6611 scaling_descriptor["name"]
6612 )
6613 )
tierno59d22d22018-09-25 18:10:19 +02006614 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006615 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006616
aktas5f75f102021-03-15 11:26:10 +03006617 scaling_info["scaling_direction"] = "OUT"
6618 scaling_info["vdu-create"] = {}
6619 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006620 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006621 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006622 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006623 # vdu_index also provides the number of instance of the targeted vdu
6624 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006625 if vdu_index <= len(db_vnfr["vdur"]):
6626 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6627 prom_job_name = (
6628 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6629 )
6630 prom_job_name = prom_job_name.replace("_", "")
6631 prom_job_name = prom_job_name.replace("-", "")
6632 else:
6633 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006634 cloud_init_text = self._get_vdu_cloud_init_content(
6635 vdud, db_vnfd
6636 )
tierno72ef84f2020-10-06 08:22:07 +00006637 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006638 additional_params = (
6639 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6640 or {}
6641 )
bravof832f8992020-12-07 12:57:31 -03006642 cloud_init_list = []
6643
6644 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6645 max_instance_count = 10
6646 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006647 max_instance_count = vdu_profile.get(
6648 "max-number-of-instances", 10
6649 )
6650
6651 default_instance_num = get_number_of_instances(
6652 db_vnfd, vdud["id"]
6653 )
aktas5f75f102021-03-15 11:26:10 +03006654 instances_number = vdu_delta.get("number-of-instances", 1)
6655 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006656
aktas5f75f102021-03-15 11:26:10 +03006657 new_instance_count = nb_scale_op + default_instance_num
6658 # Control if new count is over max and vdu count is less than max.
6659 # Then assign new instance count
6660 if new_instance_count > max_instance_count > vdu_count:
6661 instances_number = new_instance_count - max_instance_count
6662 else:
6663 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006664
aktas5f75f102021-03-15 11:26:10 +03006665 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006666 raise LcmException(
6667 "reached the limit of {} (max-instance-count) "
6668 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006669 "scaling-group-descriptor '{}'".format(
6670 nb_scale_op, scaling_group
6671 )
bravof922c4172020-11-24 21:21:43 -03006672 )
bravof832f8992020-12-07 12:57:31 -03006673 for x in range(vdu_delta.get("number-of-instances", 1)):
6674 if cloud_init_text:
6675 # TODO Information of its own ip is not available because db_vnfr is not updated.
6676 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006677 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006678 )
bravof832f8992020-12-07 12:57:31 -03006679 cloud_init_list.append(
6680 self._parse_cloud_init(
6681 cloud_init_text,
6682 additional_params,
6683 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006684 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006685 )
6686 )
aktas5f75f102021-03-15 11:26:10 +03006687 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006688 {
6689 "osm_vdu_id": vdu_delta["id"],
6690 "member-vnf-index": vnf_index,
6691 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006692 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006693 }
6694 )
aktas5f75f102021-03-15 11:26:10 +03006695 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6696 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006697 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006698 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006699 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006700
6701 # Might have different kdus in the same delta
6702 # Should have list for each kdu
6703 if not scaling_info["kdu-create"].get(kdu_name, None):
6704 scaling_info["kdu-create"][kdu_name] = []
6705
6706 kdur = get_kdur(db_vnfr, kdu_name)
6707 if kdur.get("helm-chart"):
6708 k8s_cluster_type = "helm-chart-v3"
6709 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006710 elif kdur.get("juju-bundle"):
6711 k8s_cluster_type = "juju-bundle"
6712 else:
6713 raise LcmException(
6714 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6715 "juju-bundle. Maybe an old NBI version is running".format(
6716 db_vnfr["member-vnf-index-ref"], kdu_name
6717 )
6718 )
6719
6720 max_instance_count = 10
6721 if kdu_profile and "max-number-of-instances" in kdu_profile:
6722 max_instance_count = kdu_profile.get(
6723 "max-number-of-instances", 10
6724 )
6725
6726 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6727 deployed_kdu, _ = get_deployed_kdu(
6728 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006729 )
aktas5f75f102021-03-15 11:26:10 +03006730 if deployed_kdu is None:
6731 raise LcmException(
6732 "KDU '{}' for vnf '{}' not deployed".format(
6733 kdu_name, vnf_index
6734 )
6735 )
6736 kdu_instance = deployed_kdu.get("kdu-instance")
6737 instance_num = await self.k8scluster_map[
6738 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006739 ].get_scale_count(
6740 resource_name,
6741 kdu_instance,
6742 vca_id=vca_id,
6743 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6744 kdu_model=deployed_kdu.get("kdu-model"),
6745 )
aktas5f75f102021-03-15 11:26:10 +03006746 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006747 "number-of-instances", 1
6748 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006749
aktas5f75f102021-03-15 11:26:10 +03006750 # Control if new count is over max and instance_num is less than max.
6751 # Then assign max instance number to kdu replica count
6752 if kdu_replica_count > max_instance_count > instance_num:
6753 kdu_replica_count = max_instance_count
6754 if kdu_replica_count > max_instance_count:
6755 raise LcmException(
6756 "reached the limit of {} (max-instance-count) "
6757 "scaling-out operations for the "
6758 "scaling-group-descriptor '{}'".format(
6759 instance_num, scaling_group
6760 )
6761 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006762
aktas5f75f102021-03-15 11:26:10 +03006763 for x in range(kdu_delta.get("number-of-instances", 1)):
6764 vca_scaling_info.append(
6765 {
6766 "osm_kdu_id": kdu_name,
6767 "member-vnf-index": vnf_index,
6768 "type": "create",
6769 "kdu_index": instance_num + x - 1,
6770 }
6771 )
6772 scaling_info["kdu-create"][kdu_name].append(
6773 {
6774 "member-vnf-index": vnf_index,
6775 "type": "create",
6776 "k8s-cluster-type": k8s_cluster_type,
6777 "resource-name": resource_name,
6778 "scale": kdu_replica_count,
6779 }
6780 )
6781 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006782 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006783
6784 scaling_info["scaling_direction"] = "IN"
6785 scaling_info["vdu-delete"] = {}
6786 scaling_info["kdu-delete"] = {}
6787
bravof832f8992020-12-07 12:57:31 -03006788 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006789 for vdu_delta in delta.get("vdu-delta", {}):
6790 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006791 min_instance_count = 0
6792 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6793 if vdu_profile and "min-number-of-instances" in vdu_profile:
6794 min_instance_count = vdu_profile["min-number-of-instances"]
6795
garciadeblas5697b8b2021-03-24 09:17:02 +01006796 default_instance_num = get_number_of_instances(
6797 db_vnfd, vdu_delta["id"]
6798 )
aktas5f75f102021-03-15 11:26:10 +03006799 instance_num = vdu_delta.get("number-of-instances", 1)
6800 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006801
aktas5f75f102021-03-15 11:26:10 +03006802 new_instance_count = nb_scale_op + default_instance_num
6803
6804 if new_instance_count < min_instance_count < vdu_count:
6805 instances_number = min_instance_count - new_instance_count
6806 else:
6807 instances_number = instance_num
6808
6809 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006810 raise LcmException(
6811 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006812 "scaling-group-descriptor '{}'".format(
6813 nb_scale_op, scaling_group
6814 )
bravof832f8992020-12-07 12:57:31 -03006815 )
aktas13251562021-02-12 22:19:10 +03006816 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006817 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006818 {
6819 "osm_vdu_id": vdu_delta["id"],
6820 "member-vnf-index": vnf_index,
6821 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006822 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006823 }
6824 )
aktas5f75f102021-03-15 11:26:10 +03006825 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6826 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006827 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006828 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006829 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006830
6831 if not scaling_info["kdu-delete"].get(kdu_name, None):
6832 scaling_info["kdu-delete"][kdu_name] = []
6833
6834 kdur = get_kdur(db_vnfr, kdu_name)
6835 if kdur.get("helm-chart"):
6836 k8s_cluster_type = "helm-chart-v3"
6837 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006838 elif kdur.get("juju-bundle"):
6839 k8s_cluster_type = "juju-bundle"
6840 else:
6841 raise LcmException(
6842 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6843 "juju-bundle. Maybe an old NBI version is running".format(
6844 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6845 )
6846 )
6847
6848 min_instance_count = 0
6849 if kdu_profile and "min-number-of-instances" in kdu_profile:
6850 min_instance_count = kdu_profile["min-number-of-instances"]
6851
6852 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6853 deployed_kdu, _ = get_deployed_kdu(
6854 nsr_deployed, kdu_name, vnf_index
6855 )
6856 if deployed_kdu is None:
6857 raise LcmException(
6858 "KDU '{}' for vnf '{}' not deployed".format(
6859 kdu_name, vnf_index
6860 )
6861 )
6862 kdu_instance = deployed_kdu.get("kdu-instance")
6863 instance_num = await self.k8scluster_map[
6864 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006865 ].get_scale_count(
6866 resource_name,
6867 kdu_instance,
6868 vca_id=vca_id,
6869 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6870 kdu_model=deployed_kdu.get("kdu-model"),
6871 )
aktas5f75f102021-03-15 11:26:10 +03006872 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006873 "number-of-instances", 1
6874 )
tierno59d22d22018-09-25 18:10:19 +02006875
aktas5f75f102021-03-15 11:26:10 +03006876 if kdu_replica_count < min_instance_count < instance_num:
6877 kdu_replica_count = min_instance_count
6878 if kdu_replica_count < min_instance_count:
6879 raise LcmException(
6880 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6881 "scaling-group-descriptor '{}'".format(
6882 instance_num, scaling_group
6883 )
6884 )
6885
6886 for x in range(kdu_delta.get("number-of-instances", 1)):
6887 vca_scaling_info.append(
6888 {
6889 "osm_kdu_id": kdu_name,
6890 "member-vnf-index": vnf_index,
6891 "type": "delete",
6892 "kdu_index": instance_num - x - 1,
6893 }
6894 )
6895 scaling_info["kdu-delete"][kdu_name].append(
6896 {
6897 "member-vnf-index": vnf_index,
6898 "type": "delete",
6899 "k8s-cluster-type": k8s_cluster_type,
6900 "resource-name": resource_name,
6901 "scale": kdu_replica_count,
6902 }
6903 )
6904
tierno59d22d22018-09-25 18:10:19 +02006905 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006906 vdu_delete = copy(scaling_info.get("vdu-delete"))
6907 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006908 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006909 if vdu_delete.get(vdur["vdu-id-ref"]):
6910 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006911 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006912 {
6913 "name": vdur.get("name") or vdur.get("vdu-name"),
6914 "vdu_id": vdur["vdu-id-ref"],
6915 "interface": [],
6916 }
6917 )
tierno59d22d22018-09-25 18:10:19 +02006918 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006919 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006920 {
6921 "name": interface["name"],
6922 "ip_address": interface["ip-address"],
6923 "mac_address": interface.get("mac-address"),
6924 }
6925 )
tierno2357f4e2020-10-19 16:38:59 +00006926 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006927
kuuseac3a8882019-10-03 10:48:06 +02006928 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006929 step = "Executing pre-scale vnf-config-primitive"
6930 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006931 for scaling_config_action in scaling_descriptor[
6932 "scaling-config-action"
6933 ]:
6934 if (
6935 scaling_config_action.get("trigger") == "pre-scale-in"
6936 and scaling_type == "SCALE_IN"
6937 ) or (
6938 scaling_config_action.get("trigger") == "pre-scale-out"
6939 and scaling_type == "SCALE_OUT"
6940 ):
6941 vnf_config_primitive = scaling_config_action[
6942 "vnf-config-primitive-name-ref"
6943 ]
6944 step = db_nslcmop_update[
6945 "detailed-status"
6946 ] = "executing pre-scale scaling-config-action '{}'".format(
6947 vnf_config_primitive
6948 )
tiernoda964822019-01-14 15:53:47 +00006949
tierno59d22d22018-09-25 18:10:19 +02006950 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006951 for config_primitive in (
6952 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6953 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006954 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006955 break
6956 else:
6957 raise LcmException(
6958 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006959 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006960 "primitive".format(scaling_group, vnf_config_primitive)
6961 )
tiernoda964822019-01-14 15:53:47 +00006962
aktas5f75f102021-03-15 11:26:10 +03006963 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006964 if db_vnfr.get("additionalParamsForVnf"):
6965 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006966
tierno9ab95942018-10-10 16:44:22 +02006967 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006968 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006969 primitive_params = self._map_primitive_params(
6970 config_primitive, {}, vnfr_params
6971 )
kuuseac3a8882019-10-03 10:48:06 +02006972
tierno7c4e24c2020-05-13 08:41:35 +00006973 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006974 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006975 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006976 vnf_index,
6977 vnf_config_primitive,
6978 primitive_params,
6979 "PRE-SCALE",
6980 )
tierno7c4e24c2020-05-13 08:41:35 +00006981 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006982 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006983 result = "COMPLETED"
6984 result_detail = "Done"
6985 self.logger.debug(
6986 logging_text
6987 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6988 vnf_config_primitive, result, result_detail
6989 )
6990 )
kuuseac3a8882019-10-03 10:48:06 +02006991 else:
tierno7c4e24c2020-05-13 08:41:35 +00006992 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006993 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006994 op_index = (
6995 len(db_nslcmop.get("_admin", {}).get("operations"))
6996 - 1
6997 )
6998 self.logger.debug(
6999 logging_text
7000 + "vnf_config_primitive={} New sub-operation".format(
7001 vnf_config_primitive
7002 )
7003 )
kuuseac3a8882019-10-03 10:48:06 +02007004 else:
tierno7c4e24c2020-05-13 08:41:35 +00007005 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007006 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7007 op_index
7008 ]
7009 vnf_index = op.get("member_vnf_index")
7010 vnf_config_primitive = op.get("primitive")
7011 primitive_params = op.get("primitive_params")
7012 self.logger.debug(
7013 logging_text
7014 + "vnf_config_primitive={} Sub-operation retry".format(
7015 vnf_config_primitive
7016 )
7017 )
tierno588547c2020-07-01 15:30:20 +00007018 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007019 ee_descriptor_id = config_primitive.get(
7020 "execution-environment-ref"
7021 )
7022 primitive_name = config_primitive.get(
7023 "execution-environment-primitive", vnf_config_primitive
7024 )
7025 ee_id, vca_type = self._look_for_deployed_vca(
7026 nsr_deployed["VCA"],
7027 member_vnf_index=vnf_index,
7028 vdu_id=None,
7029 vdu_count_index=None,
7030 ee_descriptor_id=ee_descriptor_id,
7031 )
kuuseac3a8882019-10-03 10:48:06 +02007032 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01007033 ee_id,
7034 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02007035 primitive_params,
7036 vca_type=vca_type,
7037 vca_id=vca_id,
7038 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007039 self.logger.debug(
7040 logging_text
7041 + "vnf_config_primitive={} Done with result {} {}".format(
7042 vnf_config_primitive, result, result_detail
7043 )
7044 )
kuuseac3a8882019-10-03 10:48:06 +02007045 # Update operationState = COMPLETED | FAILED
7046 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007047 db_nslcmop, op_index, result, result_detail
7048 )
kuuseac3a8882019-10-03 10:48:06 +02007049
tierno59d22d22018-09-25 18:10:19 +02007050 if result == "FAILED":
7051 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007052 db_nsr_update["config-status"] = old_config_status
7053 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007054 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007055
garciadeblas5697b8b2021-03-24 09:17:02 +01007056 db_nsr_update[
7057 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
7058 ] = nb_scale_op
7059 db_nsr_update[
7060 "_admin.scaling-group.{}.time".format(admin_scale_index)
7061 ] = time()
jegan976c06a2024-07-01 16:47:53 +00007062 nb_scale_op_update = True
tierno2357f4e2020-10-19 16:38:59 +00007063
aktas13251562021-02-12 22:19:10 +03007064 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007065 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007066 step = db_nslcmop_update[
7067 "detailed-status"
7068 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007069 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007070 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007071 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007072 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007073 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007074 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007075 )
aktas5f75f102021-03-15 11:26:10 +03007076 if vca_info.get("osm_vdu_id"):
7077 vdu_id = vca_info["osm_vdu_id"]
7078 vdu_index = int(vca_info["vdu_index"])
7079 stage[
7080 1
7081 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7082 member_vnf_index, vdu_id, vdu_index
7083 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007084 stage[2] = step = "Scaling in VCA"
7085 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007086 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7087 config_update = db_nsr["configurationStatus"]
7088 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007089 if (
7090 (vca or vca.get("ee_id"))
7091 and vca["member-vnf-index"] == member_vnf_index
7092 and vca["vdu_count_index"] == vdu_index
7093 ):
aktas13251562021-02-12 22:19:10 +03007094 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007095 config_descriptor = get_configuration(
7096 db_vnfd, vca.get("vdu_id")
7097 )
aktas13251562021-02-12 22:19:10 +03007098 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007099 config_descriptor = get_configuration(
7100 db_vnfd, vca.get("kdu_name")
7101 )
aktas13251562021-02-12 22:19:10 +03007102 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007103 config_descriptor = get_configuration(
7104 db_vnfd, db_vnfd["id"]
7105 )
7106 operation_params = (
7107 db_nslcmop.get("operationParams") or {}
7108 )
7109 exec_terminate_primitives = not operation_params.get(
7110 "skip_terminate_primitives"
7111 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007112 task = asyncio.ensure_future(
7113 asyncio.wait_for(
7114 self.destroy_N2VC(
7115 logging_text,
7116 db_nslcmop,
7117 vca,
7118 config_descriptor,
7119 vca_index,
7120 destroy_ee=True,
7121 exec_primitives=exec_terminate_primitives,
7122 scaling_in=True,
7123 vca_id=vca_id,
7124 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007125 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007126 )
7127 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007128 tasks_dict_info[task] = "Terminating VCA {}".format(
7129 vca.get("ee_id")
7130 )
aktas13251562021-02-12 22:19:10 +03007131 del vca_update[vca_index]
7132 del config_update[vca_index]
7133 # wait for pending tasks of terminate primitives
7134 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007135 self.logger.debug(
7136 logging_text
7137 + "Waiting for tasks {}".format(
7138 list(tasks_dict_info.keys())
7139 )
7140 )
7141 error_list = await self._wait_for_tasks(
7142 logging_text,
7143 tasks_dict_info,
7144 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007145 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007146 ),
7147 stage,
7148 nslcmop_id,
7149 )
aktas13251562021-02-12 22:19:10 +03007150 tasks_dict_info.clear()
7151 if error_list:
7152 raise LcmException("; ".join(error_list))
7153
7154 db_vca_and_config_update = {
7155 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007156 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007157 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007158 self.update_db_2(
7159 "nsrs", db_nsr["_id"], db_vca_and_config_update
7160 )
aktas13251562021-02-12 22:19:10 +03007161 scale_process = None
7162 # SCALE-IN VCA - END
7163
kuuseac3a8882019-10-03 10:48:06 +02007164 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007165 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007166 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007167 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007168 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007169 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007170 )
aktas5f75f102021-03-15 11:26:10 +03007171 scaling_info.pop("vdu-create", None)
7172 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007173
tierno9ab95942018-10-10 16:44:22 +02007174 scale_process = None
aktas13251562021-02-12 22:19:10 +03007175 # SCALE RO - END
7176
aktas5f75f102021-03-15 11:26:10 +03007177 # SCALE KDU - BEGIN
7178 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7179 scale_process = "KDU"
7180 await self._scale_kdu(
7181 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7182 )
7183 scaling_info.pop("kdu-create", None)
7184 scaling_info.pop("kdu-delete", None)
7185
7186 scale_process = None
7187 # SCALE KDU - END
7188
7189 if db_nsr_update:
7190 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7191
aktas13251562021-02-12 22:19:10 +03007192 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007193 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007194 step = db_nslcmop_update[
7195 "detailed-status"
7196 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007197 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007198 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007199 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007200 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007201 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007202 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007203 )
aktas13251562021-02-12 22:19:10 +03007204 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007205 if vca_info.get("osm_vdu_id"):
7206 vdu_index = int(vca_info["vdu_index"])
7207 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7208 if db_vnfr.get("additionalParamsForVnf"):
7209 deploy_params.update(
7210 parse_yaml_strings(
7211 db_vnfr["additionalParamsForVnf"].copy()
7212 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007213 )
aktas5f75f102021-03-15 11:26:10 +03007214 descriptor_config = get_configuration(
7215 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007216 )
aktas5f75f102021-03-15 11:26:10 +03007217 if descriptor_config:
7218 vdu_id = None
7219 vdu_name = None
7220 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007221 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007222 self._deploy_n2vc(
7223 logging_text=logging_text
7224 + "member_vnf_index={} ".format(member_vnf_index),
7225 db_nsr=db_nsr,
7226 db_vnfr=db_vnfr,
7227 nslcmop_id=nslcmop_id,
7228 nsr_id=nsr_id,
7229 nsi_id=nsi_id,
7230 vnfd_id=vnfd_id,
7231 vdu_id=vdu_id,
7232 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007233 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007234 member_vnf_index=member_vnf_index,
7235 vdu_index=vdu_index,
7236 vdu_name=vdu_name,
7237 deploy_params=deploy_params,
7238 descriptor_config=descriptor_config,
7239 base_folder=base_folder,
7240 task_instantiation_info=tasks_dict_info,
7241 stage=stage,
7242 )
7243 vdu_id = vca_info["osm_vdu_id"]
7244 vdur = find_in_list(
7245 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007246 )
aktas5f75f102021-03-15 11:26:10 +03007247 descriptor_config = get_configuration(db_vnfd, vdu_id)
7248 if vdur.get("additionalParams"):
7249 deploy_params_vdu = parse_yaml_strings(
7250 vdur["additionalParams"]
7251 )
7252 else:
7253 deploy_params_vdu = deploy_params
7254 deploy_params_vdu["OSM"] = get_osm_params(
7255 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007256 )
aktas5f75f102021-03-15 11:26:10 +03007257 if descriptor_config:
7258 vdu_name = None
7259 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007260 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007261 stage[
7262 1
7263 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007264 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007265 )
7266 stage[2] = step = "Scaling out VCA"
7267 self._write_op_status(op_id=nslcmop_id, stage=stage)
7268 self._deploy_n2vc(
7269 logging_text=logging_text
7270 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7271 member_vnf_index, vdu_id, vdu_index
7272 ),
7273 db_nsr=db_nsr,
7274 db_vnfr=db_vnfr,
7275 nslcmop_id=nslcmop_id,
7276 nsr_id=nsr_id,
7277 nsi_id=nsi_id,
7278 vnfd_id=vnfd_id,
7279 vdu_id=vdu_id,
7280 kdu_name=kdu_name,
7281 member_vnf_index=member_vnf_index,
7282 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007283 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007284 vdu_name=vdu_name,
7285 deploy_params=deploy_params_vdu,
7286 descriptor_config=descriptor_config,
7287 base_folder=base_folder,
7288 task_instantiation_info=tasks_dict_info,
7289 stage=stage,
7290 )
aktas13251562021-02-12 22:19:10 +03007291 # SCALE-UP VCA - END
7292 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007293
kuuseac3a8882019-10-03 10:48:06 +02007294 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007295 # execute primitive service POST-SCALING
7296 step = "Executing post-scale vnf-config-primitive"
7297 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007298 for scaling_config_action in scaling_descriptor[
7299 "scaling-config-action"
7300 ]:
7301 if (
7302 scaling_config_action.get("trigger") == "post-scale-in"
7303 and scaling_type == "SCALE_IN"
7304 ) or (
7305 scaling_config_action.get("trigger") == "post-scale-out"
7306 and scaling_type == "SCALE_OUT"
7307 ):
7308 vnf_config_primitive = scaling_config_action[
7309 "vnf-config-primitive-name-ref"
7310 ]
7311 step = db_nslcmop_update[
7312 "detailed-status"
7313 ] = "executing post-scale scaling-config-action '{}'".format(
7314 vnf_config_primitive
7315 )
tiernoda964822019-01-14 15:53:47 +00007316
aktas5f75f102021-03-15 11:26:10 +03007317 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007318 if db_vnfr.get("additionalParamsForVnf"):
7319 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7320
tierno59d22d22018-09-25 18:10:19 +02007321 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007322 for config_primitive in (
7323 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7324 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007325 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007326 break
7327 else:
tiernoa278b842020-07-08 15:33:55 +00007328 raise LcmException(
7329 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7330 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007331 "config-primitive".format(
7332 scaling_group, vnf_config_primitive
7333 )
7334 )
tierno9ab95942018-10-10 16:44:22 +02007335 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007336 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007337 primitive_params = self._map_primitive_params(
7338 config_primitive, {}, vnfr_params
7339 )
tiernod6de1992018-10-11 13:05:52 +02007340
tierno7c4e24c2020-05-13 08:41:35 +00007341 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007342 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007343 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007344 vnf_index,
7345 vnf_config_primitive,
7346 primitive_params,
7347 "POST-SCALE",
7348 )
quilesj4cda56b2019-12-05 10:02:20 +00007349 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007350 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007351 result = "COMPLETED"
7352 result_detail = "Done"
7353 self.logger.debug(
7354 logging_text
7355 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7356 vnf_config_primitive, result, result_detail
7357 )
7358 )
kuuseac3a8882019-10-03 10:48:06 +02007359 else:
quilesj4cda56b2019-12-05 10:02:20 +00007360 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007361 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007362 op_index = (
7363 len(db_nslcmop.get("_admin", {}).get("operations"))
7364 - 1
7365 )
7366 self.logger.debug(
7367 logging_text
7368 + "vnf_config_primitive={} New sub-operation".format(
7369 vnf_config_primitive
7370 )
7371 )
kuuseac3a8882019-10-03 10:48:06 +02007372 else:
tierno7c4e24c2020-05-13 08:41:35 +00007373 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007374 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7375 op_index
7376 ]
7377 vnf_index = op.get("member_vnf_index")
7378 vnf_config_primitive = op.get("primitive")
7379 primitive_params = op.get("primitive_params")
7380 self.logger.debug(
7381 logging_text
7382 + "vnf_config_primitive={} Sub-operation retry".format(
7383 vnf_config_primitive
7384 )
7385 )
tierno588547c2020-07-01 15:30:20 +00007386 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007387 ee_descriptor_id = config_primitive.get(
7388 "execution-environment-ref"
7389 )
7390 primitive_name = config_primitive.get(
7391 "execution-environment-primitive", vnf_config_primitive
7392 )
7393 ee_id, vca_type = self._look_for_deployed_vca(
7394 nsr_deployed["VCA"],
7395 member_vnf_index=vnf_index,
7396 vdu_id=None,
7397 vdu_count_index=None,
7398 ee_descriptor_id=ee_descriptor_id,
7399 )
kuuseac3a8882019-10-03 10:48:06 +02007400 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007401 ee_id,
7402 primitive_name,
7403 primitive_params,
7404 vca_type=vca_type,
7405 vca_id=vca_id,
7406 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007407 self.logger.debug(
7408 logging_text
7409 + "vnf_config_primitive={} Done with result {} {}".format(
7410 vnf_config_primitive, result, result_detail
7411 )
7412 )
kuuseac3a8882019-10-03 10:48:06 +02007413 # Update operationState = COMPLETED | FAILED
7414 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007415 db_nslcmop, op_index, result, result_detail
7416 )
kuuseac3a8882019-10-03 10:48:06 +02007417
tierno59d22d22018-09-25 18:10:19 +02007418 if result == "FAILED":
7419 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007420 db_nsr_update["config-status"] = old_config_status
7421 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007422 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007423 # Check if each vnf has exporter for metric collection if so update prometheus job records
Rahul Kumar54671c52024-05-09 15:34:01 +05307424 if scaling_type == "SCALE_OUT" and bool(self.service_kpi.old_sa):
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007425 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7426 vnfr_id = db_vnfr["id"]
7427 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7428 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7429 self.logger.debug("exporter config :{}".format(exporter_config))
7430 artifact_path = "{}/{}/{}".format(
7431 base_folder["folder"],
7432 base_folder["pkg-dir"],
7433 "exporter-endpoint",
7434 )
7435 ee_id = None
7436 ee_config_descriptor = exporter_config
7437 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7438 logging_text,
7439 nsr_id,
7440 vnfr_id,
7441 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7442 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7443 user=None,
7444 pub_key=None,
7445 )
7446 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7447 self.logger.debug("Artifact_path:{}".format(artifact_path))
7448 vdu_id_for_prom = None
7449 vdu_index_for_prom = None
7450 for x in get_iterable(db_vnfr, "vdur"):
7451 vdu_id_for_prom = x.get("vdu-id-ref")
7452 vdu_index_for_prom = x.get("count-index")
7453 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7454 vnfr_id = vnfr_id.replace("_", "")
7455 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7456 ee_id=ee_id,
7457 artifact_path=artifact_path,
7458 ee_config_descriptor=ee_config_descriptor,
7459 vnfr_id=vnfr_id,
7460 nsr_id=nsr_id,
7461 target_ip=rw_mgmt_ip,
7462 element_type="VDU",
7463 vdu_id=vdu_id_for_prom,
7464 vdu_index=vdu_index_for_prom,
7465 )
tierno59d22d22018-09-25 18:10:19 +02007466
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007467 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7468 if prometheus_jobs:
7469 db_nsr_update[
7470 "_admin.deployed.prometheus_jobs"
7471 ] = prometheus_jobs
7472 self.update_db_2(
7473 "nsrs",
7474 nsr_id,
7475 db_nsr_update,
7476 )
7477
7478 for job in prometheus_jobs:
7479 self.db.set_one(
7480 "prometheus_jobs",
7481 {"job_name": ""},
7482 job,
7483 upsert=True,
7484 fail_on_empty=False,
7485 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007486 db_nsr_update[
7487 "detailed-status"
7488 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7489 db_nsr_update["operational-status"] = (
7490 "running"
7491 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007492 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007493 )
tiernod6de1992018-10-11 13:05:52 +02007494 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007495 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007496 except (
7497 ROclient.ROClientException,
jegan976c06a2024-07-01 16:47:53 +00007498 NgRoException,
7499 ) as e:
7500 exe = "RO exception"
7501 self.logger.error(logging_text + "Exit Exception {}".format(e))
7502 exc = e
7503 except (
garciadeblas5697b8b2021-03-24 09:17:02 +01007504 DbException,
7505 LcmException,
garciadeblas5697b8b2021-03-24 09:17:02 +01007506 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007507 self.logger.error(logging_text + "Exit Exception {}".format(e))
7508 exc = e
7509 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007510 self.logger.error(
7511 logging_text + "Cancelled Exception while '{}'".format(step)
7512 )
tierno59d22d22018-09-25 18:10:19 +02007513 exc = "Operation was cancelled"
7514 except Exception as e:
7515 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007516 self.logger.critical(
7517 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7518 exc_info=True,
7519 )
tierno59d22d22018-09-25 18:10:19 +02007520 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007521 error_list = list()
7522 if exc:
7523 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007524 self._write_ns_status(
7525 nsr_id=nsr_id,
7526 ns_state=None,
7527 current_operation="IDLE",
7528 current_operation_id=None,
7529 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007530 try:
7531 if tasks_dict_info:
7532 stage[1] = "Waiting for instantiate pending tasks."
7533 self.logger.debug(logging_text + stage[1])
7534 exc = await self._wait_for_tasks(
7535 logging_text,
7536 tasks_dict_info,
7537 self.timeout.ns_deploy,
7538 stage,
7539 nslcmop_id,
7540 nsr_id=nsr_id,
7541 )
7542 except asyncio.CancelledError:
7543 error_list.append("Cancelled")
7544 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7545 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007546 logging_text,
7547 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007548 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007549 stage,
7550 nslcmop_id,
7551 nsr_id=nsr_id,
7552 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007553 if error_list:
7554 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007555 db_nslcmop_update[
7556 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007557 ] = error_description_nslcmop = "FAILED {}: {}".format(
7558 step, error_detail
7559 )
tiernoa17d4f42020-04-28 09:59:23 +00007560 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007561 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007562 db_nsr_update["operational-status"] = old_operational_status
7563 db_nsr_update["config-status"] = old_config_status
7564 db_nsr_update["detailed-status"] = ""
7565 if scale_process:
7566 if "VCA" in scale_process:
7567 db_nsr_update["config-status"] = "failed"
7568 if "RO" in scale_process:
7569 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007570 db_nsr_update[
7571 "detailed-status"
7572 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007573 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007574 )
tiernoa17d4f42020-04-28 09:59:23 +00007575 else:
7576 error_description_nslcmop = None
7577 nslcmop_operation_state = "COMPLETED"
7578 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007579 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7580 self.db.del_one(
7581 "prometheus_jobs",
7582 {"job_name": prom_job_name},
7583 fail_on_empty=False,
7584 )
quilesj4cda56b2019-12-05 10:02:20 +00007585
garciadeblas5697b8b2021-03-24 09:17:02 +01007586 self._write_op_status(
7587 op_id=nslcmop_id,
7588 stage="",
7589 error_message=error_description_nslcmop,
7590 operation_state=nslcmop_operation_state,
7591 other_update=db_nslcmop_update,
7592 )
tiernoa17d4f42020-04-28 09:59:23 +00007593 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007594 self._write_ns_status(
7595 nsr_id=nsr_id,
7596 ns_state=None,
7597 current_operation="IDLE",
7598 current_operation_id=None,
7599 other_update=db_nsr_update,
7600 )
jegan976c06a2024-07-01 16:47:53 +00007601 if exe:
7602 if (
7603 scaling_type == "SCALE_OUT"
7604 and nb_scale_op_update
7605 and exe == "RO exception"
7606 ):
7607 self.rollback_scaling(nsr_id, nslcmop_id)
tiernoa17d4f42020-04-28 09:59:23 +00007608
tierno59d22d22018-09-25 18:10:19 +02007609 if nslcmop_operation_state:
7610 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007611 msg = {
7612 "nsr_id": nsr_id,
7613 "nslcmop_id": nslcmop_id,
7614 "operationState": nslcmop_operation_state,
7615 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007616 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007617 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007618 self.logger.error(
7619 logging_text + "kafka_write notification Exception {}".format(e)
7620 )
tierno59d22d22018-09-25 18:10:19 +02007621 self.logger.debug(logging_text + "Exit")
7622 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007623
aktas5f75f102021-03-15 11:26:10 +03007624 async def _scale_kdu(
7625 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7626 ):
7627 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7628 for kdu_name in _scaling_info:
7629 for kdu_scaling_info in _scaling_info[kdu_name]:
7630 deployed_kdu, index = get_deployed_kdu(
7631 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7632 )
7633 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7634 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007635 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007636 scale = int(kdu_scaling_info["scale"])
7637 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7638
7639 db_dict = {
7640 "collection": "nsrs",
7641 "filter": {"_id": nsr_id},
7642 "path": "_admin.deployed.K8s.{}".format(index),
7643 }
7644
7645 step = "scaling application {}".format(
7646 kdu_scaling_info["resource-name"]
7647 )
7648 self.logger.debug(logging_text + step)
7649
7650 if kdu_scaling_info["type"] == "delete":
7651 kdu_config = get_configuration(db_vnfd, kdu_name)
7652 if (
7653 kdu_config
7654 and kdu_config.get("terminate-config-primitive")
7655 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7656 ):
7657 terminate_config_primitive_list = kdu_config.get(
7658 "terminate-config-primitive"
7659 )
7660 terminate_config_primitive_list.sort(
7661 key=lambda val: int(val["seq"])
7662 )
7663
7664 for (
7665 terminate_config_primitive
7666 ) in terminate_config_primitive_list:
7667 primitive_params_ = self._map_primitive_params(
7668 terminate_config_primitive, {}, {}
7669 )
7670 step = "execute terminate config primitive"
7671 self.logger.debug(logging_text + step)
7672 await asyncio.wait_for(
7673 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7674 cluster_uuid=cluster_uuid,
7675 kdu_instance=kdu_instance,
7676 primitive_name=terminate_config_primitive["name"],
7677 params=primitive_params_,
7678 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007679 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007680 vca_id=vca_id,
7681 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007682 timeout=self.timeout.primitive
7683 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007684 )
7685
7686 await asyncio.wait_for(
7687 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007688 kdu_instance=kdu_instance,
7689 scale=scale,
7690 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007691 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007692 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007693 cluster_uuid=cluster_uuid,
7694 kdu_model=kdu_model,
7695 atomic=True,
7696 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007697 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007698 timeout=self.timeout.scale_on_error
7699 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007700 )
7701
7702 if kdu_scaling_info["type"] == "create":
7703 kdu_config = get_configuration(db_vnfd, kdu_name)
7704 if (
7705 kdu_config
7706 and kdu_config.get("initial-config-primitive")
7707 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7708 ):
7709 initial_config_primitive_list = kdu_config.get(
7710 "initial-config-primitive"
7711 )
7712 initial_config_primitive_list.sort(
7713 key=lambda val: int(val["seq"])
7714 )
7715
7716 for initial_config_primitive in initial_config_primitive_list:
7717 primitive_params_ = self._map_primitive_params(
7718 initial_config_primitive, {}, {}
7719 )
7720 step = "execute initial config primitive"
7721 self.logger.debug(logging_text + step)
7722 await asyncio.wait_for(
7723 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7724 cluster_uuid=cluster_uuid,
7725 kdu_instance=kdu_instance,
7726 primitive_name=initial_config_primitive["name"],
7727 params=primitive_params_,
7728 db_dict=db_dict,
7729 vca_id=vca_id,
7730 ),
7731 timeout=600,
7732 )
7733
garciadeblas5697b8b2021-03-24 09:17:02 +01007734 async def _scale_ng_ro(
7735 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7736 ):
tierno2357f4e2020-10-19 16:38:59 +00007737 nsr_id = db_nslcmop["nsInstanceId"]
7738 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7739 db_vnfrs = {}
7740
7741 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007742 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007743
7744 # for each vnf in ns, read vnfd
7745 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7746 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7747 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007748 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007749 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007750 # read from db
7751 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007752 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007753 n2vc_key = self.n2vc.get_public_key()
7754 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007755 self.scale_vnfr(
7756 db_vnfr,
7757 vdu_scaling_info.get("vdu-create"),
7758 vdu_scaling_info.get("vdu-delete"),
7759 mark_delete=True,
7760 )
tierno2357f4e2020-10-19 16:38:59 +00007761 # db_vnfr has been updated, update db_vnfrs to use it
7762 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007763 await self._instantiate_ng_ro(
7764 logging_text,
7765 nsr_id,
7766 db_nsd,
7767 db_nsr,
7768 db_nslcmop,
7769 db_vnfrs,
7770 db_vnfds,
7771 n2vc_key_list,
7772 stage=stage,
7773 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007774 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007775 )
tierno2357f4e2020-10-19 16:38:59 +00007776 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007777 self.scale_vnfr(
7778 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7779 )
tierno2357f4e2020-10-19 16:38:59 +00007780
bravof73bac502021-05-11 07:38:47 -04007781 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007782 self,
7783 ee_id: str,
7784 artifact_path: str,
7785 ee_config_descriptor: dict,
7786 vnfr_id: str,
7787 nsr_id: str,
7788 target_ip: str,
7789 element_type: str,
7790 vnf_member_index: str = "",
7791 vdu_id: str = "",
7792 vdu_index: int = None,
7793 kdu_name: str = "",
7794 kdu_index: int = None,
7795 ) -> dict:
7796 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7797 This method will wait until the corresponding VDU or KDU is fully instantiated
7798
7799 Args:
7800 ee_id (str): Execution Environment ID
7801 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7802 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7803 vnfr_id (str): VNFR ID where this EE applies
7804 nsr_id (str): NSR ID where this EE applies
7805 target_ip (str): VDU/KDU instance IP address
7806 element_type (str): NS or VNF or VDU or KDU
7807 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7808 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7809 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7810 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7811 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7812
7813 Raises:
7814 LcmException: When the VDU or KDU instance was not found in an hour
7815
7816 Returns:
7817 _type_: Prometheus jobs
7818 """
7819 # default the vdur and kdur names to an empty string, to avoid any later
7820 # problem with Prometheus when the element type is not VDU or KDU
7821 vdur_name = ""
7822 kdur_name = ""
7823
tiernob996d942020-07-03 14:52:28 +00007824 # look if exist a file called 'prometheus*.j2' and
7825 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007826 job_file = next(
7827 (
7828 f
7829 for f in artifact_content
7830 if f.startswith("prometheus") and f.endswith(".j2")
7831 ),
7832 None,
7833 )
tiernob996d942020-07-03 14:52:28 +00007834 if not job_file:
7835 return
k4.rahul74944982023-04-19 17:00:52 +05307836 self.logger.debug("Artifact path{}".format(artifact_path))
7837 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007838 with self.fs.file_open((artifact_path, job_file), "r") as f:
7839 job_data = f.read()
7840
Pedro Escaleira120695e2022-06-11 21:17:26 +01007841 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7842 if element_type in ("VDU", "KDU"):
7843 for _ in range(360):
7844 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7845 if vdu_id and vdu_index is not None:
7846 vdur = next(
7847 (
7848 x
7849 for x in get_iterable(db_vnfr, "vdur")
7850 if (
7851 x.get("vdu-id-ref") == vdu_id
7852 and x.get("count-index") == vdu_index
7853 )
7854 ),
7855 {},
7856 )
7857 if vdur.get("name"):
7858 vdur_name = vdur.get("name")
7859 break
7860 if kdu_name and kdu_index is not None:
7861 kdur = next(
7862 (
7863 x
7864 for x in get_iterable(db_vnfr, "kdur")
7865 if (
7866 x.get("kdu-name") == kdu_name
7867 and x.get("count-index") == kdu_index
7868 )
7869 ),
7870 {},
7871 )
7872 if kdur.get("name"):
7873 kdur_name = kdur.get("name")
7874 break
7875
Gabriel Cubae7898982023-05-11 01:57:21 -05007876 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007877 else:
7878 if vdu_id and vdu_index is not None:
7879 raise LcmException(
7880 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7881 )
7882 if kdu_name and kdu_index is not None:
7883 raise LcmException(
7884 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7885 )
7886
k4.rahul74944982023-04-19 17:00:52 +05307887 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007888 _, namespace, helm_id = get_ee_id_parts(
7889 ee_id
7890 ) # get namespace and EE gRPC service name
7891 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307892 host_port = "80"
7893 vnfr_id = vnfr_id.replace("-", "")
7894 variables = {
7895 "JOB_NAME": vnfr_id,
7896 "TARGET_IP": target_ip,
7897 "EXPORTER_POD_IP": host_name,
7898 "EXPORTER_POD_PORT": host_port,
7899 "NSR_ID": nsr_id,
7900 "VNF_MEMBER_INDEX": vnf_member_index,
7901 "VDUR_NAME": vdur_name,
7902 "KDUR_NAME": kdur_name,
7903 "ELEMENT_TYPE": element_type,
7904 }
7905 else:
7906 metric_path = ee_config_descriptor["metric-path"]
7907 target_port = ee_config_descriptor["metric-port"]
7908 vnfr_id = vnfr_id.replace("-", "")
7909 variables = {
7910 "JOB_NAME": vnfr_id,
7911 "TARGET_IP": target_ip,
7912 "TARGET_PORT": target_port,
7913 "METRIC_PATH": metric_path,
7914 }
7915
bravof73bac502021-05-11 07:38:47 -04007916 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007917 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7918 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007919 if (
7920 not isinstance(job.get("job_name"), str)
7921 or vnfr_id not in job["job_name"]
7922 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307923 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007924 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007925 job["vnfr_id"] = vnfr_id
7926 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007927
Isabel Lloret23aea8e2025-04-25 11:27:11 +02007928 async def process_operate_vnf(
7929 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7930 ):
7931 self.logger.debug("Process operate vnf, operation_type: %s", operation_type)
7932 operations = {"console": self.get_console_operation}
7933 default_operation = self.rebuild_start_stop
7934
7935 operation_func = operations.get(operation_type, default_operation)
7936 if callable(operation_func):
7937 result = await operation_func(
7938 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7939 )
7940 if len(result) == 2:
7941 result = (*result, None)
7942 return result
7943 return "FAILED", f"Unknown operation type: {operation_type}", None
7944
7945 async def get_console_operation(
7946 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7947 ):
7948 self.logger.debug(
7949 "Get console operation, nsr_id: %s, nslcmop_id: %s, vnf_id: %s, additional_param: %s, operation_type: %s",
7950 nsr_id,
7951 nslcmop_id,
7952 vnf_id,
7953 additional_param,
7954 operation_type,
7955 )
7956 status = "PROCESSING"
7957 detailed_status = ""
7958 start_deploy = time()
7959 try:
7960 # Obtain vnf data from database
7961 operation_data = self._get_vdu_operation_data(
7962 vnf_id, additional_param["count-index"], additional_param["vdu_id"]
7963 )
7964 self.logger.debug("Operation data: %s", operation_data)
7965
7966 # Execute operation
7967 desc = {"console": operation_data}
7968 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7969 self.logger.debug("Result dict: %s", result_dict)
7970
7971 # Wait for response
7972 action_id = result_dict["action_id"]
7973 await self._wait_ng_ro(
7974 nsr_id,
7975 action_id,
7976 nslcmop_id,
7977 start_deploy,
7978 self.timeout.operate,
7979 None,
7980 "console",
7981 )
7982
7983 # Obtain the console vim data
7984 result_vim_info = await self.RO.get_action_vim_info(nsr_id, action_id)
7985 self.logger.debug("Result vim info: %s", result_vim_info)
7986 console_data = None
7987 if result_vim_info.get("vim_info_list"):
7988 for vim_info in result_vim_info.get("vim_info_list"):
7989 if vim_info.get("vim_console_data"):
7990 console_data = vim_info.get("vim_console_data")
7991
7992 self.logger.debug("console_data: %s", console_data)
7993 if not console_data:
7994 raise ROclient.ROClientException("console data not properly returned")
7995
7996 return "COMPLETED", "Done", console_data
7997
7998 except (ROclient.ROClientException, DbException, LcmException) as e:
7999 self.logger.error("Exit Exception {}".format(e))
8000 status = "FAILED"
8001 detailed_status = str(e)
8002 except asyncio.CancelledError:
8003 self.logger.error("Cancelled Exception obtaining console data")
8004 exc = "Operation was cancelled"
8005 status = "FAILED"
8006 detailed_status = exc
8007 except Exception as e:
8008 exc = traceback.format_exc()
8009 self.logger.critical(
8010 "Processing get_console_operation, end operation Exception {} {}".format(
8011 type(e).__name__, e
8012 ),
8013 exc_info=True,
8014 )
8015 status = "FAILED"
8016 detailed_status = "Error in operate VNF {}".format(exc)
8017
8018 return status, detailed_status
8019
8020 def _get_vdu_operation_data(self, vnf_id, count_index, vdu_id):
8021 """
8022 Obtains vdu required data from database
8023 """
8024 operation_data = {"vnf_id": vnf_id, "vdu_index": count_index}
8025 # Obtain vnf from the database
8026 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
8027
8028 self.logger.debug("db_vnfr: %s", db_vnfr)
8029 # Obtain additional data and vdu data
8030 vim_account_id = db_vnfr.get("vim-account-id")
8031 vim_info_key = "vim:" + vim_account_id
8032 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
8033 vdur = find_in_list(vdurs, lambda vdu: vdu["count-index"] == count_index)
8034 self.logger.debug("vdur: %s", vdur)
8035 if vdur:
8036 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
8037 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
8038 else:
8039 raise LcmException("Target vdu is not found")
8040
8041 # Store all the needed data for the operation
8042 operation_data["vim_vm_id"] = vim_vm_id
8043 operation_data["vdu_id"] = vdur["id"]
8044 operation_data["target_vim"] = target_vim
8045 operation_data["vim_account_id"] = vim_account_id
8046 return operation_data
8047
preethika.p28b0bf82022-09-23 07:36:28 +00008048 async def rebuild_start_stop(
8049 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
8050 ):
k4.rahulb827de92022-05-02 16:35:02 +00008051 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
8052 self.logger.info(logging_text + "Enter")
8053 stage = ["Preparing the environment", ""]
8054 # database nsrs record
8055 db_nsr_update = {}
8056 vdu_vim_name = None
8057 vim_vm_id = None
8058 # in case of error, indicates what part of scale was failed to put nsr at error status
8059 start_deploy = time()
8060 try:
8061 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
8062 vim_account_id = db_vnfr.get("vim-account-id")
8063 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00008064 vdu_id = additional_param["vdu_id"]
8065 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00008066 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00008067 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00008068 )
k4.rahulb827de92022-05-02 16:35:02 +00008069 if vdur:
8070 vdu_vim_name = vdur["name"]
8071 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
8072 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00008073 else:
8074 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00008075 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
8076 # wait for any previous tasks in process
8077 stage[1] = "Waiting for previous operations to terminate"
8078 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00008079 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00008080
8081 stage[1] = "Reading from database."
8082 self.logger.info(stage[1])
8083 self._write_ns_status(
8084 nsr_id=nsr_id,
8085 ns_state=None,
8086 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00008087 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00008088 )
8089 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
8090
8091 # read from db: ns
8092 stage[1] = "Getting nsr={} from db.".format(nsr_id)
8093 db_nsr_update["operational-status"] = operation_type
8094 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8095 # Payload for RO
8096 desc = {
8097 operation_type: {
8098 "vim_vm_id": vim_vm_id,
8099 "vnf_id": vnf_id,
8100 "vdu_index": additional_param["count-index"],
8101 "vdu_id": vdur["id"],
8102 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00008103 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00008104 }
8105 }
8106 stage[1] = "Sending rebuild request to RO... {}".format(desc)
8107 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
8108 self.logger.info("ro nsr id: {}".format(nsr_id))
8109 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
8110 self.logger.info("response from RO: {}".format(result_dict))
8111 action_id = result_dict["action_id"]
8112 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008113 nsr_id,
8114 action_id,
8115 nslcmop_id,
8116 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00008117 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00008118 None,
8119 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00008120 )
8121 return "COMPLETED", "Done"
8122 except (ROclient.ROClientException, DbException, LcmException) as e:
8123 self.logger.error("Exit Exception {}".format(e))
8124 exc = e
8125 except asyncio.CancelledError:
8126 self.logger.error("Cancelled Exception while '{}'".format(stage))
8127 exc = "Operation was cancelled"
8128 except Exception as e:
8129 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00008130 self.logger.critical(
8131 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8132 )
k4.rahulb827de92022-05-02 16:35:02 +00008133 return "FAILED", "Error in operate VNF {}".format(exc)
8134
elumalai80bcf1c2022-04-28 18:05:01 +05308135 async def migrate(self, nsr_id, nslcmop_id):
8136 """
8137 Migrate VNFs and VDUs instances in a NS
8138
8139 :param: nsr_id: NS Instance ID
8140 :param: nslcmop_id: nslcmop ID of migrate
8141
8142 """
8143 # Try to lock HA task here
8144 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8145 if not task_is_locked_by_me:
8146 return
8147 logging_text = "Task ns={} migrate ".format(nsr_id)
8148 self.logger.debug(logging_text + "Enter")
8149 # get all needed from database
8150 db_nslcmop = None
8151 db_nslcmop_update = {}
8152 nslcmop_operation_state = None
8153 db_nsr_update = {}
8154 target = {}
8155 exc = None
8156 # in case of error, indicates what part of scale was failed to put nsr at error status
8157 start_deploy = time()
8158
8159 try:
8160 # wait for any previous tasks in process
8161 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03008162 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05308163
8164 self._write_ns_status(
8165 nsr_id=nsr_id,
8166 ns_state=None,
8167 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03008168 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05308169 )
8170 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03008171 self.logger.debug(
8172 step + " after having waited for previous tasks to be completed"
8173 )
elumalai80bcf1c2022-04-28 18:05:01 +05308174 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8175 migrate_params = db_nslcmop.get("operationParams")
8176
8177 target = {}
8178 target.update(migrate_params)
Pedro Pereirab6cccb22024-08-23 10:23:02 +01008179
8180 if "migrateToHost" in target:
8181 desc = await self.RO.migrate(nsr_id, target)
8182 self.logger.debug("RO return > {}".format(desc))
8183 action_id = desc["action_id"]
8184 await self._wait_ng_ro(
8185 nsr_id,
8186 action_id,
8187 nslcmop_id,
8188 start_deploy,
8189 self.timeout.migrate,
8190 operation="migrate",
8191 )
8192
8193 elif "targetHostK8sLabels" in target:
8194 await self.k8sclusterhelm3.migrate(nsr_id, target)
8195
elumalai80bcf1c2022-04-28 18:05:01 +05308196 except (ROclient.ROClientException, DbException, LcmException) as e:
8197 self.logger.error("Exit Exception {}".format(e))
8198 exc = e
8199 except asyncio.CancelledError:
8200 self.logger.error("Cancelled Exception while '{}'".format(step))
8201 exc = "Operation was cancelled"
8202 except Exception as e:
8203 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03008204 self.logger.critical(
8205 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8206 )
elumalai80bcf1c2022-04-28 18:05:01 +05308207 finally:
8208 self._write_ns_status(
8209 nsr_id=nsr_id,
8210 ns_state=None,
8211 current_operation="IDLE",
8212 current_operation_id=None,
8213 )
8214 if exc:
aticig349aa462022-05-19 12:29:35 +03008215 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308216 nslcmop_operation_state = "FAILED"
8217 else:
8218 nslcmop_operation_state = "COMPLETED"
8219 db_nslcmop_update["detailed-status"] = "Done"
8220 db_nsr_update["detailed-status"] = "Done"
8221
8222 self._write_op_status(
8223 op_id=nslcmop_id,
8224 stage="",
8225 error_message="",
8226 operation_state=nslcmop_operation_state,
8227 other_update=db_nslcmop_update,
8228 )
8229 if nslcmop_operation_state:
8230 try:
8231 msg = {
8232 "nsr_id": nsr_id,
8233 "nslcmop_id": nslcmop_id,
8234 "operationState": nslcmop_operation_state,
8235 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008236 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308237 except Exception as e:
8238 self.logger.error(
8239 logging_text + "kafka_write notification Exception {}".format(e)
8240 )
8241 self.logger.debug(logging_text + "Exit")
8242 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008243
garciadeblas07f4e4c2022-06-09 09:42:58 +02008244 async def heal(self, nsr_id, nslcmop_id):
8245 """
8246 Heal NS
8247
8248 :param nsr_id: ns instance to heal
8249 :param nslcmop_id: operation to run
8250 :return:
8251 """
8252
8253 # Try to lock HA task here
8254 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8255 if not task_is_locked_by_me:
8256 return
8257
8258 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8259 stage = ["", "", ""]
8260 tasks_dict_info = {}
8261 # ^ stage, step, VIM progress
8262 self.logger.debug(logging_text + "Enter")
8263 # get all needed from database
8264 db_nsr = None
8265 db_nslcmop_update = {}
8266 db_nsr_update = {}
8267 db_vnfrs = {} # vnf's info indexed by _id
8268 exc = None
8269 old_operational_status = ""
8270 old_config_status = ""
8271 nsi_id = None
8272 try:
8273 # wait for any previous tasks in process
8274 step = "Waiting for previous operations to terminate"
8275 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8276 self._write_ns_status(
8277 nsr_id=nsr_id,
8278 ns_state=None,
8279 current_operation="HEALING",
8280 current_operation_id=nslcmop_id,
8281 )
8282
8283 step = "Getting nslcmop from database"
8284 self.logger.debug(
8285 step + " after having waited for previous tasks to be completed"
8286 )
8287 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8288
8289 step = "Getting nsr from database"
8290 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8291 old_operational_status = db_nsr["operational-status"]
8292 old_config_status = db_nsr["config-status"]
8293
8294 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008295 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008296 "_admin.deployed.RO.operational-status": "healing",
8297 }
8298 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8299
8300 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008301 await self.heal_RO(
8302 logging_text=logging_text,
8303 nsr_id=nsr_id,
8304 db_nslcmop=db_nslcmop,
8305 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008306 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008307 # VCA tasks
8308 # read from db: nsd
8309 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8310 self.logger.debug(logging_text + stage[1])
8311 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8312 self.fs.sync(db_nsr["nsd-id"])
8313 db_nsr["nsd"] = nsd
8314 # read from db: vnfr's of this ns
8315 step = "Getting vnfrs from db"
8316 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8317 for vnfr in db_vnfrs_list:
8318 db_vnfrs[vnfr["_id"]] = vnfr
8319 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8320
8321 # Check for each target VNF
8322 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8323 for target_vnf in target_list:
8324 # Find this VNF in the list from DB
8325 vnfr_id = target_vnf.get("vnfInstanceId", None)
8326 if vnfr_id:
8327 db_vnfr = db_vnfrs[vnfr_id]
8328 vnfd_id = db_vnfr.get("vnfd-id")
8329 vnfd_ref = db_vnfr.get("vnfd-ref")
8330 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8331 base_folder = vnfd["_admin"]["storage"]
8332 vdu_id = None
8333 vdu_index = 0
8334 vdu_name = None
8335 kdu_name = None
8336 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8337 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8338
8339 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008340 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8341 "vdu", []
8342 )
garciadeblas50639832022-09-01 13:09:47 +02008343 if not target_vdu_list:
8344 # Codigo nuevo para crear diccionario
8345 target_vdu_list = []
8346 for existing_vdu in db_vnfr.get("vdur"):
8347 vdu_name = existing_vdu.get("vdu-name", None)
8348 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008349 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8350 "run-day1", False
8351 )
8352 vdu_to_be_healed = {
8353 "vdu-id": vdu_name,
8354 "count-index": vdu_index,
8355 "run-day1": vdu_run_day1,
8356 }
garciadeblas50639832022-09-01 13:09:47 +02008357 target_vdu_list.append(vdu_to_be_healed)
8358 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008359 deploy_params_vdu = target_vdu
8360 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008361 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8362 "additionalParams", {}
8363 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008364 deploy_params_vdu["run-day1"] = target_vnf[
8365 "additionalParams"
8366 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008367 vdu_name = target_vdu.get("vdu-id", None)
8368 # TODO: Get vdu_id from vdud.
8369 vdu_id = vdu_name
8370 # For multi instance VDU count-index is mandatory
8371 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008372 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008373
8374 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8375 stage[1] = "Deploying Execution Environments."
8376 self.logger.debug(logging_text + stage[1])
8377
8378 # VNF Level charm. Normal case when proxy charms.
8379 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8380 descriptor_config = get_configuration(vnfd, vnfd_ref)
8381 if descriptor_config:
8382 # Continue if healed machine is management machine
8383 vnf_ip_address = db_vnfr.get("ip-address")
8384 target_instance = None
8385 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008386 if (
8387 instance["vdu-name"] == vdu_name
8388 and instance["count-index"] == vdu_index
8389 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008390 target_instance = instance
8391 break
8392 if vnf_ip_address == target_instance.get("ip-address"):
8393 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008394 logging_text=logging_text
8395 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8396 member_vnf_index, vdu_name, vdu_index
8397 ),
8398 db_nsr=db_nsr,
8399 db_vnfr=db_vnfr,
8400 nslcmop_id=nslcmop_id,
8401 nsr_id=nsr_id,
8402 nsi_id=nsi_id,
8403 vnfd_id=vnfd_ref,
8404 vdu_id=None,
8405 kdu_name=None,
8406 member_vnf_index=member_vnf_index,
8407 vdu_index=0,
8408 vdu_name=None,
8409 deploy_params=deploy_params_vdu,
8410 descriptor_config=descriptor_config,
8411 base_folder=base_folder,
8412 task_instantiation_info=tasks_dict_info,
8413 stage=stage,
8414 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008415
8416 # VDU Level charm. Normal case with native charms.
8417 descriptor_config = get_configuration(vnfd, vdu_name)
8418 if descriptor_config:
8419 self._heal_n2vc(
8420 logging_text=logging_text
8421 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8422 member_vnf_index, vdu_name, vdu_index
8423 ),
8424 db_nsr=db_nsr,
8425 db_vnfr=db_vnfr,
8426 nslcmop_id=nslcmop_id,
8427 nsr_id=nsr_id,
8428 nsi_id=nsi_id,
8429 vnfd_id=vnfd_ref,
8430 vdu_id=vdu_id,
8431 kdu_name=kdu_name,
8432 member_vnf_index=member_vnf_index,
8433 vdu_index=vdu_index,
8434 vdu_name=vdu_name,
8435 deploy_params=deploy_params_vdu,
8436 descriptor_config=descriptor_config,
8437 base_folder=base_folder,
8438 task_instantiation_info=tasks_dict_info,
8439 stage=stage,
8440 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008441 except (
8442 ROclient.ROClientException,
8443 DbException,
8444 LcmException,
8445 NgRoException,
8446 ) as e:
8447 self.logger.error(logging_text + "Exit Exception {}".format(e))
8448 exc = e
8449 except asyncio.CancelledError:
8450 self.logger.error(
8451 logging_text + "Cancelled Exception while '{}'".format(step)
8452 )
8453 exc = "Operation was cancelled"
8454 except Exception as e:
8455 exc = traceback.format_exc()
8456 self.logger.critical(
8457 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8458 exc_info=True,
8459 )
8460 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008461 error_list = list()
36970544ef442024-04-01 10:58:42 +00008462 if db_vnfrs_list and target_list:
8463 for vnfrs in db_vnfrs_list:
8464 for vnf_instance in target_list:
8465 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8466 self.db.set_list(
8467 "vnfrs",
8468 {"_id": vnfrs["_id"]},
8469 {"_admin.modified": time()},
8470 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008471 if exc:
8472 error_list.append(str(exc))
8473 try:
8474 if tasks_dict_info:
8475 stage[1] = "Waiting for healing pending tasks."
8476 self.logger.debug(logging_text + stage[1])
8477 exc = await self._wait_for_tasks(
8478 logging_text,
8479 tasks_dict_info,
8480 self.timeout.ns_deploy,
8481 stage,
8482 nslcmop_id,
8483 nsr_id=nsr_id,
8484 )
8485 except asyncio.CancelledError:
8486 error_list.append("Cancelled")
8487 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8488 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008489 logging_text,
8490 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008491 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008492 stage,
8493 nslcmop_id,
8494 nsr_id=nsr_id,
8495 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008496 if error_list:
8497 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008498 db_nslcmop_update[
8499 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008500 ] = error_description_nslcmop = "FAILED {}: {}".format(
8501 step, error_detail
8502 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008503 nslcmop_operation_state = "FAILED"
8504 if db_nsr:
8505 db_nsr_update["operational-status"] = old_operational_status
8506 db_nsr_update["config-status"] = old_config_status
8507 db_nsr_update[
8508 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008509 ] = "FAILED healing nslcmop={} {}: {}".format(
8510 nslcmop_id, step, error_detail
8511 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008512 for task, task_name in tasks_dict_info.items():
8513 if not task.done() or task.cancelled() or task.exception():
8514 if task_name.startswith(self.task_name_deploy_vca):
8515 # A N2VC task is pending
8516 db_nsr_update["config-status"] = "failed"
8517 else:
8518 # RO task is pending
8519 db_nsr_update["operational-status"] = "failed"
8520 else:
8521 error_description_nslcmop = None
8522 nslcmop_operation_state = "COMPLETED"
8523 db_nslcmop_update["detailed-status"] = "Done"
8524 db_nsr_update["detailed-status"] = "Done"
8525 db_nsr_update["operational-status"] = "running"
8526 db_nsr_update["config-status"] = "configured"
8527
8528 self._write_op_status(
8529 op_id=nslcmop_id,
8530 stage="",
8531 error_message=error_description_nslcmop,
8532 operation_state=nslcmop_operation_state,
8533 other_update=db_nslcmop_update,
8534 )
8535 if db_nsr:
8536 self._write_ns_status(
8537 nsr_id=nsr_id,
8538 ns_state=None,
8539 current_operation="IDLE",
8540 current_operation_id=None,
8541 other_update=db_nsr_update,
8542 )
8543
8544 if nslcmop_operation_state:
8545 try:
8546 msg = {
8547 "nsr_id": nsr_id,
8548 "nslcmop_id": nslcmop_id,
8549 "operationState": nslcmop_operation_state,
8550 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008551 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008552 except Exception as e:
8553 self.logger.error(
8554 logging_text + "kafka_write notification Exception {}".format(e)
8555 )
8556 self.logger.debug(logging_text + "Exit")
8557 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8558
8559 async def heal_RO(
8560 self,
8561 logging_text,
8562 nsr_id,
8563 db_nslcmop,
8564 stage,
8565 ):
8566 """
8567 Heal at RO
8568 :param logging_text: preffix text to use at logging
8569 :param nsr_id: nsr identity
8570 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8571 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8572 :return: None or exception
8573 """
preethika.p28b0bf82022-09-23 07:36:28 +00008574
garciadeblas07f4e4c2022-06-09 09:42:58 +02008575 def get_vim_account(vim_account_id):
Anirudh Guptac2be9492025-05-13 05:53:38 +00008576 # nonlocal db_vims
garciadeblas07f4e4c2022-06-09 09:42:58 +02008577 if vim_account_id in db_vims:
8578 return db_vims[vim_account_id]
8579 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8580 db_vims[vim_account_id] = db_vim
8581 return db_vim
8582
8583 try:
8584 start_heal = time()
8585 ns_params = db_nslcmop.get("operationParams")
8586 if ns_params and ns_params.get("timeout_ns_heal"):
8587 timeout_ns_heal = ns_params["timeout_ns_heal"]
8588 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008589 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008590
8591 db_vims = {}
8592
8593 nslcmop_id = db_nslcmop["_id"]
8594 target = {
8595 "action_id": nslcmop_id,
8596 }
preethika.p28b0bf82022-09-23 07:36:28 +00008597 self.logger.warning(
8598 "db_nslcmop={} and timeout_ns_heal={}".format(
8599 db_nslcmop, timeout_ns_heal
8600 )
8601 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008602 target.update(db_nslcmop.get("operationParams", {}))
8603
8604 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8605 desc = await self.RO.recreate(nsr_id, target)
8606 self.logger.debug("RO return > {}".format(desc))
8607 action_id = desc["action_id"]
8608 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8609 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008610 nsr_id,
8611 action_id,
8612 nslcmop_id,
8613 start_heal,
8614 timeout_ns_heal,
8615 stage,
8616 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008617 )
8618
8619 # Updating NSR
8620 db_nsr_update = {
8621 "_admin.deployed.RO.operational-status": "running",
8622 "detailed-status": " ".join(stage),
8623 }
8624 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8625 self._write_op_status(nslcmop_id, stage)
8626 self.logger.debug(
8627 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8628 )
8629
8630 except Exception as e:
8631 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008632 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008633 self.logger.error(
8634 "Error healing at VIM {}".format(e),
8635 exc_info=not isinstance(
8636 e,
8637 (
8638 ROclient.ROClientException,
8639 LcmException,
8640 DbException,
8641 NgRoException,
8642 ),
8643 ),
8644 )
8645 raise
8646
8647 def _heal_n2vc(
8648 self,
8649 logging_text,
8650 db_nsr,
8651 db_vnfr,
8652 nslcmop_id,
8653 nsr_id,
8654 nsi_id,
8655 vnfd_id,
8656 vdu_id,
8657 kdu_name,
8658 member_vnf_index,
8659 vdu_index,
8660 vdu_name,
8661 deploy_params,
8662 descriptor_config,
8663 base_folder,
8664 task_instantiation_info,
8665 stage,
8666 ):
8667 # launch instantiate_N2VC in a asyncio task and register task object
8668 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8669 # if not found, create one entry and update database
8670 # fill db_nsr._admin.deployed.VCA.<index>
8671
8672 self.logger.debug(
8673 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8674 )
aticig9bc63ac2022-07-27 09:32:06 +03008675
8676 charm_name = ""
8677 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008678 if "execution-environment-list" in descriptor_config:
8679 ee_list = descriptor_config.get("execution-environment-list", [])
8680 elif "juju" in descriptor_config:
8681 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008682 if "execution-environment-list" not in descriptor_config:
8683 # charm name is only required for ns charms
8684 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008685 else: # other types as script are not supported
8686 ee_list = []
8687
8688 for ee_item in ee_list:
8689 self.logger.debug(
8690 logging_text
8691 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8692 ee_item.get("juju"), ee_item.get("helm-chart")
8693 )
8694 )
8695 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008696 vca_name, charm_name, vca_type = self.get_vca_info(
8697 ee_item, db_nsr, get_charm_name
8698 )
8699 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008700 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008701 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008702 )
8703 continue
8704
8705 vca_index = -1
8706 for vca_index, vca_deployed in enumerate(
8707 db_nsr["_admin"]["deployed"]["VCA"]
8708 ):
8709 if not vca_deployed:
8710 continue
8711 if (
8712 vca_deployed.get("member-vnf-index") == member_vnf_index
8713 and vca_deployed.get("vdu_id") == vdu_id
8714 and vca_deployed.get("kdu_name") == kdu_name
8715 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8716 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8717 ):
8718 break
8719 else:
8720 # not found, create one.
8721 target = (
8722 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8723 )
8724 if vdu_id:
8725 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8726 elif kdu_name:
8727 target += "/kdu/{}".format(kdu_name)
8728 vca_deployed = {
8729 "target_element": target,
8730 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8731 "member-vnf-index": member_vnf_index,
8732 "vdu_id": vdu_id,
8733 "kdu_name": kdu_name,
8734 "vdu_count_index": vdu_index,
8735 "operational-status": "init", # TODO revise
8736 "detailed-status": "", # TODO revise
8737 "step": "initial-deploy", # TODO revise
8738 "vnfd_id": vnfd_id,
8739 "vdu_name": vdu_name,
8740 "type": vca_type,
8741 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008742 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008743 }
8744 vca_index += 1
8745
8746 # create VCA and configurationStatus in db
8747 db_dict = {
8748 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8749 "configurationStatus.{}".format(vca_index): dict(),
8750 }
8751 self.update_db_2("nsrs", nsr_id, db_dict)
8752
8753 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8754
8755 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8756 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8757 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8758
8759 # Launch task
8760 task_n2vc = asyncio.ensure_future(
8761 self.heal_N2VC(
8762 logging_text=logging_text,
8763 vca_index=vca_index,
8764 nsi_id=nsi_id,
8765 db_nsr=db_nsr,
8766 db_vnfr=db_vnfr,
8767 vdu_id=vdu_id,
8768 kdu_name=kdu_name,
8769 vdu_index=vdu_index,
8770 deploy_params=deploy_params,
8771 config_descriptor=descriptor_config,
8772 base_folder=base_folder,
8773 nslcmop_id=nslcmop_id,
8774 stage=stage,
8775 vca_type=vca_type,
8776 vca_name=vca_name,
8777 ee_config_descriptor=ee_item,
8778 )
8779 )
8780 self.lcm_tasks.register(
8781 "ns",
8782 nsr_id,
8783 nslcmop_id,
8784 "instantiate_N2VC-{}".format(vca_index),
8785 task_n2vc,
8786 )
8787 task_instantiation_info[
8788 task_n2vc
8789 ] = self.task_name_deploy_vca + " {}.{}".format(
8790 member_vnf_index or "", vdu_id or ""
8791 )
8792
8793 async def heal_N2VC(
8794 self,
8795 logging_text,
8796 vca_index,
8797 nsi_id,
8798 db_nsr,
8799 db_vnfr,
8800 vdu_id,
8801 kdu_name,
8802 vdu_index,
8803 config_descriptor,
8804 deploy_params,
8805 base_folder,
8806 nslcmop_id,
8807 stage,
8808 vca_type,
8809 vca_name,
8810 ee_config_descriptor,
8811 ):
8812 nsr_id = db_nsr["_id"]
8813 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8814 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8815 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8816 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8817 db_dict = {
8818 "collection": "nsrs",
8819 "filter": {"_id": nsr_id},
8820 "path": db_update_entry,
8821 }
8822 step = ""
8823 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008824 element_type = "NS"
8825 element_under_configuration = nsr_id
8826
8827 vnfr_id = None
8828 if db_vnfr:
8829 vnfr_id = db_vnfr["_id"]
8830 osm_config["osm"]["vnf_id"] = vnfr_id
8831
8832 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8833
8834 if vca_type == "native_charm":
8835 index_number = 0
8836 else:
8837 index_number = vdu_index or 0
8838
8839 if vnfr_id:
8840 element_type = "VNF"
8841 element_under_configuration = vnfr_id
8842 namespace += ".{}-{}".format(vnfr_id, index_number)
8843 if vdu_id:
8844 namespace += ".{}-{}".format(vdu_id, index_number)
8845 element_type = "VDU"
8846 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8847 osm_config["osm"]["vdu_id"] = vdu_id
8848 elif kdu_name:
8849 namespace += ".{}".format(kdu_name)
8850 element_type = "KDU"
8851 element_under_configuration = kdu_name
8852 osm_config["osm"]["kdu_name"] = kdu_name
8853
8854 # Get artifact path
8855 if base_folder["pkg-dir"]:
8856 artifact_path = "{}/{}/{}/{}".format(
8857 base_folder["folder"],
8858 base_folder["pkg-dir"],
8859 "charms"
8860 if vca_type
8861 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8862 else "helm-charts",
8863 vca_name,
8864 )
8865 else:
8866 artifact_path = "{}/Scripts/{}/{}/".format(
8867 base_folder["folder"],
8868 "charms"
8869 if vca_type
8870 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8871 else "helm-charts",
8872 vca_name,
8873 )
8874
8875 self.logger.debug("Artifact path > {}".format(artifact_path))
8876
8877 # get initial_config_primitive_list that applies to this element
8878 initial_config_primitive_list = config_descriptor.get(
8879 "initial-config-primitive"
8880 )
8881
8882 self.logger.debug(
8883 "Initial config primitive list > {}".format(
8884 initial_config_primitive_list
8885 )
8886 )
8887
8888 # add config if not present for NS charm
8889 ee_descriptor_id = ee_config_descriptor.get("id")
8890 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8891 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8892 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8893 )
8894
8895 self.logger.debug(
8896 "Initial config primitive list #2 > {}".format(
8897 initial_config_primitive_list
8898 )
8899 )
8900 # n2vc_redesign STEP 3.1
8901 # find old ee_id if exists
8902 ee_id = vca_deployed.get("ee_id")
8903
8904 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8905 # create or register execution environment in VCA. Only for native charms when healing
8906 if vca_type == "native_charm":
8907 step = "Waiting to VM being up and getting IP address"
8908 self.logger.debug(logging_text + step)
8909 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8910 logging_text,
8911 nsr_id,
8912 vnfr_id,
8913 vdu_id,
8914 vdu_index,
8915 user=None,
8916 pub_key=None,
8917 )
8918 credentials = {"hostname": rw_mgmt_ip}
8919 # get username
8920 username = deep_get(
8921 config_descriptor, ("config-access", "ssh-access", "default-user")
8922 )
8923 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8924 # merged. Meanwhile let's get username from initial-config-primitive
8925 if not username and initial_config_primitive_list:
8926 for config_primitive in initial_config_primitive_list:
8927 for param in config_primitive.get("parameter", ()):
8928 if param["name"] == "ssh-username":
8929 username = param["value"]
8930 break
8931 if not username:
8932 raise LcmException(
8933 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8934 "'config-access.ssh-access.default-user'"
8935 )
8936 credentials["username"] = username
8937
8938 # n2vc_redesign STEP 3.2
8939 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8940 self._write_configuration_status(
8941 nsr_id=nsr_id,
8942 vca_index=vca_index,
8943 status="REGISTERING",
8944 element_under_configuration=element_under_configuration,
8945 element_type=element_type,
8946 )
8947
8948 step = "register execution environment {}".format(credentials)
8949 self.logger.debug(logging_text + step)
8950 ee_id = await self.vca_map[vca_type].register_execution_environment(
8951 credentials=credentials,
8952 namespace=namespace,
8953 db_dict=db_dict,
8954 vca_id=vca_id,
8955 )
8956
8957 # update ee_id en db
8958 db_dict_ee_id = {
8959 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8960 }
8961 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8962
8963 # for compatibility with MON/POL modules, the need model and application name at database
8964 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8965 # Not sure if this need to be done when healing
8966 """
8967 ee_id_parts = ee_id.split(".")
8968 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8969 if len(ee_id_parts) >= 2:
8970 model_name = ee_id_parts[0]
8971 application_name = ee_id_parts[1]
8972 db_nsr_update[db_update_entry + "model"] = model_name
8973 db_nsr_update[db_update_entry + "application"] = application_name
8974 """
8975
8976 # n2vc_redesign STEP 3.3
8977 # Install configuration software. Only for native charms.
8978 step = "Install configuration Software"
8979
8980 self._write_configuration_status(
8981 nsr_id=nsr_id,
8982 vca_index=vca_index,
8983 status="INSTALLING SW",
8984 element_under_configuration=element_under_configuration,
8985 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008986 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008987 other_update=None,
8988 )
8989
8990 # TODO check if already done
8991 self.logger.debug(logging_text + step)
8992 config = None
8993 if vca_type == "native_charm":
8994 config_primitive = next(
8995 (p for p in initial_config_primitive_list if p["name"] == "config"),
8996 None,
8997 )
8998 if config_primitive:
8999 config = self._map_primitive_params(
9000 config_primitive, {}, deploy_params
9001 )
9002 await self.vca_map[vca_type].install_configuration_sw(
9003 ee_id=ee_id,
9004 artifact_path=artifact_path,
9005 db_dict=db_dict,
9006 config=config,
9007 num_units=1,
9008 vca_id=vca_id,
9009 vca_type=vca_type,
9010 )
9011
9012 # write in db flag of configuration_sw already installed
9013 self.update_db_2(
9014 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
9015 )
9016
9017 # Not sure if this need to be done when healing
9018 """
9019 # add relations for this VCA (wait for other peers related with this VCA)
9020 await self._add_vca_relations(
9021 logging_text=logging_text,
9022 nsr_id=nsr_id,
9023 vca_type=vca_type,
9024 vca_index=vca_index,
9025 )
9026 """
9027
9028 # if SSH access is required, then get execution environment SSH public
9029 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00009030 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02009031 pub_key = None
9032 user = None
9033 # self.logger.debug("get ssh key block")
9034 if deep_get(
9035 config_descriptor, ("config-access", "ssh-access", "required")
9036 ):
9037 # self.logger.debug("ssh key needed")
9038 # Needed to inject a ssh key
9039 user = deep_get(
9040 config_descriptor,
9041 ("config-access", "ssh-access", "default-user"),
9042 )
9043 step = "Install configuration Software, getting public ssh key"
9044 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
9045 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
9046 )
9047
9048 step = "Insert public key into VM user={} ssh_key={}".format(
9049 user, pub_key
9050 )
9051 else:
9052 # self.logger.debug("no need to get ssh key")
9053 step = "Waiting to VM being up and getting IP address"
9054 self.logger.debug(logging_text + step)
9055
9056 # n2vc_redesign STEP 5.1
9057 # wait for RO (ip-address) Insert pub_key into VM
9058 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00009059 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009060 if vnfr_id:
9061 if kdu_name:
9062 rw_mgmt_ip = await self.wait_kdu_up(
9063 logging_text, nsr_id, vnfr_id, kdu_name
9064 )
9065 else:
9066 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
9067 logging_text,
9068 nsr_id,
9069 vnfr_id,
9070 vdu_id,
9071 vdu_index,
9072 user=user,
9073 pub_key=pub_key,
9074 )
9075 else:
9076 rw_mgmt_ip = None # This is for a NS configuration
9077
9078 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
9079
9080 # store rw_mgmt_ip in deploy params for later replacement
9081 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
9082
9083 # Day1 operations.
9084 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00009085 runDay1 = deploy_params.get("run-day1", False)
9086 self.logger.debug(
9087 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
9088 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02009089 if runDay1:
9090 # n2vc_redesign STEP 6 Execute initial config primitive
9091 step = "execute initial config primitive"
9092
9093 # wait for dependent primitives execution (NS -> VNF -> VDU)
9094 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00009095 await self._wait_dependent_n2vc(
9096 nsr_id, vca_deployed_list, vca_index
9097 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02009098
9099 # stage, in function of element type: vdu, kdu, vnf or ns
9100 my_vca = vca_deployed_list[vca_index]
9101 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
9102 # VDU or KDU
9103 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
9104 elif my_vca.get("member-vnf-index"):
9105 # VNF
9106 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
9107 else:
9108 # NS
9109 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
9110
9111 self._write_configuration_status(
9112 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
9113 )
9114
9115 self._write_op_status(op_id=nslcmop_id, stage=stage)
9116
9117 check_if_terminated_needed = True
9118 for initial_config_primitive in initial_config_primitive_list:
9119 # adding information on the vca_deployed if it is a NS execution environment
9120 if not vca_deployed["member-vnf-index"]:
9121 deploy_params["ns_config_info"] = json.dumps(
9122 self._get_ns_config_info(nsr_id)
9123 )
9124 # TODO check if already done
9125 primitive_params_ = self._map_primitive_params(
9126 initial_config_primitive, {}, deploy_params
9127 )
9128
9129 step = "execute primitive '{}' params '{}'".format(
9130 initial_config_primitive["name"], primitive_params_
9131 )
9132 self.logger.debug(logging_text + step)
9133 await self.vca_map[vca_type].exec_primitive(
9134 ee_id=ee_id,
9135 primitive_name=initial_config_primitive["name"],
9136 params_dict=primitive_params_,
9137 db_dict=db_dict,
9138 vca_id=vca_id,
9139 vca_type=vca_type,
9140 )
9141 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
9142 if check_if_terminated_needed:
9143 if config_descriptor.get("terminate-config-primitive"):
9144 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00009145 "nsrs",
9146 nsr_id,
9147 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02009148 )
9149 check_if_terminated_needed = False
9150
9151 # TODO register in database that primitive is done
9152
9153 # STEP 7 Configure metrics
9154 # Not sure if this need to be done when healing
9155 """
9156 if vca_type == "helm" or vca_type == "helm-v3":
9157 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
9158 ee_id=ee_id,
9159 artifact_path=artifact_path,
9160 ee_config_descriptor=ee_config_descriptor,
9161 vnfr_id=vnfr_id,
9162 nsr_id=nsr_id,
9163 target_ip=rw_mgmt_ip,
9164 )
9165 if prometheus_jobs:
9166 self.update_db_2(
9167 "nsrs",
9168 nsr_id,
9169 {db_update_entry + "prometheus_jobs": prometheus_jobs},
9170 )
9171
9172 for job in prometheus_jobs:
9173 self.db.set_one(
9174 "prometheus_jobs",
9175 {"job_name": job["job_name"]},
9176 job,
9177 upsert=True,
9178 fail_on_empty=False,
9179 )
9180
9181 """
9182 step = "instantiated at VCA"
9183 self.logger.debug(logging_text + step)
9184
9185 self._write_configuration_status(
9186 nsr_id=nsr_id, vca_index=vca_index, status="READY"
9187 )
9188
9189 except Exception as e: # TODO not use Exception but N2VC exception
9190 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
9191 if not isinstance(
9192 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
9193 ):
9194 self.logger.error(
9195 "Exception while {} : {}".format(step, e), exc_info=True
9196 )
9197 self._write_configuration_status(
9198 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
9199 )
9200 raise LcmException("{} {}".format(step, e)) from e
9201
9202 async def _wait_heal_ro(
9203 self,
9204 nsr_id,
9205 timeout=600,
9206 ):
9207 start_time = time()
9208 while time() <= start_time + timeout:
9209 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009210 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9211 "operational-status"
9212 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009213 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9214 if operational_status_ro != "healing":
9215 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009216 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009217 else: # timeout_ns_deploy
9218 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309219
9220 async def vertical_scale(self, nsr_id, nslcmop_id):
9221 """
9222 Vertical Scale the VDUs in a NS
9223
9224 :param: nsr_id: NS Instance ID
9225 :param: nslcmop_id: nslcmop ID of migrate
9226
9227 """
govindarajul4ff4b512022-05-02 20:02:41 +05309228 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05309229 self.logger.info(logging_text + "Enter")
9230 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05309231 # get all needed from database
9232 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05309233 db_nsr_update = {}
9234 target = {}
9235 exc = None
9236 # in case of error, indicates what part of scale was failed to put nsr at error status
9237 start_deploy = time()
9238
9239 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05309240 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9241 operationParams = db_nslcmop.get("operationParams")
9242 vertical_scale_data = operationParams["verticalScaleVnf"]
9243 vnfd_id = vertical_scale_data["vnfdId"]
9244 count_index = vertical_scale_data["countIndex"]
9245 vdu_id_ref = vertical_scale_data["vduId"]
9246 vnfr_id = vertical_scale_data["vnfInstanceId"]
9247 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9248 db_flavor = db_nsr.get("flavor")
9249 db_flavor_index = str(len(db_flavor))
9250
9251 def set_flavor_refrence_to_vdur(diff=0):
9252 """
9253 Utility function to add and remove the
9254 ref to new ns-flavor-id to vdurs
9255 :param: diff: default 0
9256 """
9257 q_filter = {}
9258 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9259 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9260 if (
9261 vdur.get("count-index") == count_index
9262 and vdur.get("vdu-id-ref") == vdu_id_ref
9263 ):
9264 filter_text = {
9265 "_id": vnfr_id,
9266 "vdur.count-index": count_index,
9267 "vdur.vdu-id-ref": vdu_id_ref,
9268 }
9269 q_filter.update(filter_text)
9270 db_update = {}
9271 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9272 int(db_flavor_index) - diff
9273 )
9274 self.db.set_one(
9275 "vnfrs",
9276 q_filter=q_filter,
9277 update_dict=db_update,
9278 fail_on_empty=True,
9279 )
9280
govindarajul4ff4b512022-05-02 20:02:41 +05309281 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309282 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009283 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309284
9285 self._write_ns_status(
9286 nsr_id=nsr_id,
9287 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309288 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009289 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309290 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309291 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009292 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309293 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009294 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309295 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9296 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9297 virtual_compute = vnfd["virtual-compute-desc"][0]
9298 virtual_memory = round(
9299 float(virtual_compute["virtual-memory"]["size"]) * 1024
9300 )
9301 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9302 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009303 flavor_dict_update = {
9304 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309305 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009306 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309307 "storage-gb": str(virtual_storage),
9308 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009309 }
9310 db_flavor.append(flavor_dict_update)
9311 db_update = {}
9312 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309313 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009314 "_id": nsr_id,
9315 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309316 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009317 self.db.set_one(
9318 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309319 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009320 update_dict=db_update,
9321 fail_on_empty=True,
9322 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309323 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309324 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309325 new_operationParams = {
9326 "lcmOperationType": "verticalscale",
9327 "verticalScale": "CHANGE_VNFFLAVOR",
9328 "nsInstanceId": nsr_id,
9329 "changeVnfFlavorData": {
9330 "vnfInstanceId": vnfr_id,
9331 "additionalParams": {
9332 "vduid": vdu_id_ref,
9333 "vduCountIndex": count_index,
9334 "virtualMemory": virtual_memory,
9335 "numVirtualCpu": int(virtual_cpu),
9336 "sizeOfStorage": int(virtual_storage),
9337 },
9338 },
9339 }
9340 target.update(new_operationParams)
9341
9342 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9343 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9344 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309345 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309346 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309347 action_id = desc["action_id"]
9348 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009349 nsr_id,
9350 action_id,
9351 nslcmop_id,
9352 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009353 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009354 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309355 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009356 except (
9357 NgRoException,
9358 ROclient.ROClientException,
9359 DbException,
9360 LcmException,
9361 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309362 self.logger.error("Exit Exception {}".format(e))
9363 exc = e
9364 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309365 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309366 exc = "Operation was cancelled"
9367 except Exception as e:
9368 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009369 self.logger.critical(
9370 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9371 )
govindarajul4ff4b512022-05-02 20:02:41 +05309372 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309373 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009374 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309375 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009376 )
9377 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309378 "nsrs",
9379 {"_id": nsr_id},
9380 None,
9381 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009382 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309383 set_flavor_refrence_to_vdur(diff=1)
9384 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9385 else:
9386 return "COMPLETED", "Done"