blob: a94794999c126ba0e5a8298c0a15870b509588aa [file] [log] [blame]
tierno59d22d22018-09-25 18:10:19 +02001# -*- coding: utf-8 -*-
2
tierno2e215512018-11-28 09:37:52 +00003##
4# Copyright 2018 Telefonica S.A.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17##
18
tierno59d22d22018-09-25 18:10:19 +020019import asyncio
aticigdffa6212022-04-12 15:27:53 +030020import shutil
David Garcia444bf962021-11-11 16:35:26 +010021from typing import Any, Dict, List
tierno59d22d22018-09-25 18:10:19 +020022import yaml
23import logging
24import logging.handlers
tierno59d22d22018-09-25 18:10:19 +020025import traceback
rahul72d90d92023-08-30 14:48:01 +053026import ipaddress
David Garciad4816682019-12-09 14:57:43 +010027import json
garciadeblas5697b8b2021-03-24 09:17:02 +010028from jinja2 import (
29 Environment,
30 TemplateError,
31 TemplateNotFound,
32 StrictUndefined,
33 UndefinedError,
garciadeblasef91e082022-08-02 15:12:18 +020034 select_autoescape,
garciadeblas5697b8b2021-03-24 09:17:02 +010035)
tierno59d22d22018-09-25 18:10:19 +020036
tierno77677d92019-08-22 13:46:35 +000037from osm_lcm import ROclient
Luis Vegaa27dc532022-11-11 20:10:49 +000038from osm_lcm.data_utils.lcm_config import LcmCfg
David Garciab4ebcd02021-10-28 02:00:43 +020039from osm_lcm.data_utils.nsr import (
40 get_deployed_kdu,
41 get_deployed_vca,
42 get_deployed_vca_list,
43 get_nsd,
44)
45from osm_lcm.data_utils.vca import (
46 DeployedComponent,
47 DeployedK8sResource,
48 DeployedVCA,
49 EELevel,
50 Relation,
51 EERelation,
52 safe_get_ee_relation,
53)
tierno69f0d382020-05-07 13:08:09 +000054from osm_lcm.ng_ro import NgRoClient, NgRoException
garciadeblas5697b8b2021-03-24 09:17:02 +010055from osm_lcm.lcm_utils import (
56 LcmException,
garciadeblas5697b8b2021-03-24 09:17:02 +010057 LcmBase,
58 deep_get,
59 get_iterable,
60 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030061 check_juju_bundle_existence,
62 get_charm_artifact_path,
Gabriel Cubae539a8d2022-10-10 11:34:51 -050063 get_ee_id_parts,
Gabriel Cubac7737442023-02-14 13:09:18 -050064 vld_to_ro_ip_profile,
garciadeblas5697b8b2021-03-24 09:17:02 +010065)
David Garciab4ebcd02021-10-28 02:00:43 +020066from osm_lcm.data_utils.nsd import (
67 get_ns_configuration_relation_list,
68 get_vnf_profile,
69 get_vnf_profiles,
70)
garciadeblas5697b8b2021-03-24 09:17:02 +010071from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020072 get_kdu,
73 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020074 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010075 get_vdu_list,
76 get_vdu_profile,
77 get_ee_sorted_initial_config_primitive_list,
78 get_ee_sorted_terminate_config_primitive_list,
79 get_kdu_list,
80 get_virtual_link_profiles,
81 get_vdu,
82 get_configuration,
83 get_vdu_index,
84 get_scaling_aspect,
85 get_number_of_instances,
86 get_juju_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020087 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030088 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050089 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010090)
bravof922c4172020-11-24 21:21:43 -030091from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030092from osm_lcm.data_utils.vnfr import (
93 get_osm_params,
94 get_vdur_index,
95 get_kdur,
96 get_volumes_from_instantiation_params,
97)
bravof922c4172020-11-24 21:21:43 -030098from osm_lcm.data_utils.dict_utils import parse_yaml_strings
99from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +0200100from n2vc.definitions import RelationEndpoint
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000101from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -0500102from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200103
tierno27246d82018-09-27 15:59:09 +0200104from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200105from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200106
bravof922c4172020-11-24 21:21:43 -0300107from osm_lcm.data_utils.database.database import Database
108from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000109from osm_lcm.data_utils.wim import (
110 get_sdn_ports,
111 get_target_wim_attrs,
112 select_feasible_wim_account,
113)
bravof922c4172020-11-24 21:21:43 -0300114
quilesj7e13aeb2019-10-08 13:34:55 +0200115from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000116from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200117
tierno588547c2020-07-01 15:30:20 +0000118from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200119from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400120from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000121
tierno27246d82018-09-27 15:59:09 +0200122from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200123from time import time
tierno27246d82018-09-27 15:59:09 +0200124from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000125
k4.rahulcf47a3b2023-04-27 12:08:48 +0530126from random import SystemRandom
tierno59d22d22018-09-25 18:10:19 +0200127
tierno69f0d382020-05-07 13:08:09 +0000128__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200129
130
131class NsLcm(LcmBase):
kuuseac3a8882019-10-03 10:48:06 +0200132 SUBOPERATION_STATUS_NOT_FOUND = -1
133 SUBOPERATION_STATUS_NEW = -2
134 SUBOPERATION_STATUS_SKIP = -3
Gabriel Cubaeb585dd2023-04-25 16:48:41 -0500135 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000136 task_name_deploy_vca = "Deploying VCA"
garciadeblas9148fa82023-05-30 12:51:14 +0200137 rel_operation_types = {
138 "GE": ">=",
139 "LE": "<=",
140 "GT": ">",
141 "LT": "<",
142 "EQ": "==",
143 "NE": "!=",
144 }
kuuseac3a8882019-10-03 10:48:06 +0200145
Gabriel Cubae7898982023-05-11 01:57:21 -0500146 def __init__(self, msg, lcm_tasks, config: LcmCfg):
tierno59d22d22018-09-25 18:10:19 +0200147 """
148 Init, Connect to database, filesystem storage, and messaging
149 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
150 :return: None
151 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100152 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200153
bravof922c4172020-11-24 21:21:43 -0300154 self.db = Database().instance.db
155 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200156 self.lcm_tasks = lcm_tasks
Luis Vegaa27dc532022-11-11 20:10:49 +0000157 self.timeout = config.timeout
158 self.ro_config = config.RO
159 self.vca_config = config.VCA
Rahul Kumar54671c52024-05-09 15:34:01 +0530160 self.service_kpi = config.servicekpi
tierno59d22d22018-09-25 18:10:19 +0200161
quilesj7e13aeb2019-10-08 13:34:55 +0200162 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100163 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200164 log=self.logger,
bravof922c4172020-11-24 21:21:43 -0300165 on_update_db=self._on_update_n2vc_db,
166 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100167 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200168 )
quilesj7e13aeb2019-10-08 13:34:55 +0200169
tierno588547c2020-07-01 15:30:20 +0000170 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000171 log=self.logger,
tierno588547c2020-07-01 15:30:20 +0000172 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100173 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000174 )
175
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000176 self.k8sclusterhelm3 = K8sHelm3Connector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000177 kubectl_command=self.vca_config.kubectlpath,
178 helm_command=self.vca_config.helm3path,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000179 fs=self.fs,
180 log=self.logger,
181 db=self.db,
182 on_update_db=None,
183 )
184
Adam Israelbaacc302019-12-01 12:41:39 -0500185 self.k8sclusterjuju = K8sJujuConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000186 kubectl_command=self.vca_config.kubectlpath,
187 juju_command=self.vca_config.jujupath,
Adam Israelbaacc302019-12-01 12:41:39 -0500188 log=self.logger,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530189 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300190 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100191 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500192 )
193
tiernoa2143262020-03-27 16:20:40 +0000194 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000195 "helm-chart-v3": self.k8sclusterhelm3,
196 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000197 "juju-bundle": self.k8sclusterjuju,
198 "juju": self.k8sclusterjuju,
199 }
tierno588547c2020-07-01 15:30:20 +0000200
201 self.vca_map = {
202 "lxc_proxy_charm": self.n2vc,
203 "native_charm": self.n2vc,
204 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000205 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100206 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000207 }
208
quilesj7e13aeb2019-10-08 13:34:55 +0200209 # create RO client
Gabriel Cubae7898982023-05-11 01:57:21 -0500210 self.RO = NgRoClient(**self.ro_config.to_dict())
tierno59d22d22018-09-25 18:10:19 +0200211
garciadeblas07f4e4c2022-06-09 09:42:58 +0200212 self.op_status_map = {
213 "instantiation": self.RO.status,
214 "termination": self.RO.status,
215 "migrate": self.RO.status,
216 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000217 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000218 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200219 }
220
tierno2357f4e2020-10-19 16:38:59 +0000221 @staticmethod
222 def increment_ip_mac(ip_mac, vm_index=1):
223 if not isinstance(ip_mac, str):
224 return ip_mac
225 try:
rahul72d90d92023-08-30 14:48:01 +0530226 next_ipv6 = None
227 next_ipv4 = None
228 dual_ip = ip_mac.split(";")
229 if len(dual_ip) == 2:
230 for ip in dual_ip:
231 if ipaddress.ip_address(ip).version == 6:
232 ipv6 = ipaddress.IPv6Address(ip)
233 next_ipv6 = str(ipaddress.IPv6Address(int(ipv6) + 1))
234 elif ipaddress.ip_address(ip).version == 4:
235 ipv4 = ipaddress.IPv4Address(ip)
236 next_ipv4 = str(ipaddress.IPv4Address(int(ipv4) + 1))
237 return [next_ipv4, next_ipv6]
tierno2357f4e2020-10-19 16:38:59 +0000238 # try with ipv4 look for last dot
239 i = ip_mac.rfind(".")
240 if i > 0:
241 i += 1
242 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
243 # try with ipv6 or mac look for last colon. Operate in hex
244 i = ip_mac.rfind(":")
245 if i > 0:
246 i += 1
247 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100248 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
249 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
250 )
tierno2357f4e2020-10-19 16:38:59 +0000251 except Exception:
252 pass
253 return None
254
David Garciac1fe90a2021-03-31 19:12:02 +0200255 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000256 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100257 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000258 path = path[:-1]
259
quilesj3655ae02019-12-12 16:08:35 +0000260 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
261 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000262 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100263 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000264
265 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100266 nsr = self.db.get_one(table="nsrs", q_filter=filter)
267 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000268
3697083243632024-06-07 05:44:08 +0000269 # First, we need to verify if the current vcaStatus is null, because if that is the case,
270 # MongoDB will not be able to create the fields used within the update key in the database
271 if not nsr.get("vcaStatus"):
272 # Write an empty dictionary to the vcaStatus field, it its value is null
273 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
274
275 # Get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100276 status_dict = await self.n2vc.get_status(
277 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
278 )
quilesj3655ae02019-12-12 16:08:35 +0000279
3697083243632024-06-07 05:44:08 +0000280 # Update the vcaStatus
281 db_key = f"vcaStatus.{nsr_id}.VNF"
quilesj3655ae02019-12-12 16:08:35 +0000282 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000283
284 db_dict[db_key] = status_dict[nsr_id]
285 await self.n2vc.update_vca_status(db_dict[db_key], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000286
287 # update configurationStatus for this VCA
288 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100289 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000290
garciadeblas5697b8b2021-03-24 09:17:02 +0100291 vca_list = deep_get(
292 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
293 )
294 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000295
garciadeblas5697b8b2021-03-24 09:17:02 +0100296 configuration_status_list = nsr.get("configurationStatus")
297 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000298
garciadeblas5697b8b2021-03-24 09:17:02 +0100299 if config_status == "BROKEN" and vca_status != "failed":
300 db_dict["configurationStatus"][vca_index] = "READY"
301 elif config_status != "BROKEN" and vca_status == "failed":
302 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000303 except Exception as e:
304 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100305 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000306
307 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
308 # if nsState = 'DEGRADED' check if all is OK
309 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100310 if current_ns_status in ("READY", "DEGRADED"):
311 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000312 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100313 if status_dict.get("machines"):
314 for machine_id in status_dict.get("machines"):
315 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000316 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100317 if machine.get("agent-status"):
318 s = machine.get("agent-status").get("status")
319 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000320 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100321 error_description += (
322 "machine {} agent-status={} ; ".format(
323 machine_id, s
324 )
325 )
quilesj3655ae02019-12-12 16:08:35 +0000326 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100327 if machine.get("instance-status"):
328 s = machine.get("instance-status").get("status")
329 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000330 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100331 error_description += (
332 "machine {} instance-status={} ; ".format(
333 machine_id, s
334 )
335 )
quilesj3655ae02019-12-12 16:08:35 +0000336 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100337 if status_dict.get("applications"):
338 for app_id in status_dict.get("applications"):
339 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000340 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100341 if app.get("status"):
342 s = app.get("status").get("status")
343 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000344 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100345 error_description += (
346 "application {} status={} ; ".format(app_id, s)
347 )
quilesj3655ae02019-12-12 16:08:35 +0000348
349 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100350 db_dict["errorDescription"] = error_description
351 if current_ns_status == "READY" and is_degraded:
352 db_dict["nsState"] = "DEGRADED"
353 if current_ns_status == "DEGRADED" and not is_degraded:
354 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000355
356 # write to database
357 self.update_db_2("nsrs", nsr_id, db_dict)
358
tierno51183952020-04-03 15:48:18 +0000359 except (asyncio.CancelledError, asyncio.TimeoutError):
360 raise
quilesj3655ae02019-12-12 16:08:35 +0000361 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100362 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200363
garciadeblas5697b8b2021-03-24 09:17:02 +0100364 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100365 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100366 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530367 """
368 Updating vca status in NSR record
369 :param cluster_uuid: UUID of a k8s cluster
370 :param kdu_instance: The unique name of the KDU instance
371 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100372 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530373 :return: none
374 """
375
376 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
377 # .format(cluster_uuid, kdu_instance, filter))
378
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100379 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530380 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100381 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
382 cluster_uuid=cluster_uuid,
383 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200384 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100385 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200386 vca_id=vca_id,
387 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100388
3697083243632024-06-07 05:44:08 +0000389 # First, we need to verify if the current vcaStatus is null, because if that is the case,
390 # MongoDB will not be able to create the fields used within the update key in the database
391 nsr = self.db.get_one(table="nsrs", q_filter=filter)
392 if not nsr.get("vcaStatus"):
393 # Write an empty dictionary to the vcaStatus field, it its value is null
394 self.update_db_2("nsrs", nsr_id, {"vcaStatus": dict()})
395
396 # Update the vcaStatus
397 db_key = f"vcaStatus.{nsr_id}.KNF"
ksaikiranr656b6dd2021-02-19 10:25:18 +0530398 db_dict = dict()
3697083243632024-06-07 05:44:08 +0000399
400 db_dict[db_key] = vca_status
401
402 if cluster_type in ("juju-bundle", "juju"):
403 # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA
404 # status in a similar way between Juju Bundles and Helm Charts on this side
405 await self.k8sclusterjuju.update_vca_status(
406 db_dict[db_key],
407 kdu_instance,
408 vca_id=vca_id,
409 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530410
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100411 self.logger.debug(
412 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200413 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530414
415 # write to database
416 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530417 except (asyncio.CancelledError, asyncio.TimeoutError):
418 raise
419 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100420 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530421
tierno72ef84f2020-10-06 08:22:07 +0000422 @staticmethod
423 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
424 try:
garciadeblasef91e082022-08-02 15:12:18 +0200425 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000426 undefined=StrictUndefined,
427 autoescape=select_autoescape(default_for_string=True, default=True),
428 )
tierno72ef84f2020-10-06 08:22:07 +0000429 template = env.from_string(cloud_init_text)
430 return template.render(additional_params or {})
431 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100432 raise LcmException(
433 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
434 "file, must be provided in the instantiation parameters inside the "
435 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
436 )
tierno72ef84f2020-10-06 08:22:07 +0000437 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100438 raise LcmException(
439 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
440 vnfd_id, vdu_id, e
441 )
442 )
tierno72ef84f2020-10-06 08:22:07 +0000443
bravof922c4172020-11-24 21:21:43 -0300444 def _get_vdu_cloud_init_content(self, vdu, vnfd):
445 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000446 try:
tierno72ef84f2020-10-06 08:22:07 +0000447 if vdu.get("cloud-init-file"):
448 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300449 if base_folder["pkg-dir"]:
450 cloud_init_file = "{}/{}/cloud_init/{}".format(
451 base_folder["folder"],
452 base_folder["pkg-dir"],
453 vdu["cloud-init-file"],
454 )
455 else:
456 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
457 base_folder["folder"],
458 vdu["cloud-init-file"],
459 )
tierno72ef84f2020-10-06 08:22:07 +0000460 with self.fs.file_open(cloud_init_file, "r") as ci_file:
461 cloud_init_content = ci_file.read()
462 elif vdu.get("cloud-init"):
463 cloud_init_content = vdu["cloud-init"]
464
465 return cloud_init_content
466 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100467 raise LcmException(
468 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
469 vnfd["id"], vdu["id"], cloud_init_file, e
470 )
471 )
tierno72ef84f2020-10-06 08:22:07 +0000472
tierno72ef84f2020-10-06 08:22:07 +0000473 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100474 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300475 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100476 )
tierno72ef84f2020-10-06 08:22:07 +0000477 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300478 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000479
tierno2357f4e2020-10-19 16:38:59 +0000480 @staticmethod
481 def ip_profile_2_RO(ip_profile):
482 RO_ip_profile = deepcopy(ip_profile)
483 if "dns-server" in RO_ip_profile:
484 if isinstance(RO_ip_profile["dns-server"], list):
485 RO_ip_profile["dns-address"] = []
486 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100487 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000488 else:
489 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
490 if RO_ip_profile.get("ip-version") == "ipv4":
491 RO_ip_profile["ip-version"] = "IPv4"
492 if RO_ip_profile.get("ip-version") == "ipv6":
493 RO_ip_profile["ip-version"] = "IPv6"
494 if "dhcp-params" in RO_ip_profile:
495 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
496 return RO_ip_profile
497
tierno2357f4e2020-10-19 16:38:59 +0000498 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000499 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000500 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000501 db_update = {"_admin.modified": time()}
502 if vdu_create:
503 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100504 vdur = next(
505 (
506 vdur
507 for vdur in reversed(db_vnfr["vdur"])
508 if vdur["vdu-id-ref"] == vdu_id
509 ),
510 None,
511 )
tierno2357f4e2020-10-19 16:38:59 +0000512 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000513 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300514 self.logger.debug(
515 "No vdur in the database. Using the vdur-template to scale"
516 )
vegall8d625f12022-03-22 16:23:30 +0000517 vdur_template = db_vnfr.get("vdur-template")
518 if not vdur_template:
519 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300520 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
521 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000522 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100523 )
vegall8d625f12022-03-22 16:23:30 +0000524 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300525 # Delete a template from the database after using it
526 self.db.set_one(
527 "vnfrs",
528 {"_id": db_vnfr["_id"]},
529 None,
530 pull={"vdur-template": {"_id": vdur["_id"]}},
531 )
tierno2357f4e2020-10-19 16:38:59 +0000532 for count in range(vdu_count):
533 vdur_copy = deepcopy(vdur)
534 vdur_copy["status"] = "BUILD"
535 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100536 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000537 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000538 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100539 vdur_copy["id"] = "{}-{}".format(
540 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
541 )
tierno2357f4e2020-10-19 16:38:59 +0000542 vdur_copy.pop("vim_info", None)
543 for iface in vdur_copy["interfaces"]:
544 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100545 iface["ip-address"] = self.increment_ip_mac(
546 iface["ip-address"], count + 1
547 )
tierno2357f4e2020-10-19 16:38:59 +0000548 else:
549 iface.pop("ip-address", None)
550 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100551 iface["mac-address"] = self.increment_ip_mac(
552 iface["mac-address"], count + 1
553 )
tierno2357f4e2020-10-19 16:38:59 +0000554 else:
555 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000556 if db_vnfr["vdur"]:
557 iface.pop(
558 "mgmt_vnf", None
559 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000560 db_vdu_push_list.append(vdur_copy)
561 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200562 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000563 if len(db_vnfr["vdur"]) == 1:
564 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300565 self.logger.debug(
566 "Scaling to 0 !, creating the template with the last vdur"
567 )
vegall8d625f12022-03-22 16:23:30 +0000568 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000569 for vdu_id, vdu_count in vdu_delete.items():
570 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100571 indexes_to_delete = [
572 iv[0]
573 for iv in enumerate(db_vnfr["vdur"])
574 if iv[1]["vdu-id-ref"] == vdu_id
575 ]
576 db_update.update(
577 {
578 "vdur.{}.status".format(i): "DELETING"
579 for i in indexes_to_delete[-vdu_count:]
580 }
581 )
tierno2357f4e2020-10-19 16:38:59 +0000582 else:
583 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100584 vdus_to_delete = [
585 v
586 for v in reversed(db_vnfr["vdur"])
587 if v["vdu-id-ref"] == vdu_id
588 ]
tierno2357f4e2020-10-19 16:38:59 +0000589 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100590 self.db.set_one(
591 "vnfrs",
592 {"_id": db_vnfr["_id"]},
593 None,
594 pull={"vdur": {"_id": vdu["_id"]}},
595 )
vegall8d625f12022-03-22 16:23:30 +0000596 db_push = {}
597 if db_vdu_push_list:
598 db_push["vdur"] = db_vdu_push_list
599 if template_vdur:
600 db_push["vdur-template"] = template_vdur
601 if not db_push:
602 db_push = None
603 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000604 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
605 # modify passed dictionary db_vnfr
606 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
607 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200608
tiernof578e552018-11-08 19:07:20 +0100609 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
610 """
611 Updates database nsr with the RO info for the created vld
612 :param ns_update_nsr: dictionary to be filled with the updated info
613 :param db_nsr: content of db_nsr. This is also modified
614 :param nsr_desc_RO: nsr descriptor from RO
615 :return: Nothing, LcmException is raised on errors
616 """
617
618 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
619 for net_RO in get_iterable(nsr_desc_RO, "nets"):
620 if vld["id"] != net_RO.get("ns_net_osm_id"):
621 continue
622 vld["vim-id"] = net_RO.get("vim_net_id")
623 vld["name"] = net_RO.get("vim_name")
624 vld["status"] = net_RO.get("status")
625 vld["status-detailed"] = net_RO.get("error_msg")
626 ns_update_nsr["vld.{}".format(vld_index)] = vld
627 break
628 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100629 raise LcmException(
630 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
631 )
tiernof578e552018-11-08 19:07:20 +0100632
tiernoe876f672020-02-13 14:34:48 +0000633 def set_vnfr_at_error(self, db_vnfrs, error_text):
634 try:
635 for db_vnfr in db_vnfrs.values():
636 vnfr_update = {"status": "ERROR"}
637 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
638 if "status" not in vdur:
639 vdur["status"] = "ERROR"
640 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
641 if error_text:
642 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100643 vnfr_update[
644 "vdur.{}.status-detailed".format(vdu_index)
645 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000646 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
647 except DbException as e:
648 self.logger.error("Cannot update vnf. {}".format(e))
649
tierno5ee02052019-12-05 19:55:02 +0000650 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000651 """
652 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000653 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000654 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
655 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
656 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
657 """
tierno5ee02052019-12-05 19:55:02 +0000658 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
659 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000660 mapping = {}
661 ns_config_info = {"osm-config-mapping": mapping}
662 for vca in vca_deployed_list:
663 if not vca["member-vnf-index"]:
664 continue
665 if not vca["vdu_id"]:
666 mapping[vca["member-vnf-index"]] = vca["application"]
667 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100668 mapping[
669 "{}.{}.{}".format(
670 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
671 )
672 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000673 return ns_config_info
674
garciadeblas5697b8b2021-03-24 09:17:02 +0100675 async def _instantiate_ng_ro(
676 self,
677 logging_text,
678 nsr_id,
679 nsd,
680 db_nsr,
681 db_nslcmop,
682 db_vnfrs,
683 db_vnfds,
684 n2vc_key_list,
685 stage,
686 start_deploy,
687 timeout_ns_deploy,
688 ):
tierno2357f4e2020-10-19 16:38:59 +0000689 db_vims = {}
690
691 def get_vim_account(vim_account_id):
692 nonlocal db_vims
693 if vim_account_id in db_vims:
694 return db_vims[vim_account_id]
695 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
696 db_vims[vim_account_id] = db_vim
697 return db_vim
698
699 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100700 def parse_vld_instantiation_params(
701 target_vim, target_vld, vld_params, target_sdn
702 ):
tierno2357f4e2020-10-19 16:38:59 +0000703 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500704 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
705 vld_params["ip-profile"]
706 )
tierno2357f4e2020-10-19 16:38:59 +0000707 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100708 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
709 "provider-network"
710 ]
tierno2357f4e2020-10-19 16:38:59 +0000711 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100712 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
713 "provider-network"
714 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000715
716 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
717 # if wim_account_id is specified in vld_params, validate if it is feasible.
718 wim_account_id, db_wim = select_feasible_wim_account(
719 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
720 )
721
722 if wim_account_id:
723 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
724 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
725 # update vld_params with correct WIM account Id
726 vld_params["wimAccountId"] = wim_account_id
727
728 target_wim = "wim:{}".format(wim_account_id)
729 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
730 sdn_ports = get_sdn_ports(vld_params, db_wim)
731 if len(sdn_ports) > 0:
732 target_vld["vim_info"][target_wim] = target_wim_attrs
733 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
734
735 self.logger.debug(
736 "Target VLD with WIM data: {:s}".format(str(target_vld))
737 )
738
tierno2357f4e2020-10-19 16:38:59 +0000739 for param in ("vim-network-name", "vim-network-id"):
740 if vld_params.get(param):
741 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300742 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300743 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100744 populate_dict(
745 target_vld["vim_info"],
746 (other_target_vim, param.replace("-", "_")),
747 vim_net,
748 )
tierno2357f4e2020-10-19 16:38:59 +0000749 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100750 target_vld["vim_info"][target_vim][
751 param.replace("-", "_")
752 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300753 if vld_params.get("common_id"):
754 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000755
aticig15db6142022-01-24 12:51:26 +0300756 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
757 def update_ns_vld_target(target, ns_params):
758 for vnf_params in ns_params.get("vnf", ()):
759 if vnf_params.get("vimAccountId"):
760 target_vnf = next(
761 (
762 vnfr
763 for vnfr in db_vnfrs.values()
764 if vnf_params["member-vnf-index"]
765 == vnfr["member-vnf-index-ref"]
766 ),
767 None,
768 )
769 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100770 if not vdur:
Pedro Escaleira556f5c72023-04-20 15:22:16 +0100771 continue
aticig15db6142022-01-24 12:51:26 +0300772 for a_index, a_vld in enumerate(target["ns"]["vld"]):
773 target_vld = find_in_list(
774 get_iterable(vdur, "interfaces"),
775 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
776 )
aticig84bd9a72022-06-14 03:01:36 +0300777
778 vld_params = find_in_list(
779 get_iterable(ns_params, "vld"),
780 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
781 )
aticig15db6142022-01-24 12:51:26 +0300782 if target_vld:
783 if vnf_params.get("vimAccountId") not in a_vld.get(
784 "vim_info", {}
785 ):
aticig84bd9a72022-06-14 03:01:36 +0300786 target_vim_network_list = [
787 v for _, v in a_vld.get("vim_info").items()
788 ]
789 target_vim_network_name = next(
790 (
791 item.get("vim_network_name", "")
792 for item in target_vim_network_list
793 ),
794 "",
795 )
796
aticig15db6142022-01-24 12:51:26 +0300797 target["ns"]["vld"][a_index].get("vim_info").update(
798 {
799 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300800 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300801 }
802 }
803 )
804
aticig84bd9a72022-06-14 03:01:36 +0300805 if vld_params:
806 for param in ("vim-network-name", "vim-network-id"):
807 if vld_params.get(param) and isinstance(
808 vld_params[param], dict
809 ):
810 for vim, vim_net in vld_params[
811 param
812 ].items():
813 other_target_vim = "vim:" + vim
814 populate_dict(
815 target["ns"]["vld"][a_index].get(
816 "vim_info"
817 ),
818 (
819 other_target_vim,
820 param.replace("-", "_"),
821 ),
822 vim_net,
823 )
824
tierno69f0d382020-05-07 13:08:09 +0000825 nslcmop_id = db_nslcmop["_id"]
826 target = {
827 "name": db_nsr["name"],
828 "ns": {"vld": []},
829 "vnf": [],
830 "image": deepcopy(db_nsr["image"]),
831 "flavor": deepcopy(db_nsr["flavor"]),
832 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000833 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000834 }
835 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000836 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000837 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000838 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000839 if db_nsr.get("shared-volumes"):
840 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
841 for shared_volumes in target["shared-volumes"]:
842 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100843 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100844 target["affinity-or-anti-affinity-group"] = deepcopy(
845 db_nsr["affinity-or-anti-affinity-group"]
846 )
847 for affinity_or_anti_affinity_group in target[
848 "affinity-or-anti-affinity-group"
849 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100850 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000851
tierno2357f4e2020-10-19 16:38:59 +0000852 if db_nslcmop.get("lcmOperationType") != "instantiate":
853 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100854 db_nslcmop_instantiate = self.db.get_list(
855 "nslcmops",
856 {
857 "nsInstanceId": db_nslcmop["nsInstanceId"],
858 "lcmOperationType": "instantiate",
859 },
860 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000861 ns_params = db_nslcmop_instantiate.get("operationParams")
862 else:
863 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300864 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
865 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000866
867 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000868 for vld_index, vld in enumerate(db_nsr.get("vld")):
869 target_vim = "vim:{}".format(ns_params["vimAccountId"])
870 target_vld = {
871 "id": vld["id"],
872 "name": vld["name"],
873 "mgmt-network": vld.get("mgmt-network", False),
874 "type": vld.get("type"),
875 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300876 target_vim: {
877 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100878 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -0300879 }
garciadeblas5697b8b2021-03-24 09:17:02 +0100880 },
tierno2357f4e2020-10-19 16:38:59 +0000881 }
882 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000883 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +0000884 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +0300885 if vim_config := db_vim.get("config"):
886 if sdnc_id := vim_config.get("sdn-controller"):
887 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
888 target_sdn = "sdn:{}".format(sdnc_id)
889 target_vld["vim_info"][target_sdn] = {
890 "sdn": True,
891 "target_vim": target_vim,
892 "vlds": [sdn_vld],
893 "type": vld.get("type"),
894 }
tierno2357f4e2020-10-19 16:38:59 +0000895
bravof922c4172020-11-24 21:21:43 -0300896 nsd_vnf_profiles = get_vnf_profiles(nsd)
897 for nsd_vnf_profile in nsd_vnf_profiles:
898 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
899 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100900 cp2target[
901 "member_vnf:{}.{}".format(
902 cp["constituent-cpd-id"][0][
903 "constituent-base-element-id"
904 ],
905 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
906 )
907 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000908
909 # check at nsd descriptor, if there is an ip-profile
910 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +0000911 nsd_vlp = find_in_list(
912 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100913 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
914 == vld["id"],
915 )
916 if (
917 nsd_vlp
918 and nsd_vlp.get("virtual-link-protocol-data")
919 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
920 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500921 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100922 "l3-protocol-data"
923 ]
bravof922c4172020-11-24 21:21:43 -0300924
tierno2357f4e2020-10-19 16:38:59 +0000925 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +0100926 vld_instantiation_params = find_in_list(
927 get_iterable(ns_params, "vld"),
928 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
929 )
tierno2357f4e2020-10-19 16:38:59 +0000930 if vld_instantiation_params:
931 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300932 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000933 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +0300934 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
935 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -0300936
tierno69f0d382020-05-07 13:08:09 +0000937 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +0100938 vnfd = find_in_list(
939 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
940 )
941 vnf_params = find_in_list(
942 get_iterable(ns_params, "vnf"),
943 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
944 )
tierno69f0d382020-05-07 13:08:09 +0000945 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000946 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000947 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000948 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +0100949 vnf_cp = find_in_list(
950 vnfd.get("int-virtual-link-desc", ()),
951 lambda cpd: cpd.get("id") == vld["id"],
952 )
tierno69f0d382020-05-07 13:08:09 +0000953 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +0100954 ns_cp = "member_vnf:{}.{}".format(
955 vnfr["member-vnf-index-ref"], vnf_cp["id"]
956 )
tierno69f0d382020-05-07 13:08:09 +0000957 if cp2target.get(ns_cp):
958 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300959
garciadeblas5697b8b2021-03-24 09:17:02 +0100960 vld["vim_info"] = {
961 target_vim: {"vim_network_name": vld.get("vim-network-name")}
962 }
tierno2357f4e2020-10-19 16:38:59 +0000963 # check if this network needs SDN assist
964 target_sdn = None
965 if vld.get("pci-interfaces"):
966 db_vim = get_vim_account(vnfr["vim-account-id"])
967 sdnc_id = db_vim["config"].get("sdn-controller")
968 if sdnc_id:
969 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
970 target_sdn = "sdn:{}".format(sdnc_id)
971 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +0100972 "sdn": True,
973 "target_vim": target_vim,
974 "vlds": [sdn_vld],
975 "type": vld.get("type"),
976 }
tierno69f0d382020-05-07 13:08:09 +0000977
tierno2357f4e2020-10-19 16:38:59 +0000978 # check at vnfd descriptor, if there is an ip-profile
979 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300980 vnfd_vlp = find_in_list(
981 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +0100982 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -0300983 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100984 if (
985 vnfd_vlp
986 and vnfd_vlp.get("virtual-link-protocol-data")
987 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
988 ):
Gabriel Cubac7737442023-02-14 13:09:18 -0500989 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +0100990 "l3-protocol-data"
991 ]
tierno2357f4e2020-10-19 16:38:59 +0000992 # update vld_params with instantiation params
993 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +0100994 vld_instantiation_params = find_in_list(
995 get_iterable(vnf_params, "internal-vld"),
996 lambda i_vld: i_vld["name"] == vld["id"],
997 )
tierno2357f4e2020-10-19 16:38:59 +0000998 if vld_instantiation_params:
999 vld_params.update(vld_instantiation_params)
1000 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1001
1002 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001003 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001004 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1005 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001006 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001007
bravof922c4172020-11-24 21:21:43 -03001008 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1009
1010 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001011 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1012 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001013 if (
1014 vdu_configuration
1015 and vdu_configuration.get("config-access")
1016 and vdu_configuration.get("config-access").get("ssh-access")
1017 ):
bravof922c4172020-11-24 21:21:43 -03001018 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001019 vdur["ssh-access-required"] = vdu_configuration[
1020 "config-access"
1021 ]["ssh-access"]["required"]
1022 elif (
1023 vnf_configuration
1024 and vnf_configuration.get("config-access")
1025 and vnf_configuration.get("config-access").get("ssh-access")
1026 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1027 ):
bravof922c4172020-11-24 21:21:43 -03001028 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001029 vdur["ssh-access-required"] = vnf_configuration[
1030 "config-access"
1031 ]["ssh-access"]["required"]
1032 elif ssh_keys_instantiation and find_in_list(
1033 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1034 ):
bravof922c4172020-11-24 21:21:43 -03001035 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001036
bravof922c4172020-11-24 21:21:43 -03001037 self.logger.debug("NS > vdur > {}".format(vdur))
1038
1039 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001040 # cloud-init
1041 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001042 vdur["cloud-init"] = "{}:file:{}".format(
1043 vnfd["_id"], vdud.get("cloud-init-file")
1044 )
tierno2357f4e2020-10-19 16:38:59 +00001045 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1046 if vdur["cloud-init"] not in target["cloud_init_content"]:
1047 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001048 if base_folder["pkg-dir"]:
1049 cloud_init_file = "{}/{}/cloud_init/{}".format(
1050 base_folder["folder"],
1051 base_folder["pkg-dir"],
1052 vdud.get("cloud-init-file"),
1053 )
1054 else:
1055 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1056 base_folder["folder"],
1057 vdud.get("cloud-init-file"),
1058 )
tierno2357f4e2020-10-19 16:38:59 +00001059 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001060 target["cloud_init_content"][
1061 vdur["cloud-init"]
1062 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001063 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001064 vdur["cloud-init"] = "{}:vdu:{}".format(
1065 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1066 )
tierno2357f4e2020-10-19 16:38:59 +00001067 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001068 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1069 "cloud-init"
1070 ]
tierno2357f4e2020-10-19 16:38:59 +00001071 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001072 deploy_params_vdu = self._format_additional_params(
1073 vdur.get("additionalParams") or {}
1074 )
1075 deploy_params_vdu["OSM"] = get_osm_params(
1076 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1077 )
tierno2357f4e2020-10-19 16:38:59 +00001078 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001079
1080 # flavor
1081 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001082 if target_vim not in ns_flavor["vim_info"]:
1083 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001084
1085 # deal with images
1086 # in case alternative images are provided we must check if they should be applied
1087 # for the vim_type, modify the vim_type taking into account
1088 ns_image_id = int(vdur["ns-image-id"])
1089 if vdur.get("alt-image-ids"):
1090 db_vim = get_vim_account(vnfr["vim-account-id"])
1091 vim_type = db_vim["vim_type"]
1092 for alt_image_id in vdur.get("alt-image-ids"):
1093 ns_alt_image = target["image"][int(alt_image_id)]
1094 if vim_type == ns_alt_image.get("vim-type"):
1095 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001096 self.logger.debug(
1097 "use alternative image id: {}".format(alt_image_id)
1098 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001099 ns_image_id = alt_image_id
1100 vdur["ns-image-id"] = ns_image_id
1101 break
1102 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001103 if target_vim not in ns_image["vim_info"]:
1104 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001105
Alexis Romero305b5c42022-03-11 15:29:18 +01001106 # Affinity groups
1107 if vdur.get("affinity-or-anti-affinity-group-id"):
1108 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1109 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1110 if target_vim not in ns_ags["vim_info"]:
1111 ns_ags["vim_info"][target_vim] = {}
1112
vegall63162192023-03-06 14:19:16 +00001113 # shared-volumes
1114 if vdur.get("shared-volumes-id"):
1115 for sv_id in vdur["shared-volumes-id"]:
1116 ns_sv = find_in_list(
1117 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1118 )
1119 if ns_sv:
1120 ns_sv["vim_info"][target_vim] = {}
1121
tierno2357f4e2020-10-19 16:38:59 +00001122 vdur["vim_info"] = {target_vim: {}}
1123 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001124 if vnf_params:
1125 vdu_instantiation_params = find_in_list(
1126 get_iterable(vnf_params, "vdu"),
1127 lambda i_vdu: i_vdu["id"] == vdud["id"],
1128 )
1129 if vdu_instantiation_params:
1130 # Parse the vdu_volumes from the instantiation params
1131 vdu_volumes = get_volumes_from_instantiation_params(
1132 vdu_instantiation_params, vdud
1133 )
1134 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001135 vdur["additionalParams"]["OSM"][
1136 "vim_flavor_id"
1137 ] = vdu_instantiation_params.get("vim-flavor-id")
kayal20011028e362024-06-27 08:23:36 +05301138 vdur["additionalParams"]["OSM"][
1139 "instance_name"
1140 ] = vdu_instantiation_params.get("instance_name")
tierno2357f4e2020-10-19 16:38:59 +00001141 vdur_list.append(vdur)
1142 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001143 target["vnf"].append(target_vnf)
1144
garciadeblas07f4e4c2022-06-09 09:42:58 +02001145 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001146 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001147 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001148 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001149 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001150 nsr_id,
1151 action_id,
1152 nslcmop_id,
1153 start_deploy,
1154 timeout_ns_deploy,
1155 stage,
1156 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001157 )
tierno69f0d382020-05-07 13:08:09 +00001158
1159 # Updating NSR
1160 db_nsr_update = {
1161 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001162 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001163 }
1164 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1165 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1166 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001167 self.logger.debug(
1168 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1169 )
tierno69f0d382020-05-07 13:08:09 +00001170 return
1171
garciadeblas5697b8b2021-03-24 09:17:02 +01001172 async def _wait_ng_ro(
1173 self,
1174 nsr_id,
1175 action_id,
1176 nslcmop_id=None,
1177 start_time=None,
1178 timeout=600,
1179 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001180 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001181 ):
tierno69f0d382020-05-07 13:08:09 +00001182 detailed_status_old = None
1183 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001184 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001185 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001186 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001187 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001188 if desc_status["status"] == "FAILED":
1189 raise NgRoException(desc_status["details"])
1190 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001191 if stage:
1192 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001193 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001194 if stage:
1195 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001196 break
1197 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001198 assert False, "ROclient.check_ns_status returns unknown {}".format(
1199 desc_status["status"]
1200 )
tierno2357f4e2020-10-19 16:38:59 +00001201 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001202 detailed_status_old = stage[2]
1203 db_nsr_update["detailed-status"] = " ".join(stage)
1204 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1205 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001206 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001207 else: # timeout_ns_deploy
1208 raise NgRoException("Timeout waiting ns to deploy")
1209
garciadeblas5697b8b2021-03-24 09:17:02 +01001210 async def _terminate_ng_ro(
1211 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1212 ):
tierno69f0d382020-05-07 13:08:09 +00001213 db_nsr_update = {}
1214 failed_detail = []
1215 action_id = None
1216 start_deploy = time()
1217 try:
1218 target = {
1219 "ns": {"vld": []},
1220 "vnf": [],
1221 "image": [],
1222 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001223 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001224 }
1225 desc = await self.RO.deploy(nsr_id, target)
1226 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001227 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001228 self.logger.debug(
1229 logging_text
1230 + "ns terminate action at RO. action_id={}".format(action_id)
1231 )
tierno69f0d382020-05-07 13:08:09 +00001232
1233 # wait until done
1234 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001235 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001236 nsr_id,
1237 action_id,
1238 nslcmop_id,
1239 start_deploy,
1240 delete_timeout,
1241 stage,
1242 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001243 )
tierno69f0d382020-05-07 13:08:09 +00001244 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1245 # delete all nsr
1246 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001247 except NgRoException as e:
1248 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001249 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1250 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001251 self.logger.debug(
1252 logging_text + "RO_action_id={} already deleted".format(action_id)
1253 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001254 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001255 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001256 self.logger.debug(
1257 logging_text
1258 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1259 )
tierno69f0d382020-05-07 13:08:09 +00001260 else:
1261 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001262 self.logger.error(
1263 logging_text
1264 + "RO_action_id={} delete error: {}".format(action_id, e)
1265 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001266 except Exception as e:
1267 failed_detail.append("delete error: {}".format(e))
1268 self.logger.error(
1269 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1270 )
tierno69f0d382020-05-07 13:08:09 +00001271
1272 if failed_detail:
1273 stage[2] = "Error deleting from VIM"
1274 else:
1275 stage[2] = "Deleted from VIM"
1276 db_nsr_update["detailed-status"] = " ".join(stage)
1277 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1278 self._write_op_status(nslcmop_id, stage)
1279
1280 if failed_detail:
1281 raise LcmException("; ".join(failed_detail))
1282 return
1283
garciadeblas5697b8b2021-03-24 09:17:02 +01001284 async def instantiate_RO(
1285 self,
1286 logging_text,
1287 nsr_id,
1288 nsd,
1289 db_nsr,
1290 db_nslcmop,
1291 db_vnfrs,
1292 db_vnfds,
1293 n2vc_key_list,
1294 stage,
1295 ):
tiernoe95ed362020-04-23 08:24:57 +00001296 """
1297 Instantiate at RO
1298 :param logging_text: preffix text to use at logging
1299 :param nsr_id: nsr identity
1300 :param nsd: database content of ns descriptor
1301 :param db_nsr: database content of ns record
1302 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1303 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001304 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001305 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1306 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1307 :return: None or exception
1308 """
tiernoe876f672020-02-13 14:34:48 +00001309 try:
tiernoe876f672020-02-13 14:34:48 +00001310 start_deploy = time()
1311 ns_params = db_nslcmop.get("operationParams")
1312 if ns_params and ns_params.get("timeout_ns_deploy"):
1313 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1314 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001315 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001316
tiernoe876f672020-02-13 14:34:48 +00001317 # Check for and optionally request placement optimization. Database will be updated if placement activated
1318 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001319 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1320 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1321 for vnfr in db_vnfrs.values():
1322 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1323 break
1324 else:
1325 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001326
garciadeblas5697b8b2021-03-24 09:17:02 +01001327 return await self._instantiate_ng_ro(
1328 logging_text,
1329 nsr_id,
1330 nsd,
1331 db_nsr,
1332 db_nslcmop,
1333 db_vnfrs,
1334 db_vnfds,
1335 n2vc_key_list,
1336 stage,
1337 start_deploy,
1338 timeout_ns_deploy,
1339 )
tierno2357f4e2020-10-19 16:38:59 +00001340 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001341 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001342 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001343 self.logger.error(
1344 "Error deploying at VIM {}".format(e),
1345 exc_info=not isinstance(
1346 e,
1347 (
1348 ROclient.ROClientException,
1349 LcmException,
1350 DbException,
1351 NgRoException,
1352 ),
1353 ),
1354 )
tiernoe876f672020-02-13 14:34:48 +00001355 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001356
tierno7ecbc342020-09-21 14:05:39 +00001357 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1358 """
1359 Wait for kdu to be up, get ip address
1360 :param logging_text: prefix use for logging
1361 :param nsr_id:
1362 :param vnfr_id:
1363 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001364 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001365 """
1366
1367 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1368 nb_tries = 0
1369
1370 while nb_tries < 360:
1371 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001372 kdur = next(
1373 (
1374 x
1375 for x in get_iterable(db_vnfr, "kdur")
1376 if x.get("kdu-name") == kdu_name
1377 ),
1378 None,
1379 )
tierno7ecbc342020-09-21 14:05:39 +00001380 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001381 raise LcmException(
1382 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1383 )
tierno7ecbc342020-09-21 14:05:39 +00001384 if kdur.get("status"):
1385 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001386 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001387 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001388 raise LcmException(
1389 "target KDU={} is in error state".format(kdu_name)
1390 )
tierno7ecbc342020-09-21 14:05:39 +00001391
Gabriel Cubae7898982023-05-11 01:57:21 -05001392 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001393 nb_tries += 1
1394 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1395
garciadeblas5697b8b2021-03-24 09:17:02 +01001396 async def wait_vm_up_insert_key_ro(
1397 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1398 ):
tiernoa5088192019-11-26 16:12:53 +00001399 """
1400 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1401 :param logging_text: prefix use for logging
1402 :param nsr_id:
1403 :param vnfr_id:
1404 :param vdu_id:
1405 :param vdu_index:
1406 :param pub_key: public ssh key to inject, None to skip
1407 :param user: user to apply the public ssh key
1408 :return: IP address
1409 """
quilesj7e13aeb2019-10-08 13:34:55 +02001410
tierno2357f4e2020-10-19 16:38:59 +00001411 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001412 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001413 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001414 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001415
tiernod8323042019-08-09 11:32:23 +00001416 while True:
quilesj3149f262019-12-03 10:58:10 +00001417 ro_retries += 1
1418 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001419 raise LcmException(
1420 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1421 )
quilesj3149f262019-12-03 10:58:10 +00001422
Gabriel Cubae7898982023-05-11 01:57:21 -05001423 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001424
1425 # get ip address
tiernod8323042019-08-09 11:32:23 +00001426 if not target_vdu_id:
1427 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001428
1429 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001430 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001431 raise LcmException(
1432 "Cannot inject ssh-key because target VNF is in error state"
1433 )
tiernod8323042019-08-09 11:32:23 +00001434 ip_address = db_vnfr.get("ip-address")
1435 if not ip_address:
1436 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001437 vdur = next(
1438 (
1439 x
1440 for x in get_iterable(db_vnfr, "vdur")
1441 if x.get("ip-address") == ip_address
1442 ),
1443 None,
1444 )
quilesj3149f262019-12-03 10:58:10 +00001445 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001446 vdur = next(
1447 (
1448 x
1449 for x in get_iterable(db_vnfr, "vdur")
1450 if x.get("vdu-id-ref") == vdu_id
1451 and x.get("count-index") == vdu_index
1452 ),
1453 None,
1454 )
quilesj3149f262019-12-03 10:58:10 +00001455
garciadeblas5697b8b2021-03-24 09:17:02 +01001456 if (
1457 not vdur and len(db_vnfr.get("vdur", ())) == 1
1458 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001459 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001460 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001461 raise LcmException(
1462 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1463 vnfr_id, vdu_id, vdu_index
1464 )
1465 )
tierno2357f4e2020-10-19 16:38:59 +00001466 # New generation RO stores information at "vim_info"
1467 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001468 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001469 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001470 target_vim = next(
1471 t for t in vdur["vim_info"]
1472 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001473 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001474 if (
1475 vdur.get("pdu-type")
1476 or vdur.get("status") == "ACTIVE"
1477 or ng_ro_status == "ACTIVE"
1478 ):
quilesj3149f262019-12-03 10:58:10 +00001479 ip_address = vdur.get("ip-address")
1480 if not ip_address:
1481 continue
1482 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001483 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001484 raise LcmException(
1485 "Cannot inject ssh-key because target VM is in error state"
1486 )
quilesj3149f262019-12-03 10:58:10 +00001487
tiernod8323042019-08-09 11:32:23 +00001488 if not target_vdu_id:
1489 continue
tiernod8323042019-08-09 11:32:23 +00001490
quilesj7e13aeb2019-10-08 13:34:55 +02001491 # inject public key into machine
1492 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001493 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001494 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001495 if vdur.get("pdu-type"):
1496 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1497 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001498 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001499 target = {
1500 "action": {
1501 "action": "inject_ssh_key",
1502 "key": pub_key,
1503 "user": user,
1504 },
1505 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1506 }
1507 desc = await self.RO.deploy(nsr_id, target)
1508 action_id = desc["action_id"]
1509 await self._wait_ng_ro(
1510 nsr_id, action_id, timeout=600, operation="instantiation"
1511 )
1512 break
tierno69f0d382020-05-07 13:08:09 +00001513 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001514 raise LcmException(
1515 "Reaching max tries injecting key. Error: {}".format(e)
1516 )
quilesj7e13aeb2019-10-08 13:34:55 +02001517 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001518 break
1519
1520 return ip_address
1521
tierno5ee02052019-12-05 19:55:02 +00001522 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1523 """
1524 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1525 """
1526 my_vca = vca_deployed_list[vca_index]
1527 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001528 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001529 return
1530 timeout = 300
1531 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001532 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1533 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1534 configuration_status_list = db_nsr["configurationStatus"]
1535 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001536 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001537 # myself
tierno5ee02052019-12-05 19:55:02 +00001538 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001539 if not my_vca.get("member-vnf-index") or (
1540 vca_deployed.get("member-vnf-index")
1541 == my_vca.get("member-vnf-index")
1542 ):
quilesj3655ae02019-12-12 16:08:35 +00001543 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001544 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001545 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001546 elif internal_status == "BROKEN":
1547 raise LcmException(
1548 "Configuration aborted because dependent charm/s has failed"
1549 )
quilesj3655ae02019-12-12 16:08:35 +00001550 else:
1551 break
tierno5ee02052019-12-05 19:55:02 +00001552 else:
quilesj3655ae02019-12-12 16:08:35 +00001553 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001554 return
1555 await asyncio.sleep(10)
1556 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001557
1558 raise LcmException("Configuration aborted because dependent charm/s timeout")
1559
David Garciac1fe90a2021-03-31 19:12:02 +02001560 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001561 vca_id = None
1562 if db_vnfr:
1563 vca_id = deep_get(db_vnfr, ("vca-id",))
1564 elif db_nsr:
1565 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1566 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1567 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001568
garciadeblas5697b8b2021-03-24 09:17:02 +01001569 async def instantiate_N2VC(
1570 self,
1571 logging_text,
1572 vca_index,
1573 nsi_id,
1574 db_nsr,
1575 db_vnfr,
1576 vdu_id,
1577 kdu_name,
1578 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001579 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001580 config_descriptor,
1581 deploy_params,
1582 base_folder,
1583 nslcmop_id,
1584 stage,
1585 vca_type,
1586 vca_name,
1587 ee_config_descriptor,
1588 ):
tiernod8323042019-08-09 11:32:23 +00001589 nsr_id = db_nsr["_id"]
1590 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001591 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001592 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001593 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001594 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001595 "collection": "nsrs",
1596 "filter": {"_id": nsr_id},
1597 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001598 }
tiernod8323042019-08-09 11:32:23 +00001599 step = ""
1600 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001601 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001602 element_under_configuration = nsr_id
1603
tiernod8323042019-08-09 11:32:23 +00001604 vnfr_id = None
1605 if db_vnfr:
1606 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001607 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001608
garciadeblas5697b8b2021-03-24 09:17:02 +01001609 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001610
aktas98488ed2021-07-29 17:42:49 +03001611 if vca_type == "native_charm":
1612 index_number = 0
1613 else:
1614 index_number = vdu_index or 0
1615
tiernod8323042019-08-09 11:32:23 +00001616 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001617 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001618 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001619 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001620 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001621 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001622 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001623 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001624 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001625 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001626 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001627 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001628 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001629 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001630
1631 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001632 if base_folder["pkg-dir"]:
1633 artifact_path = "{}/{}/{}/{}".format(
1634 base_folder["folder"],
1635 base_folder["pkg-dir"],
1636 "charms"
aticig15db6142022-01-24 12:51:26 +03001637 if vca_type
1638 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001639 else "helm-charts",
1640 vca_name,
1641 )
1642 else:
1643 artifact_path = "{}/Scripts/{}/{}/".format(
1644 base_folder["folder"],
1645 "charms"
aticig15db6142022-01-24 12:51:26 +03001646 if vca_type
1647 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001648 else "helm-charts",
1649 vca_name,
1650 )
bravof922c4172020-11-24 21:21:43 -03001651
1652 self.logger.debug("Artifact path > {}".format(artifact_path))
1653
tiernoa278b842020-07-08 15:33:55 +00001654 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001655 initial_config_primitive_list = config_descriptor.get(
1656 "initial-config-primitive"
1657 )
tiernoa278b842020-07-08 15:33:55 +00001658
garciadeblas5697b8b2021-03-24 09:17:02 +01001659 self.logger.debug(
1660 "Initial config primitive list > {}".format(
1661 initial_config_primitive_list
1662 )
1663 )
bravof922c4172020-11-24 21:21:43 -03001664
tiernoa278b842020-07-08 15:33:55 +00001665 # add config if not present for NS charm
1666 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001667 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001668 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1669 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1670 )
tiernod8323042019-08-09 11:32:23 +00001671
garciadeblas5697b8b2021-03-24 09:17:02 +01001672 self.logger.debug(
1673 "Initial config primitive list #2 > {}".format(
1674 initial_config_primitive_list
1675 )
1676 )
tierno588547c2020-07-01 15:30:20 +00001677 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001678 # find old ee_id if exists
1679 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001680
David Garciac1fe90a2021-03-31 19:12:02 +02001681 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001682 # create or register execution environment in VCA
Luis Vegae11384e2023-10-10 22:36:33 +00001683 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001684 self._write_configuration_status(
1685 nsr_id=nsr_id,
1686 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001687 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001688 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001689 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001690 )
tiernod8323042019-08-09 11:32:23 +00001691
tierno588547c2020-07-01 15:30:20 +00001692 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001693 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001694
1695 ee_id = None
1696 credentials = None
1697 if vca_type == "k8s_proxy_charm":
1698 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001699 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001700 namespace=namespace,
1701 artifact_path=artifact_path,
1702 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001703 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001704 )
Luis Vegae11384e2023-10-10 22:36:33 +00001705 elif vca_type == "helm-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01001706 ee_id, credentials = await self.vca_map[
1707 vca_type
1708 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001709 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001710 reuse_ee_id=ee_id,
1711 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001712 config=osm_config,
1713 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001714 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001715 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001716 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001717 else:
1718 ee_id, credentials = await self.vca_map[
1719 vca_type
1720 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001721 namespace=namespace,
1722 reuse_ee_id=ee_id,
1723 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001724 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001725 )
quilesj3655ae02019-12-12 16:08:35 +00001726
tierno588547c2020-07-01 15:30:20 +00001727 elif vca_type == "native_charm":
1728 step = "Waiting to VM being up and getting IP address"
1729 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001730 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1731 logging_text,
1732 nsr_id,
1733 vnfr_id,
1734 vdu_id,
1735 vdu_index,
1736 user=None,
1737 pub_key=None,
1738 )
tierno588547c2020-07-01 15:30:20 +00001739 credentials = {"hostname": rw_mgmt_ip}
1740 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001741 username = deep_get(
1742 config_descriptor, ("config-access", "ssh-access", "default-user")
1743 )
tierno588547c2020-07-01 15:30:20 +00001744 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1745 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001746 if not username and initial_config_primitive_list:
1747 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001748 for param in config_primitive.get("parameter", ()):
1749 if param["name"] == "ssh-username":
1750 username = param["value"]
1751 break
1752 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001753 raise LcmException(
1754 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1755 "'config-access.ssh-access.default-user'"
1756 )
tierno588547c2020-07-01 15:30:20 +00001757 credentials["username"] = username
1758 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001759
tierno588547c2020-07-01 15:30:20 +00001760 self._write_configuration_status(
1761 nsr_id=nsr_id,
1762 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001763 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001764 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001765 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001766 )
quilesj3655ae02019-12-12 16:08:35 +00001767
tierno588547c2020-07-01 15:30:20 +00001768 step = "register execution environment {}".format(credentials)
1769 self.logger.debug(logging_text + step)
1770 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001771 credentials=credentials,
1772 namespace=namespace,
1773 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001774 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001775 )
tierno3bedc9b2019-11-27 15:46:57 +00001776
tierno588547c2020-07-01 15:30:20 +00001777 # for compatibility with MON/POL modules, the need model and application name at database
1778 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001779 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001780 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1781 if len(ee_id_parts) >= 2:
1782 model_name = ee_id_parts[0]
1783 application_name = ee_id_parts[1]
1784 db_nsr_update[db_update_entry + "model"] = model_name
1785 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001786
1787 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001788 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001789
tiernoc231a872020-01-21 08:49:05 +00001790 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001791 nsr_id=nsr_id,
1792 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001793 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001794 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001795 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001796 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001797 )
1798
tierno3bedc9b2019-11-27 15:46:57 +00001799 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001800 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001801 config = None
tierno588547c2020-07-01 15:30:20 +00001802 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001803 config_primitive = next(
1804 (p for p in initial_config_primitive_list if p["name"] == "config"),
1805 None,
1806 )
tiernoa278b842020-07-08 15:33:55 +00001807 if config_primitive:
1808 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001809 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001810 )
tierno588547c2020-07-01 15:30:20 +00001811 num_units = 1
1812 if vca_type == "lxc_proxy_charm":
1813 if element_type == "NS":
1814 num_units = db_nsr.get("config-units") or 1
1815 elif element_type == "VNF":
1816 num_units = db_vnfr.get("config-units") or 1
1817 elif element_type == "VDU":
1818 for v in db_vnfr["vdur"]:
1819 if vdu_id == v["vdu-id-ref"]:
1820 num_units = v.get("config-units") or 1
1821 break
David Garciaaae391f2020-11-09 11:12:54 +01001822 if vca_type != "k8s_proxy_charm":
1823 await self.vca_map[vca_type].install_configuration_sw(
1824 ee_id=ee_id,
1825 artifact_path=artifact_path,
1826 db_dict=db_dict,
1827 config=config,
1828 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001829 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001830 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001831 )
quilesj7e13aeb2019-10-08 13:34:55 +02001832
quilesj63f90042020-01-17 09:53:55 +00001833 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001834 self.update_db_2(
1835 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1836 )
quilesj63f90042020-01-17 09:53:55 +00001837
1838 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001839 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001840 logging_text=logging_text,
1841 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001842 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001843 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001844 )
quilesj63f90042020-01-17 09:53:55 +00001845
Patricia Reinosob4312c02023-01-06 22:28:44 +00001846 if not is_relation_added:
1847 raise LcmException("Relations could not be added to VCA.")
1848
quilesj7e13aeb2019-10-08 13:34:55 +02001849 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001850 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00001851 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001852 pub_key = None
1853 user = None
tierno588547c2020-07-01 15:30:20 +00001854 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001855 if deep_get(
1856 config_descriptor, ("config-access", "ssh-access", "required")
1857 ):
tierno588547c2020-07-01 15:30:20 +00001858 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001859 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001860 user = deep_get(
1861 config_descriptor,
1862 ("config-access", "ssh-access", "default-user"),
1863 )
tierno3bedc9b2019-11-27 15:46:57 +00001864 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001865 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001866 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001867 )
quilesj7e13aeb2019-10-08 13:34:55 +02001868
garciadeblas5697b8b2021-03-24 09:17:02 +01001869 step = "Insert public key into VM user={} ssh_key={}".format(
1870 user, pub_key
1871 )
tierno3bedc9b2019-11-27 15:46:57 +00001872 else:
tierno588547c2020-07-01 15:30:20 +00001873 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001874 step = "Waiting to VM being up and getting IP address"
1875 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001876
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001877 # default rw_mgmt_ip to None, avoiding the non definition of the variable
1878 rw_mgmt_ip = None
1879
tierno3bedc9b2019-11-27 15:46:57 +00001880 # n2vc_redesign STEP 5.1
1881 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001882 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001883 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001884 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01001885 logging_text, nsr_id, vnfr_id, kdu_name
1886 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001887 vnfd = self.db.get_one(
1888 "vnfds_revisions",
1889 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
1890 )
1891 kdu = get_kdu(vnfd, kdu_name)
1892 kdu_services = [
1893 service["name"] for service in get_kdu_services(kdu)
1894 ]
1895 exposed_services = []
1896 for service in services:
1897 if any(s in service["name"] for s in kdu_services):
1898 exposed_services.append(service)
1899 await self.vca_map[vca_type].exec_primitive(
1900 ee_id=ee_id,
1901 primitive_name="config",
1902 params_dict={
1903 "osm-config": json.dumps(
1904 OsmConfigBuilder(
1905 k8s={"services": exposed_services}
1906 ).build()
1907 )
1908 },
1909 vca_id=vca_id,
1910 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01001911
1912 # This verification is needed in order to avoid trying to add a public key
1913 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
1914 # for a KNF and not for its KDUs, the previous verification gives False, and the code
1915 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
1916 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00001917 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001918 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1919 logging_text,
1920 nsr_id,
1921 vnfr_id,
1922 vdu_id,
1923 vdu_index,
1924 user=user,
1925 pub_key=pub_key,
1926 )
David Garcia78b6e6d2022-04-29 05:50:46 +02001927
garciadeblas5697b8b2021-03-24 09:17:02 +01001928 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001929
tiernoa5088192019-11-26 16:12:53 +00001930 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001931 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001932
1933 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01001934 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00001935
1936 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001937 if initial_config_primitive_list:
1938 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001939
1940 # stage, in function of element type: vdu, kdu, vnf or ns
1941 my_vca = vca_deployed_list[vca_index]
1942 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1943 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01001944 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00001945 elif my_vca.get("member-vnf-index"):
1946 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01001947 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00001948 else:
1949 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01001950 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00001951
tiernoc231a872020-01-21 08:49:05 +00001952 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01001953 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00001954 )
1955
garciadeblas5697b8b2021-03-24 09:17:02 +01001956 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00001957
tiernoe876f672020-02-13 14:34:48 +00001958 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001959 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001960 # adding information on the vca_deployed if it is a NS execution environment
1961 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001962 deploy_params["ns_config_info"] = json.dumps(
1963 self._get_ns_config_info(nsr_id)
1964 )
tiernod8323042019-08-09 11:32:23 +00001965 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01001966 primitive_params_ = self._map_primitive_params(
1967 initial_config_primitive, {}, deploy_params
1968 )
tierno3bedc9b2019-11-27 15:46:57 +00001969
garciadeblas5697b8b2021-03-24 09:17:02 +01001970 step = "execute primitive '{}' params '{}'".format(
1971 initial_config_primitive["name"], primitive_params_
1972 )
tiernod8323042019-08-09 11:32:23 +00001973 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001974 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001975 ee_id=ee_id,
1976 primitive_name=initial_config_primitive["name"],
1977 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02001978 db_dict=db_dict,
1979 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001980 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02001981 )
tiernoe876f672020-02-13 14:34:48 +00001982 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1983 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01001984 if config_descriptor.get("terminate-config-primitive"):
1985 self.update_db_2(
1986 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
1987 )
tiernoe876f672020-02-13 14:34:48 +00001988 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001989
tiernod8323042019-08-09 11:32:23 +00001990 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001991
tiernob996d942020-07-03 14:52:28 +00001992 # STEP 7 Configure metrics
Luis Vegae11384e2023-10-10 22:36:33 +00001993 if vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02001994 # TODO: review for those cases where the helm chart is a reference and
1995 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04001996 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00001997 ee_id=ee_id,
1998 artifact_path=artifact_path,
1999 ee_config_descriptor=ee_config_descriptor,
2000 vnfr_id=vnfr_id,
2001 nsr_id=nsr_id,
2002 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002003 element_type=element_type,
2004 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2005 vdu_id=vdu_id,
2006 vdu_index=vdu_index,
2007 kdu_name=kdu_name,
2008 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002009 )
2010 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002011 self.update_db_2(
2012 "nsrs",
2013 nsr_id,
2014 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2015 )
tiernob996d942020-07-03 14:52:28 +00002016
bravof73bac502021-05-11 07:38:47 -04002017 for job in prometheus_jobs:
2018 self.db.set_one(
2019 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002020 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002021 job,
2022 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002023 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002024 )
2025
quilesj7e13aeb2019-10-08 13:34:55 +02002026 step = "instantiated at VCA"
2027 self.logger.debug(logging_text + step)
2028
tiernoc231a872020-01-21 08:49:05 +00002029 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002030 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002031 )
2032
tiernod8323042019-08-09 11:32:23 +00002033 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002034 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002035 if not isinstance(
2036 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2037 ):
2038 self.logger.error(
2039 "Exception while {} : {}".format(step, e), exc_info=True
2040 )
tiernoc231a872020-01-21 08:49:05 +00002041 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002042 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002043 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002044 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002045
garciadeblas5697b8b2021-03-24 09:17:02 +01002046 def _write_ns_status(
2047 self,
2048 nsr_id: str,
2049 ns_state: str,
2050 current_operation: str,
2051 current_operation_id: str,
2052 error_description: str = None,
2053 error_detail: str = None,
2054 other_update: dict = None,
2055 ):
tiernoe876f672020-02-13 14:34:48 +00002056 """
2057 Update db_nsr fields.
2058 :param nsr_id:
2059 :param ns_state:
2060 :param current_operation:
2061 :param current_operation_id:
2062 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002063 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002064 :param other_update: Other required changes at database if provided, will be cleared
2065 :return:
2066 """
quilesj4cda56b2019-12-05 10:02:20 +00002067 try:
tiernoe876f672020-02-13 14:34:48 +00002068 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002069 db_dict[
2070 "_admin.nslcmop"
2071 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002072 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002073 db_dict["_admin.operation-type"] = (
2074 current_operation if current_operation != "IDLE" else None
2075 )
quilesj4cda56b2019-12-05 10:02:20 +00002076 db_dict["currentOperation"] = current_operation
2077 db_dict["currentOperationID"] = current_operation_id
2078 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002079 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002080
2081 if ns_state:
2082 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002083 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002084 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002085 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002086
garciadeblas5697b8b2021-03-24 09:17:02 +01002087 def _write_op_status(
2088 self,
2089 op_id: str,
2090 stage: list = None,
2091 error_message: str = None,
2092 queuePosition: int = 0,
2093 operation_state: str = None,
2094 other_update: dict = None,
2095 ):
quilesj3655ae02019-12-12 16:08:35 +00002096 try:
tiernoe876f672020-02-13 14:34:48 +00002097 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002098 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002099 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002100 db_dict["stage"] = stage[0]
2101 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002102 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002103 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002104
2105 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002106 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002107 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002108 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002109 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002110 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002111 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002112 self.logger.warn(
2113 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2114 )
quilesj3655ae02019-12-12 16:08:35 +00002115
tierno51183952020-04-03 15:48:18 +00002116 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002117 try:
tierno51183952020-04-03 15:48:18 +00002118 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002119 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002120 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002121 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002122 db_nsr_update = {
2123 "configurationStatus.{}.status".format(index): status
2124 for index, v in enumerate(config_status)
2125 if v
2126 }
quilesj3655ae02019-12-12 16:08:35 +00002127 # update status
tierno51183952020-04-03 15:48:18 +00002128 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002129
tiernoe876f672020-02-13 14:34:48 +00002130 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002131 self.logger.warn(
2132 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2133 )
quilesj3655ae02019-12-12 16:08:35 +00002134
garciadeblas5697b8b2021-03-24 09:17:02 +01002135 def _write_configuration_status(
2136 self,
2137 nsr_id: str,
2138 vca_index: int,
2139 status: str = None,
2140 element_under_configuration: str = None,
2141 element_type: str = None,
2142 other_update: dict = None,
2143 ):
quilesj3655ae02019-12-12 16:08:35 +00002144 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2145 # .format(vca_index, status))
2146
2147 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002148 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002149 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002150 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002151 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002152 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002153 db_dict[
2154 db_path + "elementUnderConfiguration"
2155 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002156 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002157 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002158 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002159 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002160 self.logger.warn(
2161 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2162 status, nsr_id, vca_index, e
2163 )
2164 )
quilesj4cda56b2019-12-05 10:02:20 +00002165
tierno38089af2020-04-16 07:56:58 +00002166 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2167 """
2168 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2169 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2170 Database is used because the result can be obtained from a different LCM worker in case of HA.
2171 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2172 :param db_nslcmop: database content of nslcmop
2173 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002174 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2175 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002176 """
tierno8790a3d2020-04-23 22:49:52 +00002177 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002178 nslcmop_id = db_nslcmop["_id"]
2179 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002180 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002181 self.logger.debug(
2182 logging_text + "Invoke and wait for placement optimization"
2183 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002184 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002185 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002186 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002187 pla_result = None
2188 while not pla_result and wait >= 0:
2189 await asyncio.sleep(db_poll_interval)
2190 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002191 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002192 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002193
2194 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002195 raise LcmException(
2196 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2197 )
magnussonle9198bb2020-01-21 13:00:51 +01002198
garciadeblas5697b8b2021-03-24 09:17:02 +01002199 for pla_vnf in pla_result["vnf"]:
2200 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2201 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002202 continue
tierno8790a3d2020-04-23 22:49:52 +00002203 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002204 self.db.set_one(
2205 "vnfrs",
2206 {"_id": vnfr["_id"]},
2207 {"vim-account-id": pla_vnf["vimAccountId"]},
2208 )
tierno38089af2020-04-16 07:56:58 +00002209 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002210 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002211 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002212
aguilard1ae3c562023-02-16 17:24:35 +00002213 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2214 alerts = []
2215 nsr_id = vnfr["nsr-id-ref"]
2216 df = vnfd.get("df", [{}])[0]
2217 # Checking for auto-healing configuration
2218 if "healing-aspect" in df:
2219 healing_aspects = df["healing-aspect"]
2220 for healing in healing_aspects:
2221 for healing_policy in healing.get("healing-policy", ()):
2222 vdu_id = healing_policy["vdu-id"]
2223 vdur = next(
2224 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2225 {},
2226 )
2227 if not vdur:
2228 continue
2229 metric_name = "vm_status"
2230 vdu_name = vdur.get("name")
2231 vnf_member_index = vnfr["member-vnf-index-ref"]
2232 uuid = str(uuid4())
2233 name = f"healing_{uuid}"
2234 action = healing_policy
2235 # action_on_recovery = healing.get("action-on-recovery")
2236 # cooldown_time = healing.get("cooldown-time")
2237 # day1 = healing.get("day1")
2238 alert = {
2239 "uuid": uuid,
2240 "name": name,
2241 "metric": metric_name,
2242 "tags": {
2243 "ns_id": nsr_id,
2244 "vnf_member_index": vnf_member_index,
2245 "vdu_name": vdu_name,
2246 },
2247 "alarm_status": "ok",
2248 "action_type": "healing",
2249 "action": action,
2250 }
2251 alerts.append(alert)
2252 return alerts
2253
2254 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2255 alerts = []
2256 nsr_id = vnfr["nsr-id-ref"]
2257 df = vnfd.get("df", [{}])[0]
2258 # Checking for auto-scaling configuration
2259 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002260 scaling_aspects = df["scaling-aspect"]
2261 all_vnfd_monitoring_params = {}
2262 for ivld in vnfd.get("int-virtual-link-desc", ()):
2263 for mp in ivld.get("monitoring-parameters", ()):
2264 all_vnfd_monitoring_params[mp.get("id")] = mp
2265 for vdu in vnfd.get("vdu", ()):
2266 for mp in vdu.get("monitoring-parameter", ()):
2267 all_vnfd_monitoring_params[mp.get("id")] = mp
2268 for df in vnfd.get("df", ()):
2269 for mp in df.get("monitoring-parameter", ()):
2270 all_vnfd_monitoring_params[mp.get("id")] = mp
2271 for scaling_aspect in scaling_aspects:
2272 scaling_group_name = scaling_aspect.get("name", "")
2273 # Get monitored VDUs
2274 all_monitored_vdus = set()
2275 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2276 "deltas", ()
2277 ):
2278 for vdu_delta in delta.get("vdu-delta", ()):
2279 all_monitored_vdus.add(vdu_delta.get("id"))
2280 monitored_vdurs = list(
2281 filter(
2282 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2283 vnfr["vdur"],
2284 )
2285 )
2286 if not monitored_vdurs:
2287 self.logger.error(
2288 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2289 )
2290 continue
2291 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2292 if scaling_policy["scaling-type"] != "automatic":
2293 continue
2294 threshold_time = scaling_policy.get("threshold-time", "1")
2295 cooldown_time = scaling_policy.get("cooldown-time", "0")
2296 for scaling_criteria in scaling_policy["scaling-criteria"]:
2297 monitoring_param_ref = scaling_criteria.get(
2298 "vnf-monitoring-param-ref"
2299 )
2300 vnf_monitoring_param = all_vnfd_monitoring_params[
2301 monitoring_param_ref
2302 ]
2303 for vdur in monitored_vdurs:
2304 vdu_id = vdur["vdu-id-ref"]
2305 metric_name = vnf_monitoring_param.get("performance-metric")
Rahul Kumar54671c52024-05-09 15:34:01 +05302306 if "exporters-endpoints" not in df:
2307 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002308 vnf_member_index = vnfr["member-vnf-index-ref"]
2309 scalein_threshold = scaling_criteria.get(
2310 "scale-in-threshold"
2311 )
2312 scaleout_threshold = scaling_criteria.get(
2313 "scale-out-threshold"
2314 )
2315 # Looking for min/max-number-of-instances
2316 instances_min_number = 1
2317 instances_max_number = 1
2318 vdu_profile = df["vdu-profile"]
2319 if vdu_profile:
2320 profile = next(
2321 item for item in vdu_profile if item["id"] == vdu_id
2322 )
2323 instances_min_number = profile.get(
2324 "min-number-of-instances", 1
2325 )
2326 instances_max_number = profile.get(
2327 "max-number-of-instances", 1
2328 )
2329
2330 if scalein_threshold:
2331 uuid = str(uuid4())
2332 name = f"scalein_{uuid}"
2333 operation = scaling_criteria[
2334 "scale-in-relational-operation"
2335 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002336 rel_operator = self.rel_operation_types.get(
2337 operation, "<="
2338 )
aguilard1ae3c562023-02-16 17:24:35 +00002339 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2340 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302341 if (
2342 "exporters-endpoints" in df
2343 and metric_name.startswith("kpi_")
2344 ):
2345 new_metric_name = (
2346 f'osm_{metric_name.replace("kpi_", "").strip()}'
2347 )
2348 metric_port = df["exporters-endpoints"].get(
2349 "metric-port", 9100
2350 )
2351 vdu_ip = vdur["ip-address"]
2352 ip_port = str(vdu_ip) + ":" + str(metric_port)
2353 metric_selector = (
2354 f'{new_metric_name}{{instance="{ip_port}"}}'
2355 )
2356 expression = f"({metric_selector} {rel_operator} {scalein_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002357 labels = {
2358 "ns_id": nsr_id,
2359 "vnf_member_index": vnf_member_index,
2360 "vdu_id": vdu_id,
2361 }
2362 prom_cfg = {
2363 "alert": name,
2364 "expr": expression,
2365 "for": str(threshold_time) + "m",
2366 "labels": labels,
2367 }
2368 action = scaling_policy
2369 action = {
2370 "scaling-group": scaling_group_name,
2371 "cooldown-time": cooldown_time,
2372 }
2373 alert = {
2374 "uuid": uuid,
2375 "name": name,
2376 "metric": metric_name,
2377 "tags": {
2378 "ns_id": nsr_id,
2379 "vnf_member_index": vnf_member_index,
2380 "vdu_id": vdu_id,
2381 },
2382 "alarm_status": "ok",
2383 "action_type": "scale_in",
2384 "action": action,
2385 "prometheus_config": prom_cfg,
2386 }
2387 alerts.append(alert)
2388
2389 if scaleout_threshold:
2390 uuid = str(uuid4())
2391 name = f"scaleout_{uuid}"
2392 operation = scaling_criteria[
2393 "scale-out-relational-operation"
2394 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002395 rel_operator = self.rel_operation_types.get(
2396 operation, "<="
2397 )
aguilard1ae3c562023-02-16 17:24:35 +00002398 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2399 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
Rahul Kumar54671c52024-05-09 15:34:01 +05302400 if (
2401 "exporters-endpoints" in df
2402 and metric_name.startswith("kpi_")
2403 ):
2404 new_metric_name = (
2405 f'osm_{metric_name.replace("kpi_", "").strip()}'
2406 )
2407 metric_port = df["exporters-endpoints"].get(
2408 "metric-port", 9100
2409 )
2410 vdu_ip = vdur["ip-address"]
2411 ip_port = str(vdu_ip) + ":" + str(metric_port)
2412 metric_selector = (
2413 f'{new_metric_name}{{instance="{ip_port}"}}'
2414 )
2415 expression = f"({metric_selector} {rel_operator} {scaleout_threshold})"
aguilard1ae3c562023-02-16 17:24:35 +00002416 labels = {
2417 "ns_id": nsr_id,
2418 "vnf_member_index": vnf_member_index,
2419 "vdu_id": vdu_id,
2420 }
2421 prom_cfg = {
2422 "alert": name,
2423 "expr": expression,
2424 "for": str(threshold_time) + "m",
2425 "labels": labels,
2426 }
2427 action = scaling_policy
2428 action = {
2429 "scaling-group": scaling_group_name,
2430 "cooldown-time": cooldown_time,
2431 }
2432 alert = {
2433 "uuid": uuid,
2434 "name": name,
2435 "metric": metric_name,
2436 "tags": {
2437 "ns_id": nsr_id,
2438 "vnf_member_index": vnf_member_index,
2439 "vdu_id": vdu_id,
2440 },
2441 "alarm_status": "ok",
2442 "action_type": "scale_out",
2443 "action": action,
2444 "prometheus_config": prom_cfg,
2445 }
2446 alerts.append(alert)
2447 return alerts
2448
garciadeblas9148fa82023-05-30 12:51:14 +02002449 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2450 alerts = []
2451 nsr_id = vnfr["nsr-id-ref"]
2452 vnf_member_index = vnfr["member-vnf-index-ref"]
2453
2454 # Checking for VNF alarm configuration
2455 for vdur in vnfr["vdur"]:
2456 vdu_id = vdur["vdu-id-ref"]
2457 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2458 if "alarm" in vdu:
2459 # Get VDU monitoring params, since alerts are based on them
2460 vdu_monitoring_params = {}
2461 for mp in vdu.get("monitoring-parameter", []):
2462 vdu_monitoring_params[mp.get("id")] = mp
2463 if not vdu_monitoring_params:
2464 self.logger.error(
2465 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2466 )
2467 continue
2468 # Get alarms in the VDU
2469 alarm_descriptors = vdu["alarm"]
2470 # Create VDU alarms for each alarm in the VDU
2471 for alarm_descriptor in alarm_descriptors:
2472 # Check that the VDU alarm refers to a proper monitoring param
2473 alarm_monitoring_param = alarm_descriptor.get(
2474 "vnf-monitoring-param-ref", ""
2475 )
2476 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2477 alarm_monitoring_param, {}
2478 )
2479 if not vdu_specific_monitoring_param:
2480 self.logger.error(
2481 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2482 )
2483 continue
2484 metric_name = vdu_specific_monitoring_param.get(
2485 "performance-metric"
2486 )
2487 if not metric_name:
2488 self.logger.error(
2489 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2490 )
2491 continue
2492 # Set params of the alarm to be created in Prometheus
2493 metric_name = f"osm_{metric_name}"
2494 metric_threshold = alarm_descriptor.get("value")
2495 uuid = str(uuid4())
2496 alert_name = f"vdu_alarm_{uuid}"
2497 operation = alarm_descriptor["operation"]
2498 rel_operator = self.rel_operation_types.get(operation, "<=")
2499 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 +00002500 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002501 labels = {
2502 "ns_id": nsr_id,
2503 "vnf_member_index": vnf_member_index,
2504 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002505 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002506 }
2507 prom_cfg = {
2508 "alert": alert_name,
2509 "expr": expression,
2510 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2511 "labels": labels,
2512 }
2513 alarm_action = dict()
2514 for action_type in ["ok", "insufficient-data", "alarm"]:
2515 if (
2516 "actions" in alarm_descriptor
2517 and action_type in alarm_descriptor["actions"]
2518 ):
aguilardeb076722023-05-31 09:45:00 +00002519 alarm_action[action_type] = alarm_descriptor["actions"][
2520 action_type
2521 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002522 alert = {
2523 "uuid": uuid,
2524 "name": alert_name,
2525 "metric": metric_name,
2526 "tags": {
2527 "ns_id": nsr_id,
2528 "vnf_member_index": vnf_member_index,
2529 "vdu_id": vdu_id,
2530 },
2531 "alarm_status": "ok",
2532 "action_type": "vdu_alarm",
2533 "action": alarm_action,
2534 "prometheus_config": prom_cfg,
2535 }
2536 alerts.append(alert)
2537 return alerts
2538
magnussonle9198bb2020-01-21 13:00:51 +01002539 def update_nsrs_with_pla_result(self, params):
2540 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002541 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2542 self.update_db_2(
2543 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2544 )
magnussonle9198bb2020-01-21 13:00:51 +01002545 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002546 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002547
tierno59d22d22018-09-25 18:10:19 +02002548 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002549 """
2550
2551 :param nsr_id: ns instance to deploy
2552 :param nslcmop_id: operation to run
2553 :return:
2554 """
kuused124bfe2019-06-18 12:09:24 +02002555
2556 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002557 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002558 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002559 self.logger.debug(
2560 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2561 )
kuused124bfe2019-06-18 12:09:24 +02002562 return
2563
tierno59d22d22018-09-25 18:10:19 +02002564 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2565 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002566
tierno59d22d22018-09-25 18:10:19 +02002567 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002568
2569 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002570 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002571
2572 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002573 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002574
2575 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002576 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002577 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002578 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002579
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002580 timeout_ns_deploy = self.timeout.ns_deploy
2581
tierno59d22d22018-09-25 18:10:19 +02002582 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002583 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002584 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002585 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002586 exc = None
tiernoe876f672020-02-13 14:34:48 +00002587 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002588 stage = [
2589 "Stage 1/5: preparation of the environment.",
2590 "Waiting for previous operations to terminate.",
2591 "",
2592 ]
tiernoe876f672020-02-13 14:34:48 +00002593 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002594 try:
kuused124bfe2019-06-18 12:09:24 +02002595 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002596 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002597
quilesj7e13aeb2019-10-08 13:34:55 +02002598 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002599 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002600 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002601 db_nsr_update["detailed-status"] = "creating"
2602 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002603 self._write_ns_status(
2604 nsr_id=nsr_id,
2605 ns_state="BUILDING",
2606 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002607 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002608 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002609 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002610 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002611
quilesj7e13aeb2019-10-08 13:34:55 +02002612 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002613 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002614 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002615 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2616 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2617 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2618 )
tierno744303e2020-01-13 16:46:31 +00002619 ns_params = db_nslcmop.get("operationParams")
2620 if ns_params and ns_params.get("timeout_ns_deploy"):
2621 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002622
2623 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002624 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002625 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002626 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002627 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002628 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002629 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002630 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002631 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002632 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002633
quilesj7e13aeb2019-10-08 13:34:55 +02002634 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002635 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002636 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002637 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002638
quilesj7e13aeb2019-10-08 13:34:55 +02002639 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002640 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002641
2642 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002643 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002644 if vnfr.get("kdur"):
2645 kdur_list = []
2646 for kdur in vnfr["kdur"]:
2647 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002648 kdur["additionalParams"] = json.loads(
2649 kdur["additionalParams"]
2650 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002651 kdur_list.append(kdur)
2652 vnfr["kdur"] = kdur_list
2653
bravof922c4172020-11-24 21:21:43 -03002654 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2655 vnfd_id = vnfr["vnfd-id"]
2656 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002657 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002658
quilesj7e13aeb2019-10-08 13:34:55 +02002659 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002660 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002661 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002662 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2663 vnfd_id, vnfd_ref
2664 )
tiernoe876f672020-02-13 14:34:48 +00002665 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002666 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002667
quilesj7e13aeb2019-10-08 13:34:55 +02002668 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002669 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002670
2671 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002672 vca_deployed_list = None
2673 if db_nsr["_admin"].get("deployed"):
2674 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2675 if vca_deployed_list is None:
2676 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002677 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002678 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002679 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002680 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002681 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002682 elif isinstance(vca_deployed_list, dict):
2683 # maintain backward compatibility. Change a dict to list at database
2684 vca_deployed_list = list(vca_deployed_list.values())
2685 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002686 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002687
garciadeblas5697b8b2021-03-24 09:17:02 +01002688 if not isinstance(
2689 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2690 ):
tiernoa009e552019-01-30 16:45:44 +00002691 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2692 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002693
tiernobaa51102018-12-14 13:16:18 +00002694 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2695 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2696 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002697 self.db.set_list(
2698 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2699 )
quilesj3655ae02019-12-12 16:08:35 +00002700
2701 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002702 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2703 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002704
tiernob5203912020-08-11 11:20:13 +00002705 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002706 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002707 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002708 await self.deploy_kdus(
2709 logging_text=logging_text,
2710 nsr_id=nsr_id,
2711 nslcmop_id=nslcmop_id,
2712 db_vnfrs=db_vnfrs,
2713 db_vnfds=db_vnfds,
2714 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002715 )
tiernoe876f672020-02-13 14:34:48 +00002716
2717 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002718 # n2vc_redesign STEP 1 Get VCA public ssh-key
2719 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002720 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002721 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002722 if self.vca_config.public_key:
2723 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002724
tiernoe876f672020-02-13 14:34:48 +00002725 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002726 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002727 self.instantiate_RO(
2728 logging_text=logging_text,
2729 nsr_id=nsr_id,
2730 nsd=nsd,
2731 db_nsr=db_nsr,
2732 db_nslcmop=db_nslcmop,
2733 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002734 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002735 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002736 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002737 )
tiernod8323042019-08-09 11:32:23 +00002738 )
2739 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002740 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002741
tiernod8323042019-08-09 11:32:23 +00002742 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002743 stage[1] = "Deploying Execution Environments."
2744 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002745
Gabriel Cuba1411a002022-10-07 11:38:23 -05002746 # create namespace and certificate if any helm based EE is present in the NS
2747 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002748 await self.vca_map["helm-v3"].setup_ns_namespace(
2749 name=nsr_id,
2750 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002751 # create TLS certificates
2752 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002753 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002754 dns_prefix="*",
2755 nsr_id=nsr_id,
2756 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002757 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002758 )
2759
tiernod8323042019-08-09 11:32:23 +00002760 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002761 for vnf_profile in get_vnf_profiles(nsd):
2762 vnfd_id = vnf_profile["vnfd-id"]
2763 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2764 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002765 db_vnfr = db_vnfrs[member_vnf_index]
2766 base_folder = vnfd["_admin"]["storage"]
2767 vdu_id = None
2768 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002769 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002770 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002771 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002772
tierno8a518872018-12-21 13:42:14 +00002773 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002774 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002775 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002776 deploy_params.update(
2777 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2778 )
tierno8a518872018-12-21 13:42:14 +00002779
bravofe5a31bc2021-02-17 19:09:12 -03002780 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002781 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002782 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002783 logging_text=logging_text
2784 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002785 db_nsr=db_nsr,
2786 db_vnfr=db_vnfr,
2787 nslcmop_id=nslcmop_id,
2788 nsr_id=nsr_id,
2789 nsi_id=nsi_id,
2790 vnfd_id=vnfd_id,
2791 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002792 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002793 member_vnf_index=member_vnf_index,
2794 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002795 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002796 vdu_name=vdu_name,
2797 deploy_params=deploy_params,
2798 descriptor_config=descriptor_config,
2799 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002800 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002801 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002802 )
tierno59d22d22018-09-25 18:10:19 +02002803
2804 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002805 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002806 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002807 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002808 vdur = find_in_list(
2809 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2810 )
bravof922c4172020-11-24 21:21:43 -03002811
tierno626e0152019-11-29 14:16:16 +00002812 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002813 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002814 else:
2815 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002816 deploy_params_vdu["OSM"] = get_osm_params(
2817 db_vnfr, vdu_id, vdu_count_index=0
2818 )
endika76ba9232021-06-21 18:55:07 +02002819 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002820
2821 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002822 self.logger.debug(
2823 "Descriptor config > {}".format(descriptor_config)
2824 )
tierno588547c2020-07-01 15:30:20 +00002825 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002826 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002827 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002828 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002829 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002830 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
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={}, vdu_id={}, vdu_index={} ".format(
2834 member_vnf_index, vdu_id, vdu_index
2835 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002836 db_nsr=db_nsr,
2837 db_vnfr=db_vnfr,
2838 nslcmop_id=nslcmop_id,
2839 nsr_id=nsr_id,
2840 nsi_id=nsi_id,
2841 vnfd_id=vnfd_id,
2842 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002843 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002844 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002845 member_vnf_index=member_vnf_index,
2846 vdu_index=vdu_index,
2847 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002848 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002849 descriptor_config=descriptor_config,
2850 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002851 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002852 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002853 )
bravof922c4172020-11-24 21:21:43 -03002854 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002855 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002856 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002857 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002858 vdu_id = None
2859 vdu_index = 0
2860 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002861 kdu_index, kdur = next(
2862 x
2863 for x in enumerate(db_vnfr["kdur"])
2864 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002865 )
bravof922c4172020-11-24 21:21:43 -03002866 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002867 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002868 deploy_params_kdu.update(
2869 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002870 )
tierno59d22d22018-09-25 18:10:19 +02002871
calvinosanch9f9c6f22019-11-04 13:37:39 +01002872 self._deploy_n2vc(
2873 logging_text=logging_text,
2874 db_nsr=db_nsr,
2875 db_vnfr=db_vnfr,
2876 nslcmop_id=nslcmop_id,
2877 nsr_id=nsr_id,
2878 nsi_id=nsi_id,
2879 vnfd_id=vnfd_id,
2880 vdu_id=vdu_id,
2881 kdu_name=kdu_name,
2882 member_vnf_index=member_vnf_index,
2883 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002884 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002885 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002886 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002887 descriptor_config=descriptor_config,
2888 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002889 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002890 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002891 )
tierno59d22d22018-09-25 18:10:19 +02002892
k4.rahul74944982023-04-19 17:00:52 +05302893 # Check if each vnf has exporter for metric collection if so update prometheus job records
2894 if "exporters-endpoints" in vnfd.get("df")[0]:
2895 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2896 self.logger.debug("exporter config :{}".format(exporter_config))
2897 artifact_path = "{}/{}/{}".format(
2898 base_folder["folder"],
2899 base_folder["pkg-dir"],
2900 "exporter-endpoint",
2901 )
2902 ee_id = None
2903 ee_config_descriptor = exporter_config
2904 vnfr_id = db_vnfr["id"]
2905 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2906 logging_text,
2907 nsr_id,
2908 vnfr_id,
2909 vdu_id=None,
2910 vdu_index=None,
2911 user=None,
2912 pub_key=None,
2913 )
2914 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
2915 self.logger.debug("Artifact_path:{}".format(artifact_path))
2916 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
2917 vdu_id_for_prom = None
2918 vdu_index_for_prom = None
2919 for x in get_iterable(db_vnfr, "vdur"):
2920 vdu_id_for_prom = x.get("vdu-id-ref")
2921 vdu_index_for_prom = x.get("count-index")
2922 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
2923 ee_id=ee_id,
2924 artifact_path=artifact_path,
2925 ee_config_descriptor=ee_config_descriptor,
2926 vnfr_id=vnfr_id,
2927 nsr_id=nsr_id,
2928 target_ip=rw_mgmt_ip,
2929 element_type="VDU",
2930 vdu_id=vdu_id_for_prom,
2931 vdu_index=vdu_index_for_prom,
2932 )
2933
2934 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
2935 if prometheus_jobs:
2936 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
2937 self.update_db_2(
2938 "nsrs",
2939 nsr_id,
2940 db_nsr_update,
2941 )
2942
2943 for job in prometheus_jobs:
2944 self.db.set_one(
2945 "prometheus_jobs",
2946 {"job_name": job["job_name"]},
2947 job,
2948 upsert=True,
2949 fail_on_empty=False,
2950 )
2951
tierno1b633412019-02-25 16:48:23 +00002952 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002953 descriptor_config = nsd.get("ns-configuration")
2954 if descriptor_config and descriptor_config.get("juju"):
2955 vnfd_id = None
2956 db_vnfr = None
2957 member_vnf_index = None
2958 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002959 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002960 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00002961 vdu_index = 0
2962 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002963
tiernod8323042019-08-09 11:32:23 +00002964 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002965 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002966 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002967 deploy_params.update(
2968 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2969 )
tiernod8323042019-08-09 11:32:23 +00002970 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002971 self._deploy_n2vc(
2972 logging_text=logging_text,
2973 db_nsr=db_nsr,
2974 db_vnfr=db_vnfr,
2975 nslcmop_id=nslcmop_id,
2976 nsr_id=nsr_id,
2977 nsi_id=nsi_id,
2978 vnfd_id=vnfd_id,
2979 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002980 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002981 member_vnf_index=member_vnf_index,
2982 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002983 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002984 vdu_name=vdu_name,
2985 deploy_params=deploy_params,
2986 descriptor_config=descriptor_config,
2987 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002988 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002989 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002990 )
tierno1b633412019-02-25 16:48:23 +00002991
tiernoe876f672020-02-13 14:34:48 +00002992 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002993
garciadeblas5697b8b2021-03-24 09:17:02 +01002994 except (
2995 ROclient.ROClientException,
2996 DbException,
2997 LcmException,
2998 N2VCException,
2999 ) as e:
3000 self.logger.error(
3001 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3002 )
tierno59d22d22018-09-25 18:10:19 +02003003 exc = e
3004 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003005 self.logger.error(
3006 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3007 )
tierno59d22d22018-09-25 18:10:19 +02003008 exc = "Operation was cancelled"
3009 except Exception as e:
3010 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003011 self.logger.critical(
3012 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3013 exc_info=True,
3014 )
tierno59d22d22018-09-25 18:10:19 +02003015 finally:
3016 if exc:
tiernoe876f672020-02-13 14:34:48 +00003017 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003018 try:
tiernoe876f672020-02-13 14:34:48 +00003019 # wait for pending tasks
3020 if tasks_dict_info:
3021 stage[1] = "Waiting for instantiate pending tasks."
3022 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003023 error_list += await self._wait_for_tasks(
3024 logging_text,
3025 tasks_dict_info,
3026 timeout_ns_deploy,
3027 stage,
3028 nslcmop_id,
3029 nsr_id=nsr_id,
3030 )
tiernoe876f672020-02-13 14:34:48 +00003031 stage[1] = stage[2] = ""
3032 except asyncio.CancelledError:
3033 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05003034 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
3035 await self._wait_for_tasks(
3036 logging_text,
3037 tasks_dict_info,
3038 timeout_ns_deploy,
3039 stage,
3040 nslcmop_id,
3041 nsr_id=nsr_id,
3042 )
tiernoe876f672020-02-13 14:34:48 +00003043 except Exception as exc:
3044 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003045
tiernoe876f672020-02-13 14:34:48 +00003046 # update operation-status
3047 db_nsr_update["operational-status"] = "running"
3048 # let's begin with VCA 'configured' status (later we can change it)
3049 db_nsr_update["config-status"] = "configured"
3050 for task, task_name in tasks_dict_info.items():
3051 if not task.done() or task.cancelled() or task.exception():
3052 if task_name.startswith(self.task_name_deploy_vca):
3053 # A N2VC task is pending
3054 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003055 else:
tiernoe876f672020-02-13 14:34:48 +00003056 # RO or KDU task is pending
3057 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003058
tiernoe876f672020-02-13 14:34:48 +00003059 # update status at database
3060 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003061 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003062 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003063 error_description_nslcmop = "{} Detail: {}".format(
3064 stage[0], error_detail
3065 )
3066 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3067 nslcmop_id, stage[0]
3068 )
quilesj3655ae02019-12-12 16:08:35 +00003069
garciadeblas5697b8b2021-03-24 09:17:02 +01003070 db_nsr_update["detailed-status"] = (
3071 error_description_nsr + " Detail: " + error_detail
3072 )
tiernoe876f672020-02-13 14:34:48 +00003073 db_nslcmop_update["detailed-status"] = error_detail
3074 nslcmop_operation_state = "FAILED"
3075 ns_state = "BROKEN"
3076 else:
tiernoa2143262020-03-27 16:20:40 +00003077 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003078 error_description_nsr = error_description_nslcmop = None
3079 ns_state = "READY"
3080 db_nsr_update["detailed-status"] = "Done"
3081 db_nslcmop_update["detailed-status"] = "Done"
3082 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003083 # Gather auto-healing and auto-scaling alerts for each vnfr
3084 healing_alerts = []
3085 scaling_alerts = []
3086 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3087 vnfd = next(
3088 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3089 )
3090 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3091 for alert in healing_alerts:
3092 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3093 self.db.create("alerts", alert)
3094
3095 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3096 for alert in scaling_alerts:
3097 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3098 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003099
garciadeblas9148fa82023-05-30 12:51:14 +02003100 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3101 for alert in alarm_alerts:
3102 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3103 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003104 if db_nsr:
3105 self._write_ns_status(
3106 nsr_id=nsr_id,
3107 ns_state=ns_state,
3108 current_operation="IDLE",
3109 current_operation_id=None,
3110 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003111 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003112 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003113 )
tiernoa17d4f42020-04-28 09:59:23 +00003114 self._write_op_status(
3115 op_id=nslcmop_id,
3116 stage="",
3117 error_message=error_description_nslcmop,
3118 operation_state=nslcmop_operation_state,
3119 other_update=db_nslcmop_update,
3120 )
quilesj3655ae02019-12-12 16:08:35 +00003121
tierno59d22d22018-09-25 18:10:19 +02003122 if nslcmop_operation_state:
3123 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003124 await self.msg.aiowrite(
3125 "ns",
3126 "instantiated",
3127 {
3128 "nsr_id": nsr_id,
3129 "nslcmop_id": nslcmop_id,
3130 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003131 "startTime": db_nslcmop["startTime"],
3132 "links": db_nslcmop["links"],
3133 "operationParams": {
3134 "nsInstanceId": nsr_id,
3135 "nsdId": db_nsr["nsd-id"],
3136 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003137 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003138 )
tierno59d22d22018-09-25 18:10:19 +02003139 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003140 self.logger.error(
3141 logging_text + "kafka_write notification Exception {}".format(e)
3142 )
tierno59d22d22018-09-25 18:10:19 +02003143
3144 self.logger.debug(logging_text + "Exit")
3145 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3146
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003147 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003148 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003149 cached_vnfds[vnfd_id] = self.db.get_one(
3150 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3151 )
David Garciab4ebcd02021-10-28 02:00:43 +02003152 return cached_vnfds[vnfd_id]
3153
3154 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3155 if vnf_profile_id not in cached_vnfrs:
3156 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3157 "vnfrs",
3158 {
3159 "member-vnf-index-ref": vnf_profile_id,
3160 "nsr-id-ref": nsr_id,
3161 },
3162 )
3163 return cached_vnfrs[vnf_profile_id]
3164
3165 def _is_deployed_vca_in_relation(
3166 self, vca: DeployedVCA, relation: Relation
3167 ) -> bool:
3168 found = False
3169 for endpoint in (relation.provider, relation.requirer):
3170 if endpoint["kdu-resource-profile-id"]:
3171 continue
3172 found = (
3173 vca.vnf_profile_id == endpoint.vnf_profile_id
3174 and vca.vdu_profile_id == endpoint.vdu_profile_id
3175 and vca.execution_environment_ref == endpoint.execution_environment_ref
3176 )
3177 if found:
3178 break
3179 return found
3180
3181 def _update_ee_relation_data_with_implicit_data(
3182 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3183 ):
3184 ee_relation_data = safe_get_ee_relation(
3185 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3186 )
3187 ee_relation_level = EELevel.get_level(ee_relation_data)
3188 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3189 "execution-environment-ref"
3190 ]:
3191 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3192 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003193 project = nsd["_admin"]["projects_read"][0]
3194 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003195 entity_id = (
3196 vnfd_id
3197 if ee_relation_level == EELevel.VNF
3198 else ee_relation_data["vdu-profile-id"]
3199 )
3200 ee = get_juju_ee_ref(db_vnfd, entity_id)
3201 if not ee:
3202 raise Exception(
3203 f"not execution environments found for ee_relation {ee_relation_data}"
3204 )
3205 ee_relation_data["execution-environment-ref"] = ee["id"]
3206 return ee_relation_data
3207
3208 def _get_ns_relations(
3209 self,
3210 nsr_id: str,
3211 nsd: Dict[str, Any],
3212 vca: DeployedVCA,
3213 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003214 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003215 relations = []
3216 db_ns_relations = get_ns_configuration_relation_list(nsd)
3217 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003218 provider_dict = None
3219 requirer_dict = None
3220 if all(key in r for key in ("provider", "requirer")):
3221 provider_dict = r["provider"]
3222 requirer_dict = r["requirer"]
3223 elif "entities" in r:
3224 provider_id = r["entities"][0]["id"]
3225 provider_dict = {
3226 "nsr-id": nsr_id,
3227 "endpoint": r["entities"][0]["endpoint"],
3228 }
3229 if provider_id != nsd["id"]:
3230 provider_dict["vnf-profile-id"] = provider_id
3231 requirer_id = r["entities"][1]["id"]
3232 requirer_dict = {
3233 "nsr-id": nsr_id,
3234 "endpoint": r["entities"][1]["endpoint"],
3235 }
3236 if requirer_id != nsd["id"]:
3237 requirer_dict["vnf-profile-id"] = requirer_id
3238 else:
aticig15db6142022-01-24 12:51:26 +03003239 raise Exception(
3240 "provider/requirer or entities must be included in the relation."
3241 )
David Garciab4ebcd02021-10-28 02:00:43 +02003242 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003243 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003244 )
3245 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003246 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003247 )
3248 provider = EERelation(relation_provider)
3249 requirer = EERelation(relation_requirer)
3250 relation = Relation(r["name"], provider, requirer)
3251 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3252 if vca_in_relation:
3253 relations.append(relation)
3254 return relations
3255
3256 def _get_vnf_relations(
3257 self,
3258 nsr_id: str,
3259 nsd: Dict[str, Any],
3260 vca: DeployedVCA,
3261 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003262 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003263 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003264 if vca.target_element == "ns":
3265 self.logger.debug("VCA is a NS charm, not a VNF.")
3266 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003267 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3268 vnf_profile_id = vnf_profile["id"]
3269 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003270 project = nsd["_admin"]["projects_read"][0]
3271 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003272 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3273 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003274 provider_dict = None
3275 requirer_dict = None
3276 if all(key in r for key in ("provider", "requirer")):
3277 provider_dict = r["provider"]
3278 requirer_dict = r["requirer"]
3279 elif "entities" in r:
3280 provider_id = r["entities"][0]["id"]
3281 provider_dict = {
3282 "nsr-id": nsr_id,
3283 "vnf-profile-id": vnf_profile_id,
3284 "endpoint": r["entities"][0]["endpoint"],
3285 }
3286 if provider_id != vnfd_id:
3287 provider_dict["vdu-profile-id"] = provider_id
3288 requirer_id = r["entities"][1]["id"]
3289 requirer_dict = {
3290 "nsr-id": nsr_id,
3291 "vnf-profile-id": vnf_profile_id,
3292 "endpoint": r["entities"][1]["endpoint"],
3293 }
3294 if requirer_id != vnfd_id:
3295 requirer_dict["vdu-profile-id"] = requirer_id
3296 else:
aticig15db6142022-01-24 12:51:26 +03003297 raise Exception(
3298 "provider/requirer or entities must be included in the relation."
3299 )
David Garciab4ebcd02021-10-28 02:00:43 +02003300 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003301 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003302 )
3303 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003304 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003305 )
3306 provider = EERelation(relation_provider)
3307 requirer = EERelation(relation_requirer)
3308 relation = Relation(r["name"], provider, requirer)
3309 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3310 if vca_in_relation:
3311 relations.append(relation)
3312 return relations
3313
3314 def _get_kdu_resource_data(
3315 self,
3316 ee_relation: EERelation,
3317 db_nsr: Dict[str, Any],
3318 cached_vnfds: Dict[str, Any],
3319 ) -> DeployedK8sResource:
3320 nsd = get_nsd(db_nsr)
3321 vnf_profiles = get_vnf_profiles(nsd)
3322 vnfd_id = find_in_list(
3323 vnf_profiles,
3324 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3325 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003326 project = nsd["_admin"]["projects_read"][0]
3327 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003328 kdu_resource_profile = get_kdu_resource_profile(
3329 db_vnfd, ee_relation.kdu_resource_profile_id
3330 )
3331 kdu_name = kdu_resource_profile["kdu-name"]
3332 deployed_kdu, _ = get_deployed_kdu(
3333 db_nsr.get("_admin", ()).get("deployed", ()),
3334 kdu_name,
3335 ee_relation.vnf_profile_id,
3336 )
3337 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3338 return deployed_kdu
3339
3340 def _get_deployed_component(
3341 self,
3342 ee_relation: EERelation,
3343 db_nsr: Dict[str, Any],
3344 cached_vnfds: Dict[str, Any],
3345 ) -> DeployedComponent:
3346 nsr_id = db_nsr["_id"]
3347 deployed_component = None
3348 ee_level = EELevel.get_level(ee_relation)
3349 if ee_level == EELevel.NS:
3350 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3351 if vca:
3352 deployed_component = DeployedVCA(nsr_id, vca)
3353 elif ee_level == EELevel.VNF:
3354 vca = get_deployed_vca(
3355 db_nsr,
3356 {
3357 "vdu_id": None,
3358 "member-vnf-index": ee_relation.vnf_profile_id,
3359 "ee_descriptor_id": ee_relation.execution_environment_ref,
3360 },
3361 )
3362 if vca:
3363 deployed_component = DeployedVCA(nsr_id, vca)
3364 elif ee_level == EELevel.VDU:
3365 vca = get_deployed_vca(
3366 db_nsr,
3367 {
3368 "vdu_id": ee_relation.vdu_profile_id,
3369 "member-vnf-index": ee_relation.vnf_profile_id,
3370 "ee_descriptor_id": ee_relation.execution_environment_ref,
3371 },
3372 )
3373 if vca:
3374 deployed_component = DeployedVCA(nsr_id, vca)
3375 elif ee_level == EELevel.KDU:
3376 kdu_resource_data = self._get_kdu_resource_data(
3377 ee_relation, db_nsr, cached_vnfds
3378 )
3379 if kdu_resource_data:
3380 deployed_component = DeployedK8sResource(kdu_resource_data)
3381 return deployed_component
3382
3383 async def _add_relation(
3384 self,
3385 relation: Relation,
3386 vca_type: str,
3387 db_nsr: Dict[str, Any],
3388 cached_vnfds: Dict[str, Any],
3389 cached_vnfrs: Dict[str, Any],
3390 ) -> bool:
3391 deployed_provider = self._get_deployed_component(
3392 relation.provider, db_nsr, cached_vnfds
3393 )
3394 deployed_requirer = self._get_deployed_component(
3395 relation.requirer, db_nsr, cached_vnfds
3396 )
3397 if (
3398 deployed_provider
3399 and deployed_requirer
3400 and deployed_provider.config_sw_installed
3401 and deployed_requirer.config_sw_installed
3402 ):
3403 provider_db_vnfr = (
3404 self._get_vnfr(
3405 relation.provider.nsr_id,
3406 relation.provider.vnf_profile_id,
3407 cached_vnfrs,
3408 )
3409 if relation.provider.vnf_profile_id
3410 else None
3411 )
3412 requirer_db_vnfr = (
3413 self._get_vnfr(
3414 relation.requirer.nsr_id,
3415 relation.requirer.vnf_profile_id,
3416 cached_vnfrs,
3417 )
3418 if relation.requirer.vnf_profile_id
3419 else None
3420 )
3421 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3422 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3423 provider_relation_endpoint = RelationEndpoint(
3424 deployed_provider.ee_id,
3425 provider_vca_id,
3426 relation.provider.endpoint,
3427 )
3428 requirer_relation_endpoint = RelationEndpoint(
3429 deployed_requirer.ee_id,
3430 requirer_vca_id,
3431 relation.requirer.endpoint,
3432 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003433 try:
3434 await self.vca_map[vca_type].add_relation(
3435 provider=provider_relation_endpoint,
3436 requirer=requirer_relation_endpoint,
3437 )
3438 except N2VCException as exception:
3439 self.logger.error(exception)
3440 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003441 return True
3442 return False
3443
David Garciac1fe90a2021-03-31 19:12:02 +02003444 async def _add_vca_relations(
3445 self,
3446 logging_text,
3447 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003448 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003449 vca_index: int,
3450 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003451 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003452 # steps:
3453 # 1. find all relations for this VCA
3454 # 2. wait for other peers related
3455 # 3. add relations
3456
3457 try:
quilesj63f90042020-01-17 09:53:55 +00003458 # STEP 1: find all relations for this VCA
3459
3460 # read nsr record
3461 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003462 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003463
3464 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003465 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3466 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003467
David Garciab4ebcd02021-10-28 02:00:43 +02003468 cached_vnfds = {}
3469 cached_vnfrs = {}
3470 relations = []
3471 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3472 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003473
3474 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003475 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003476 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003477 return True
3478
David Garciab4ebcd02021-10-28 02:00:43 +02003479 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003480
3481 # add all relations
3482 start = time()
3483 while True:
3484 # check timeout
3485 now = time()
3486 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003487 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003488 return False
3489
David Garciab4ebcd02021-10-28 02:00:43 +02003490 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003491 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3492
David Garciab4ebcd02021-10-28 02:00:43 +02003493 # for each relation, find the VCA's related
3494 for relation in relations.copy():
3495 added = await self._add_relation(
3496 relation,
3497 vca_type,
3498 db_nsr,
3499 cached_vnfds,
3500 cached_vnfrs,
3501 )
3502 if added:
3503 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003504
David Garciab4ebcd02021-10-28 02:00:43 +02003505 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003506 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003507 break
David Garciab4ebcd02021-10-28 02:00:43 +02003508 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003509
3510 return True
3511
3512 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003513 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003514 return False
3515
garciadeblas5697b8b2021-03-24 09:17:02 +01003516 async def _install_kdu(
3517 self,
3518 nsr_id: str,
3519 nsr_db_path: str,
3520 vnfr_data: dict,
3521 kdu_index: int,
3522 kdud: dict,
3523 vnfd: dict,
3524 k8s_instance_info: dict,
3525 k8params: dict = None,
3526 timeout: int = 600,
3527 vca_id: str = None,
3528 ):
tiernob9018152020-04-16 14:18:24 +00003529 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003530 k8sclustertype = k8s_instance_info["k8scluster-type"]
3531 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003532 db_dict_install = {
3533 "collection": "nsrs",
3534 "filter": {"_id": nsr_id},
3535 "path": nsr_db_path,
3536 }
lloretgalleg7c121132020-07-08 07:53:22 +00003537
romeromonser4554a702021-05-28 12:00:08 +02003538 if k8s_instance_info.get("kdu-deployment-name"):
3539 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3540 else:
3541 kdu_instance = self.k8scluster_map[
3542 k8sclustertype
3543 ].generate_kdu_instance_name(
3544 db_dict=db_dict_install,
3545 kdu_model=k8s_instance_info["kdu-model"],
3546 kdu_name=k8s_instance_info["kdu-name"],
3547 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003548
3549 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003550 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003551 item="nsrs",
3552 _id=nsr_id,
3553 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003554 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003555
3556 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3557 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3558 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3559 # namespace, this first verification could be removed, and the next step would be done for any kind
3560 # of KNF.
3561 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3562 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3563 if k8sclustertype in ("juju", "juju-bundle"):
3564 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3565 # that the user passed a namespace which he wants its KDU to be deployed in)
3566 if (
3567 self.db.count(
3568 table="nsrs",
3569 q_filter={
3570 "_id": nsr_id,
3571 "_admin.projects_write": k8s_instance_info["namespace"],
3572 "_admin.projects_read": k8s_instance_info["namespace"],
3573 },
3574 )
3575 > 0
3576 ):
3577 self.logger.debug(
3578 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3579 )
3580 self.update_db_2(
3581 item="nsrs",
3582 _id=nsr_id,
3583 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3584 )
3585 k8s_instance_info["namespace"] = kdu_instance
3586
David Garciad64e2742021-02-25 20:19:18 +01003587 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003588 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3589 kdu_model=k8s_instance_info["kdu-model"],
3590 atomic=True,
3591 params=k8params,
3592 db_dict=db_dict_install,
3593 timeout=timeout,
3594 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003595 namespace=k8s_instance_info["namespace"],
3596 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003597 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003598 )
lloretgalleg7c121132020-07-08 07:53:22 +00003599
3600 # Obtain services to obtain management service ip
3601 services = await self.k8scluster_map[k8sclustertype].get_services(
3602 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3603 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003604 namespace=k8s_instance_info["namespace"],
3605 )
lloretgalleg7c121132020-07-08 07:53:22 +00003606
3607 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003608 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003609 kdu_config = get_configuration(vnfd, kdud["name"])
3610 if kdu_config:
3611 target_ee_list = kdu_config.get("execution-environment-list", [])
3612 else:
3613 target_ee_list = []
3614
lloretgalleg7c121132020-07-08 07:53:22 +00003615 if services:
tierno7ecbc342020-09-21 14:05:39 +00003616 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003617 mgmt_services = [
3618 service
3619 for service in kdud.get("service", [])
3620 if service.get("mgmt-service")
3621 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003622 for mgmt_service in mgmt_services:
3623 for service in services:
3624 if service["name"].startswith(mgmt_service["name"]):
3625 # Mgmt service found, Obtain service ip
3626 ip = service.get("external_ip", service.get("cluster_ip"))
3627 if isinstance(ip, list) and len(ip) == 1:
3628 ip = ip[0]
3629
garciadeblas5697b8b2021-03-24 09:17:02 +01003630 vnfr_update_dict[
3631 "kdur.{}.ip-address".format(kdu_index)
3632 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003633
3634 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003635 service_external_cp = mgmt_service.get(
3636 "external-connection-point-ref"
3637 )
lloretgalleg7c121132020-07-08 07:53:22 +00003638 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003639 if (
3640 deep_get(vnfd, ("mgmt-interface", "cp"))
3641 == service_external_cp
3642 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003643 vnfr_update_dict["ip-address"] = ip
3644
bravof6ec62b72021-02-25 17:20:35 -03003645 if find_in_list(
3646 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003647 lambda ee: ee.get(
3648 "external-connection-point-ref", ""
3649 )
3650 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003651 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003652 vnfr_update_dict[
3653 "kdur.{}.ip-address".format(kdu_index)
3654 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003655 break
3656 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003657 self.logger.warn(
3658 "Mgmt service name: {} not found".format(
3659 mgmt_service["name"]
3660 )
3661 )
lloretgalleg7c121132020-07-08 07:53:22 +00003662
tierno7ecbc342020-09-21 14:05:39 +00003663 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3664 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003665
bravof9a256db2021-02-22 18:02:07 -03003666 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003667 if (
3668 kdu_config
3669 and kdu_config.get("initial-config-primitive")
3670 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3671 ):
3672 initial_config_primitive_list = kdu_config.get(
3673 "initial-config-primitive"
3674 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003675 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3676
3677 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003678 primitive_params_ = self._map_primitive_params(
3679 initial_config_primitive, {}, {}
3680 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003681
3682 await asyncio.wait_for(
3683 self.k8scluster_map[k8sclustertype].exec_primitive(
3684 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3685 kdu_instance=kdu_instance,
3686 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003687 params=primitive_params_,
3688 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003689 vca_id=vca_id,
3690 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003691 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003692 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003693
tiernob9018152020-04-16 14:18:24 +00003694 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003695 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003696 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003697 self.update_db_2(
3698 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3699 )
3700 self.update_db_2(
3701 "vnfrs",
3702 vnfr_data.get("_id"),
3703 {"kdur.{}.status".format(kdu_index): "ERROR"},
3704 )
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003705 except Exception as error:
lloretgalleg7c121132020-07-08 07:53:22 +00003706 # ignore to keep original exception
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003707 self.logger.warning(
3708 f"An exception occurred while updating DB: {str(error)}"
3709 )
lloretgalleg7c121132020-07-08 07:53:22 +00003710 # reraise original error
3711 raise
3712
3713 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003714
garciadeblas5697b8b2021-03-24 09:17:02 +01003715 async def deploy_kdus(
3716 self,
3717 logging_text,
3718 nsr_id,
3719 nslcmop_id,
3720 db_vnfrs,
3721 db_vnfds,
3722 task_instantiation_info,
3723 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003724 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003725
garciadeblas5697b8b2021-03-24 09:17:02 +01003726 k8scluster_id_2_uuic = {
3727 "helm-chart-v3": {},
garciadeblas5697b8b2021-03-24 09:17:02 +01003728 "juju-bundle": {},
3729 }
tierno626e0152019-11-29 14:16:16 +00003730
tierno16f4a4e2020-07-20 09:05:51 +00003731 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003732 nonlocal k8scluster_id_2_uuic
3733 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3734 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3735
tierno16f4a4e2020-07-20 09:05:51 +00003736 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003737 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3738 "k8scluster", cluster_id
3739 )
tierno16f4a4e2020-07-20 09:05:51 +00003740 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003741 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3742 task_name, cluster_id
3743 )
tierno16f4a4e2020-07-20 09:05:51 +00003744 self.logger.debug(logging_text + text)
3745 await asyncio.wait(task_dependency, timeout=3600)
3746
garciadeblas5697b8b2021-03-24 09:17:02 +01003747 db_k8scluster = self.db.get_one(
3748 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3749 )
tierno626e0152019-11-29 14:16:16 +00003750 if not db_k8scluster:
3751 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003752
tierno626e0152019-11-29 14:16:16 +00003753 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3754 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003755 if cluster_type == "helm-chart-v3":
3756 try:
3757 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003758 k8s_credentials = yaml.safe_dump(
3759 db_k8scluster.get("credentials")
3760 )
3761 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3762 k8s_credentials, reuse_cluster_uuid=cluster_id
3763 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003764 db_k8scluster_update = {}
3765 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3766 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003767 db_k8scluster_update[
3768 "_admin.helm-chart-v3.created"
3769 ] = uninstall_sw
3770 db_k8scluster_update[
3771 "_admin.helm-chart-v3.operationalState"
3772 ] = "ENABLED"
3773 self.update_db_2(
3774 "k8sclusters", cluster_id, db_k8scluster_update
3775 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003776 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003777 self.logger.error(
3778 logging_text
3779 + "error initializing helm-v3 cluster: {}".format(str(e))
3780 )
3781 raise LcmException(
3782 "K8s cluster '{}' has not been initialized for '{}'".format(
3783 cluster_id, cluster_type
3784 )
3785 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003786 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003787 raise LcmException(
3788 "K8s cluster '{}' has not been initialized for '{}'".format(
3789 cluster_id, cluster_type
3790 )
3791 )
tierno626e0152019-11-29 14:16:16 +00003792 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3793 return k8s_id
3794
3795 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003796 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003797 try:
tierno626e0152019-11-29 14:16:16 +00003798 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003799 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003800
tierno626e0152019-11-29 14:16:16 +00003801 index = 0
tiernoe876f672020-02-13 14:34:48 +00003802 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003803 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003804
tierno626e0152019-11-29 14:16:16 +00003805 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003806 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003807 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3808 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003809 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003810 vnfd_id = vnfr_data.get("vnfd-id")
3811 vnfd_with_id = find_in_list(
3812 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3813 )
3814 kdud = next(
3815 kdud
3816 for kdud in vnfd_with_id["kdu"]
3817 if kdud["name"] == kdur["kdu-name"]
3818 )
tiernode1584f2020-04-07 09:07:33 +00003819 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003820 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003821 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003822 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003823 # Default version: helm3, if helm-version is v2 assign v2
3824 k8sclustertype = "helm-chart-v3"
3825 self.logger.debug("kdur: {}".format(kdur))
tierno626e0152019-11-29 14:16:16 +00003826 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003827 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003828 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003829 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003830 raise LcmException(
3831 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3832 "juju-bundle. Maybe an old NBI version is running".format(
3833 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3834 )
3835 )
quilesjacde94f2020-01-23 10:07:08 +00003836 # check if kdumodel is a file and exists
3837 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003838 vnfd_with_id = find_in_list(
3839 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3840 )
3841 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003842 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003843 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003844 if storage["pkg-dir"]:
3845 filename = "{}/{}/{}s/{}".format(
3846 storage["folder"],
3847 storage["pkg-dir"],
3848 k8sclustertype,
3849 kdumodel,
3850 )
3851 else:
3852 filename = "{}/Scripts/{}s/{}".format(
3853 storage["folder"],
3854 k8sclustertype,
3855 kdumodel,
3856 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003857 if self.fs.file_exists(
3858 filename, mode="file"
3859 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003860 kdumodel = self.fs.path + filename
3861 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003862 raise
Gabriel Cuba4c0e6802023-10-09 13:22:38 -05003863 except Exception as e: # it is not a file
3864 self.logger.warning(f"An exception occurred: {str(e)}")
lloretgallegedc5f332020-02-20 11:50:50 +01003865
tiernoe876f672020-02-13 14:34:48 +00003866 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003867 step = "Synchronize repos for k8s cluster '{}'".format(
3868 k8s_cluster_id
3869 )
tierno16f4a4e2020-07-20 09:05:51 +00003870 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003871
lloretgalleg7c121132020-07-08 07:53:22 +00003872 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003873 if (
3874 k8sclustertype == "helm-chart"
3875 and cluster_uuid not in updated_cluster_list
3876 ) or (
3877 k8sclustertype == "helm-chart-v3"
3878 and cluster_uuid not in updated_v3_cluster_list
3879 ):
tiernoe876f672020-02-13 14:34:48 +00003880 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003881 self.k8scluster_map[k8sclustertype].synchronize_repos(
3882 cluster_uuid=cluster_uuid
3883 )
3884 )
tiernoe876f672020-02-13 14:34:48 +00003885 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003886 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003887 unset = {
3888 "_admin.helm_charts_added." + item: None
3889 for item in del_repo_list
3890 }
3891 updated = {
3892 "_admin.helm_charts_added." + item: name
3893 for item, name in added_repo_dict.items()
3894 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003895 updated_cluster_list.append(cluster_uuid)
3896 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003897 unset = {
3898 "_admin.helm_charts_v3_added." + item: None
3899 for item in del_repo_list
3900 }
3901 updated = {
3902 "_admin.helm_charts_v3_added." + item: name
3903 for item, name in added_repo_dict.items()
3904 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003905 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003906 self.logger.debug(
3907 logging_text + "repos synchronized on k8s cluster "
3908 "'{}' to_delete: {}, to_add: {}".format(
3909 k8s_cluster_id, del_repo_list, added_repo_dict
3910 )
3911 )
3912 self.db.set_one(
3913 "k8sclusters",
3914 {"_id": k8s_cluster_id},
3915 updated,
3916 unset=unset,
3917 )
lloretgallegedc5f332020-02-20 11:50:50 +01003918
lloretgalleg7c121132020-07-08 07:53:22 +00003919 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003920 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3921 vnfr_data["member-vnf-index-ref"],
3922 kdur["kdu-name"],
3923 k8s_cluster_id,
3924 )
3925 k8s_instance_info = {
3926 "kdu-instance": None,
3927 "k8scluster-uuid": cluster_uuid,
3928 "k8scluster-type": k8sclustertype,
3929 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3930 "kdu-name": kdur["kdu-name"],
3931 "kdu-model": kdumodel,
3932 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003933 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003934 }
tiernob9018152020-04-16 14:18:24 +00003935 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003936 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003937 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003938 vnfd_with_id = find_in_list(
3939 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3940 )
tiernoa2143262020-03-27 16:20:40 +00003941 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003942 self._install_kdu(
3943 nsr_id,
3944 db_path,
3945 vnfr_data,
3946 kdu_index,
3947 kdud,
3948 vnfd_with_id,
3949 k8s_instance_info,
3950 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003951 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003952 vca_id=vca_id,
3953 )
3954 )
3955 self.lcm_tasks.register(
3956 "ns",
3957 nsr_id,
3958 nslcmop_id,
3959 "instantiate_KDU-{}".format(index),
3960 task,
3961 )
3962 task_instantiation_info[task] = "Deploying KDU {}".format(
3963 kdur["kdu-name"]
3964 )
tiernoe876f672020-02-13 14:34:48 +00003965
tierno626e0152019-11-29 14:16:16 +00003966 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003967
tiernoe876f672020-02-13 14:34:48 +00003968 except (LcmException, asyncio.CancelledError):
3969 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003970 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003971 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3972 if isinstance(e, (N2VCException, DbException)):
3973 self.logger.error(logging_text + msg)
3974 else:
3975 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003976 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003977 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003978 if db_nsr_update:
3979 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003980
garciadeblas5697b8b2021-03-24 09:17:02 +01003981 def _deploy_n2vc(
3982 self,
3983 logging_text,
3984 db_nsr,
3985 db_vnfr,
3986 nslcmop_id,
3987 nsr_id,
3988 nsi_id,
3989 vnfd_id,
3990 vdu_id,
3991 kdu_name,
3992 member_vnf_index,
3993 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003994 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01003995 vdu_name,
3996 deploy_params,
3997 descriptor_config,
3998 base_folder,
3999 task_instantiation_info,
4000 stage,
4001 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004002 # launch instantiate_N2VC in a asyncio task and register task object
4003 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4004 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004005 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004006
garciadeblas5697b8b2021-03-24 09:17:02 +01004007 self.logger.debug(
4008 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4009 )
aticig9bc63ac2022-07-27 09:32:06 +03004010
4011 charm_name = ""
4012 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004013 if "execution-environment-list" in descriptor_config:
4014 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004015 elif "juju" in descriptor_config:
4016 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004017 if "execution-environment-list" not in descriptor_config:
4018 # charm name is only required for ns charms
4019 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004020 else: # other types as script are not supported
4021 ee_list = []
4022
4023 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004024 self.logger.debug(
4025 logging_text
4026 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4027 ee_item.get("juju"), ee_item.get("helm-chart")
4028 )
4029 )
tiernoa278b842020-07-08 15:33:55 +00004030 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05004031 vca_name, charm_name, vca_type = self.get_vca_info(
4032 ee_item, db_nsr, get_charm_name
4033 )
4034 if not vca_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01004035 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05004036 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas5697b8b2021-03-24 09:17:02 +01004037 )
quilesj7e13aeb2019-10-08 13:34:55 +02004038 continue
quilesj3655ae02019-12-12 16:08:35 +00004039
tierno588547c2020-07-01 15:30:20 +00004040 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004041 for vca_index, vca_deployed in enumerate(
4042 db_nsr["_admin"]["deployed"]["VCA"]
4043 ):
tierno588547c2020-07-01 15:30:20 +00004044 if not vca_deployed:
4045 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004046 if (
4047 vca_deployed.get("member-vnf-index") == member_vnf_index
4048 and vca_deployed.get("vdu_id") == vdu_id
4049 and vca_deployed.get("kdu_name") == kdu_name
4050 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4051 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4052 ):
tierno588547c2020-07-01 15:30:20 +00004053 break
4054 else:
4055 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004056 target = (
4057 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4058 )
tiernoa278b842020-07-08 15:33:55 +00004059 if vdu_id:
4060 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4061 elif kdu_name:
4062 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004063 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004064 "target_element": target,
4065 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004066 "member-vnf-index": member_vnf_index,
4067 "vdu_id": vdu_id,
4068 "kdu_name": kdu_name,
4069 "vdu_count_index": vdu_index,
4070 "operational-status": "init", # TODO revise
4071 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004072 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004073 "vnfd_id": vnfd_id,
4074 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004075 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004076 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004077 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004078 }
4079 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004080
tierno588547c2020-07-01 15:30:20 +00004081 # create VCA and configurationStatus in db
4082 db_dict = {
4083 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004084 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004085 }
4086 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004087
tierno588547c2020-07-01 15:30:20 +00004088 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4089
bravof922c4172020-11-24 21:21:43 -03004090 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4091 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4092 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4093
tierno588547c2020-07-01 15:30:20 +00004094 # Launch task
4095 task_n2vc = asyncio.ensure_future(
4096 self.instantiate_N2VC(
4097 logging_text=logging_text,
4098 vca_index=vca_index,
4099 nsi_id=nsi_id,
4100 db_nsr=db_nsr,
4101 db_vnfr=db_vnfr,
4102 vdu_id=vdu_id,
4103 kdu_name=kdu_name,
4104 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004105 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004106 deploy_params=deploy_params,
4107 config_descriptor=descriptor_config,
4108 base_folder=base_folder,
4109 nslcmop_id=nslcmop_id,
4110 stage=stage,
4111 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004112 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004113 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004114 )
quilesj7e13aeb2019-10-08 13:34:55 +02004115 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004116 self.lcm_tasks.register(
4117 "ns",
4118 nsr_id,
4119 nslcmop_id,
4120 "instantiate_N2VC-{}".format(vca_index),
4121 task_n2vc,
4122 )
4123 task_instantiation_info[
4124 task_n2vc
4125 ] = self.task_name_deploy_vca + " {}.{}".format(
4126 member_vnf_index or "", vdu_id or ""
4127 )
tiernobaa51102018-12-14 13:16:18 +00004128
calvinosanch9f9c6f22019-11-04 13:37:39 +01004129 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004130 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004131 for key, value in params.items():
4132 if str(value).startswith("!!yaml "):
4133 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004134 return params
4135
kuuse8b998e42019-07-30 15:22:16 +02004136 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004137 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004138 primitive_params = {}
4139 params = {
4140 "member_vnf_index": vnf_index,
4141 "primitive": primitive,
4142 "primitive_params": primitive_params,
4143 }
4144 desc_params = {}
4145 return self._map_primitive_params(seq, params, desc_params)
4146
kuuseac3a8882019-10-03 10:48:06 +02004147 # sub-operations
4148
tierno51183952020-04-03 15:48:18 +00004149 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004150 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4151 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004152 # b. Skip sub-operation
4153 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4154 return self.SUBOPERATION_STATUS_SKIP
4155 else:
tierno7c4e24c2020-05-13 08:41:35 +00004156 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004157 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004158 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004159 operationState = "PROCESSING"
4160 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004161 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004162 db_nslcmop, op_index, operationState, detailed_status
4163 )
kuuseac3a8882019-10-03 10:48:06 +02004164 # Return the sub-operation index
4165 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4166 # with arguments extracted from the sub-operation
4167 return op_index
4168
4169 # Find a sub-operation where all keys in a matching dictionary must match
4170 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4171 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004172 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004173 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004174 for i, op in enumerate(op_list):
4175 if all(op.get(k) == match[k] for k in match):
4176 return i
4177 return self.SUBOPERATION_STATUS_NOT_FOUND
4178
4179 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004180 def _update_suboperation_status(
4181 self, db_nslcmop, op_index, operationState, detailed_status
4182 ):
kuuseac3a8882019-10-03 10:48:06 +02004183 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004184 q_filter = {"_id": db_nslcmop["_id"]}
4185 update_dict = {
4186 "_admin.operations.{}.operationState".format(op_index): operationState,
4187 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4188 }
4189 self.db.set_one(
4190 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4191 )
kuuseac3a8882019-10-03 10:48:06 +02004192
4193 # Add sub-operation, return the index of the added sub-operation
4194 # Optionally, set operationState, detailed-status, and operationType
4195 # Status and type are currently set for 'scale' sub-operations:
4196 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4197 # 'detailed-status' : status message
4198 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4199 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004200 def _add_suboperation(
4201 self,
4202 db_nslcmop,
4203 vnf_index,
4204 vdu_id,
4205 vdu_count_index,
4206 vdu_name,
4207 primitive,
4208 mapped_primitive_params,
4209 operationState=None,
4210 detailed_status=None,
4211 operationType=None,
4212 RO_nsr_id=None,
4213 RO_scaling_info=None,
4214 ):
tiernoe876f672020-02-13 14:34:48 +00004215 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004216 return self.SUBOPERATION_STATUS_NOT_FOUND
4217 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004218 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4219 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004220 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004221 new_op = {
4222 "member_vnf_index": vnf_index,
4223 "vdu_id": vdu_id,
4224 "vdu_count_index": vdu_count_index,
4225 "primitive": primitive,
4226 "primitive_params": mapped_primitive_params,
4227 }
kuuseac3a8882019-10-03 10:48:06 +02004228 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004229 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004230 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004231 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004232 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004233 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004234 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004235 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004236 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004237 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004238 if not op_list:
4239 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004240 db_nslcmop_admin.update({"operations": [new_op]})
4241 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004242 else:
4243 # Existing operations, append operation to list
4244 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004245
garciadeblas5697b8b2021-03-24 09:17:02 +01004246 db_nslcmop_update = {"_admin.operations": op_list}
4247 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004248 op_index = len(op_list) - 1
4249 return op_index
4250
4251 # Helper methods for scale() sub-operations
4252
4253 # pre-scale/post-scale:
4254 # Check for 3 different cases:
4255 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4256 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004257 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004258 def _check_or_add_scale_suboperation(
4259 self,
4260 db_nslcmop,
4261 vnf_index,
4262 vnf_config_primitive,
4263 primitive_params,
4264 operationType,
4265 RO_nsr_id=None,
4266 RO_scaling_info=None,
4267 ):
kuuseac3a8882019-10-03 10:48:06 +02004268 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004269 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004270 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004271 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004272 "member_vnf_index": vnf_index,
4273 "RO_nsr_id": RO_nsr_id,
4274 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004275 }
4276 else:
4277 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004278 "member_vnf_index": vnf_index,
4279 "primitive": vnf_config_primitive,
4280 "primitive_params": primitive_params,
4281 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004282 }
4283 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004284 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004285 # a. New sub-operation
4286 # The sub-operation does not exist, add it.
4287 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4288 # The following parameters are set to None for all kind of scaling:
4289 vdu_id = None
4290 vdu_count_index = None
4291 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004292 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004293 vnf_config_primitive = None
4294 primitive_params = None
4295 else:
4296 RO_nsr_id = None
4297 RO_scaling_info = None
4298 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004299 operationState = "PROCESSING"
4300 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004301 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004302 self._add_suboperation(
4303 db_nslcmop,
4304 vnf_index,
4305 vdu_id,
4306 vdu_count_index,
4307 vdu_name,
4308 vnf_config_primitive,
4309 primitive_params,
4310 operationState,
4311 detailed_status,
4312 operationType,
4313 RO_nsr_id,
4314 RO_scaling_info,
4315 )
kuuseac3a8882019-10-03 10:48:06 +02004316 return self.SUBOPERATION_STATUS_NEW
4317 else:
4318 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4319 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004320 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004321
preethika.pdf7d8e02019-12-10 13:10:48 +00004322 # Function to return execution_environment id
4323
David Garciac1fe90a2021-03-31 19:12:02 +02004324 async def destroy_N2VC(
4325 self,
4326 logging_text,
4327 db_nslcmop,
4328 vca_deployed,
4329 config_descriptor,
4330 vca_index,
4331 destroy_ee=True,
4332 exec_primitives=True,
4333 scaling_in=False,
4334 vca_id: str = None,
4335 ):
tiernoe876f672020-02-13 14:34:48 +00004336 """
4337 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4338 :param logging_text:
4339 :param db_nslcmop:
4340 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4341 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4342 :param vca_index: index in the database _admin.deployed.VCA
4343 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004344 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4345 not executed properly
aktas13251562021-02-12 22:19:10 +03004346 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004347 :return: None or exception
4348 """
tiernoe876f672020-02-13 14:34:48 +00004349
tierno588547c2020-07-01 15:30:20 +00004350 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004351 logging_text
4352 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004353 vca_index, vca_deployed, config_descriptor, destroy_ee
4354 )
4355 )
4356
4357 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4358
4359 # execute terminate_primitives
4360 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004361 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004362 config_descriptor.get("terminate-config-primitive"),
4363 vca_deployed.get("ee_descriptor_id"),
4364 )
tierno588547c2020-07-01 15:30:20 +00004365 vdu_id = vca_deployed.get("vdu_id")
4366 vdu_count_index = vca_deployed.get("vdu_count_index")
4367 vdu_name = vca_deployed.get("vdu_name")
4368 vnf_index = vca_deployed.get("member-vnf-index")
4369 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004370 for seq in terminate_primitives:
4371 # For each sequence in list, get primitive and call _ns_execute_primitive()
4372 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004373 vnf_index, seq.get("name")
4374 )
tierno588547c2020-07-01 15:30:20 +00004375 self.logger.debug(logging_text + step)
4376 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004377 primitive = seq.get("name")
4378 mapped_primitive_params = self._get_terminate_primitive_params(
4379 seq, vnf_index
4380 )
tierno588547c2020-07-01 15:30:20 +00004381
4382 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004383 self._add_suboperation(
4384 db_nslcmop,
4385 vnf_index,
4386 vdu_id,
4387 vdu_count_index,
4388 vdu_name,
4389 primitive,
4390 mapped_primitive_params,
4391 )
tierno588547c2020-07-01 15:30:20 +00004392 # Sub-operations: Call _ns_execute_primitive() instead of action()
4393 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004394 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004395 vca_deployed["ee_id"],
4396 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004397 mapped_primitive_params,
4398 vca_type=vca_type,
4399 vca_id=vca_id,
4400 )
tierno588547c2020-07-01 15:30:20 +00004401 except LcmException:
4402 # this happens when VCA is not deployed. In this case it is not needed to terminate
4403 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004404 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004405 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004406 raise LcmException(
4407 "terminate_primitive {} for vnf_member_index={} fails with "
4408 "error {}".format(seq.get("name"), vnf_index, result_detail)
4409 )
tierno588547c2020-07-01 15:30:20 +00004410 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004411 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4412 vca_index
4413 )
4414 self.update_db_2(
4415 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4416 )
tiernoe876f672020-02-13 14:34:48 +00004417
bravof73bac502021-05-11 07:38:47 -04004418 # Delete Prometheus Jobs if any
4419 # This uses NSR_ID, so it will destroy any jobs under this index
4420 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004421
tiernoe876f672020-02-13 14:34:48 +00004422 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004423 await self.vca_map[vca_type].delete_execution_environment(
4424 vca_deployed["ee_id"],
4425 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004426 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004427 vca_id=vca_id,
4428 )
kuuse0ca67472019-05-13 15:59:27 +02004429
David Garciac1fe90a2021-03-31 19:12:02 +02004430 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004431 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004432 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004433 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004434 await self.n2vc.delete_namespace(
4435 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004436 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004437 vca_id=vca_id,
4438 )
tiernof59ad6c2020-04-08 12:50:52 +00004439 except N2VCNotFound: # already deleted. Skip
4440 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004441 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004442
tiernoe876f672020-02-13 14:34:48 +00004443 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004444 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004445 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004446 if not task_is_locked_by_me:
4447 return
4448
tierno59d22d22018-09-25 18:10:19 +02004449 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4450 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004451 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004452 db_nsr = None
4453 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004454 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004455 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004456 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004457 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004458 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004459 tasks_dict_info = {}
4460 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004461 stage = [
4462 "Stage 1/3: Preparing task.",
4463 "Waiting for previous operations to terminate.",
4464 "",
4465 ]
tiernoe876f672020-02-13 14:34:48 +00004466 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004467 try:
kuused124bfe2019-06-18 12:09:24 +02004468 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004469 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004470
tiernoe876f672020-02-13 14:34:48 +00004471 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4472 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4473 operation_params = db_nslcmop.get("operationParams") or {}
4474 if operation_params.get("timeout_ns_terminate"):
4475 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4476 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4477 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4478
4479 db_nsr_update["operational-status"] = "terminating"
4480 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004481 self._write_ns_status(
4482 nsr_id=nsr_id,
4483 ns_state="TERMINATING",
4484 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004485 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004486 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004487 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004488 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004489 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004490 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4491 return
tierno59d22d22018-09-25 18:10:19 +02004492
tiernoe876f672020-02-13 14:34:48 +00004493 stage[1] = "Getting vnf descriptors from db."
4494 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004495 db_vnfrs_dict = {
4496 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4497 }
tiernoe876f672020-02-13 14:34:48 +00004498 db_vnfds_from_id = {}
4499 db_vnfds_from_member_index = {}
4500 # Loop over VNFRs
4501 for vnfr in db_vnfrs_list:
4502 vnfd_id = vnfr["vnfd-id"]
4503 if vnfd_id not in db_vnfds_from_id:
4504 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4505 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004506 db_vnfds_from_member_index[
4507 vnfr["member-vnf-index-ref"]
4508 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004509
tiernoe876f672020-02-13 14:34:48 +00004510 # Destroy individual execution environments when there are terminating primitives.
4511 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004512 # TODO - check before calling _destroy_N2VC
4513 # if not operation_params.get("skip_terminate_primitives"):#
4514 # or not vca.get("needed_terminate"):
4515 stage[0] = "Stage 2/3 execute terminating primitives."
4516 self.logger.debug(logging_text + stage[0])
4517 stage[1] = "Looking execution environment that needs terminate."
4518 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004519
tierno588547c2020-07-01 15:30:20 +00004520 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004521 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004522 vca_member_vnf_index = vca.get("member-vnf-index")
4523 vca_id = self.get_vca_id(
4524 db_vnfrs_dict.get(vca_member_vnf_index)
4525 if vca_member_vnf_index
4526 else None,
4527 db_nsr,
4528 )
tierno588547c2020-07-01 15:30:20 +00004529 if not vca or not vca.get("ee_id"):
4530 continue
4531 if not vca.get("member-vnf-index"):
4532 # ns
4533 config_descriptor = db_nsr.get("ns-configuration")
4534 elif vca.get("vdu_id"):
4535 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004536 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004537 elif vca.get("kdu_name"):
4538 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004539 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004540 else:
bravofe5a31bc2021-02-17 19:09:12 -03004541 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004542 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004543 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004544 exec_terminate_primitives = not operation_params.get(
4545 "skip_terminate_primitives"
4546 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004547 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4548 # pending native charms
Luis Vegae11384e2023-10-10 22:36:33 +00004549 destroy_ee = True if vca_type in ("helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00004550 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4551 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004552 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004553 self.destroy_N2VC(
4554 logging_text,
4555 db_nslcmop,
4556 vca,
4557 config_descriptor,
4558 vca_index,
4559 destroy_ee,
4560 exec_terminate_primitives,
4561 vca_id=vca_id,
4562 )
4563 )
tierno588547c2020-07-01 15:30:20 +00004564 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004565
tierno588547c2020-07-01 15:30:20 +00004566 # wait for pending tasks of terminate primitives
4567 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004568 self.logger.debug(
4569 logging_text
4570 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4571 )
4572 error_list = await self._wait_for_tasks(
4573 logging_text,
4574 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004575 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004576 stage,
4577 nslcmop_id,
4578 )
tierno86e33612020-09-16 14:13:06 +00004579 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004580 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004581 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004582
tiernoe876f672020-02-13 14:34:48 +00004583 # remove All execution environments at once
4584 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004585
tierno49676be2020-04-07 16:34:35 +00004586 if nsr_deployed.get("VCA"):
4587 stage[1] = "Deleting all execution environments."
4588 self.logger.debug(logging_text + stage[1])
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004589 helm_vca_list = get_deployed_vca(db_nsr, {"type": "helm-v3"})
4590 if helm_vca_list:
Gabriel Cuba879483e2024-03-19 18:01:13 -05004591 # Delete Namespace and Certificates
4592 await self.vca_map["helm-v3"].delete_tls_certificate(
4593 namespace=db_nslcmop["nsInstanceId"],
4594 certificate_name=self.EE_TLS_NAME,
4595 )
4596 await self.vca_map["helm-v3"].delete_namespace(
4597 namespace=db_nslcmop["nsInstanceId"],
4598 )
Gabriel Cuba9cd53452024-03-21 17:14:05 -05004599 else:
4600 vca_id = self.get_vca_id({}, db_nsr)
4601 task_delete_ee = asyncio.ensure_future(
4602 asyncio.wait_for(
4603 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
4604 timeout=self.timeout.charm_delete,
4605 )
4606 )
4607 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
Gabriel Cuba1411a002022-10-07 11:38:23 -05004608
tiernoe876f672020-02-13 14:34:48 +00004609 # Delete from k8scluster
4610 stage[1] = "Deleting KDUs."
4611 self.logger.debug(logging_text + stage[1])
4612 # print(nsr_deployed)
4613 for kdu in get_iterable(nsr_deployed, "K8s"):
4614 if not kdu or not kdu.get("kdu-instance"):
4615 continue
4616 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004617 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004618 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4619 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004620 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004621 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4622 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004623 kdu_instance=kdu_instance,
4624 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004625 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004626 )
4627 )
tiernoe876f672020-02-13 14:34:48 +00004628 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004629 self.logger.error(
4630 logging_text
4631 + "Unknown k8s deployment type {}".format(
4632 kdu.get("k8scluster-type")
4633 )
4634 )
tiernoe876f672020-02-13 14:34:48 +00004635 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004636 tasks_dict_info[
4637 task_delete_kdu_instance
4638 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004639
4640 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004641 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004642 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004643 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004644 self._terminate_ng_ro(
4645 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4646 )
4647 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004648 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004649
tiernoe876f672020-02-13 14:34:48 +00004650 # rest of staff will be done at finally
4651
garciadeblas5697b8b2021-03-24 09:17:02 +01004652 except (
4653 ROclient.ROClientException,
4654 DbException,
4655 LcmException,
4656 N2VCException,
4657 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004658 self.logger.error(logging_text + "Exit Exception {}".format(e))
4659 exc = e
4660 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004661 self.logger.error(
4662 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4663 )
tiernoe876f672020-02-13 14:34:48 +00004664 exc = "Operation was cancelled"
4665 except Exception as e:
4666 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004667 self.logger.critical(
4668 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4669 exc_info=True,
4670 )
tiernoe876f672020-02-13 14:34:48 +00004671 finally:
4672 if exc:
4673 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004674 try:
tiernoe876f672020-02-13 14:34:48 +00004675 # wait for pending tasks
4676 if tasks_dict_info:
4677 stage[1] = "Waiting for terminate pending tasks."
4678 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004679 error_list += await self._wait_for_tasks(
4680 logging_text,
4681 tasks_dict_info,
4682 timeout_ns_terminate,
4683 stage,
4684 nslcmop_id,
4685 )
tiernoe876f672020-02-13 14:34:48 +00004686 stage[1] = stage[2] = ""
4687 except asyncio.CancelledError:
4688 error_list.append("Cancelled")
Gabriel Cubab6049d32023-10-30 13:44:49 -05004689 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
4690 await self._wait_for_tasks(
4691 logging_text,
4692 tasks_dict_info,
4693 timeout_ns_terminate,
4694 stage,
4695 nslcmop_id,
4696 )
tiernoe876f672020-02-13 14:34:48 +00004697 except Exception as exc:
4698 error_list.append(str(exc))
4699 # update status at database
4700 if error_list:
4701 error_detail = "; ".join(error_list)
4702 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004703 error_description_nslcmop = "{} Detail: {}".format(
4704 stage[0], error_detail
4705 )
4706 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4707 nslcmop_id, stage[0]
4708 )
tierno59d22d22018-09-25 18:10:19 +02004709
tierno59d22d22018-09-25 18:10:19 +02004710 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004711 db_nsr_update["detailed-status"] = (
4712 error_description_nsr + " Detail: " + error_detail
4713 )
tiernoe876f672020-02-13 14:34:48 +00004714 db_nslcmop_update["detailed-status"] = error_detail
4715 nslcmop_operation_state = "FAILED"
4716 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004717 else:
tiernoa2143262020-03-27 16:20:40 +00004718 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004719 error_description_nsr = error_description_nslcmop = None
4720 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004721 db_nsr_update["operational-status"] = "terminated"
4722 db_nsr_update["detailed-status"] = "Done"
4723 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4724 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004725 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004726
tiernoe876f672020-02-13 14:34:48 +00004727 if db_nsr:
4728 self._write_ns_status(
4729 nsr_id=nsr_id,
4730 ns_state=ns_state,
4731 current_operation="IDLE",
4732 current_operation_id=None,
4733 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004734 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004735 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004736 )
tiernoa17d4f42020-04-28 09:59:23 +00004737 self._write_op_status(
4738 op_id=nslcmop_id,
4739 stage="",
4740 error_message=error_description_nslcmop,
4741 operation_state=nslcmop_operation_state,
4742 other_update=db_nslcmop_update,
4743 )
Rahul Kumar54671c52024-05-09 15:34:01 +05304744 if nslcmop_operation_state == "COMPLETED":
4745 self.db.del_list("prometheus_jobs", {"nsr_id": nsr_id})
lloretgalleg6d488782020-07-22 10:13:46 +00004746 if ns_state == "NOT_INSTANTIATED":
4747 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004748 self.db.set_list(
4749 "vnfrs",
4750 {"nsr-id-ref": nsr_id},
4751 {"_admin.nsState": "NOT_INSTANTIATED"},
4752 )
lloretgalleg6d488782020-07-22 10:13:46 +00004753 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004754 self.logger.warn(
4755 logging_text
4756 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4757 nsr_id, e
4758 )
4759 )
tiernoa17d4f42020-04-28 09:59:23 +00004760 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004761 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004762 if nslcmop_operation_state:
4763 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004764 await self.msg.aiowrite(
4765 "ns",
4766 "terminated",
4767 {
4768 "nsr_id": nsr_id,
4769 "nslcmop_id": nslcmop_id,
4770 "operationState": nslcmop_operation_state,
4771 "autoremove": autoremove,
4772 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004773 )
tierno59d22d22018-09-25 18:10:19 +02004774 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004775 self.logger.error(
4776 logging_text + "kafka_write notification Exception {}".format(e)
4777 )
aguilard1ae3c562023-02-16 17:24:35 +00004778 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4779 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004780
tierno59d22d22018-09-25 18:10:19 +02004781 self.logger.debug(logging_text + "Exit")
4782 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4783
garciadeblas5697b8b2021-03-24 09:17:02 +01004784 async def _wait_for_tasks(
4785 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4786 ):
tiernoe876f672020-02-13 14:34:48 +00004787 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004788 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004789 error_list = []
4790 pending_tasks = list(created_tasks_info.keys())
4791 num_tasks = len(pending_tasks)
4792 num_done = 0
4793 stage[1] = "{}/{}.".format(num_done, num_tasks)
4794 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004795 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004796 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004797 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004798 done, pending_tasks = await asyncio.wait(
4799 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4800 )
tiernoe876f672020-02-13 14:34:48 +00004801 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004802 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004803 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004804 new_error = created_tasks_info[task] + ": Timeout"
4805 error_detail_list.append(new_error)
4806 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004807 break
4808 for task in done:
4809 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004810 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004811 else:
4812 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004813 if exc:
4814 if isinstance(exc, asyncio.TimeoutError):
4815 exc = "Timeout"
4816 new_error = created_tasks_info[task] + ": {}".format(exc)
4817 error_list.append(created_tasks_info[task])
4818 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004819 if isinstance(
4820 exc,
4821 (
4822 str,
4823 DbException,
4824 N2VCException,
4825 ROclient.ROClientException,
4826 LcmException,
4827 K8sException,
4828 NgRoException,
4829 ),
4830 ):
tierno067e04a2020-03-31 12:53:13 +00004831 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004832 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004833 exc_traceback = "".join(
4834 traceback.format_exception(None, exc, exc.__traceback__)
4835 )
4836 self.logger.error(
4837 logging_text
4838 + created_tasks_info[task]
4839 + " "
4840 + exc_traceback
4841 )
tierno067e04a2020-03-31 12:53:13 +00004842 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004843 self.logger.debug(
4844 logging_text + created_tasks_info[task] + ": Done"
4845 )
tiernoe876f672020-02-13 14:34:48 +00004846 stage[1] = "{}/{}.".format(num_done, num_tasks)
4847 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004848 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004849 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004850 self.update_db_2(
4851 "nsrs",
4852 nsr_id,
4853 {
4854 "errorDescription": "Error at: " + ", ".join(error_list),
4855 "errorDetail": ". ".join(error_detail_list),
4856 },
4857 )
tiernoe876f672020-02-13 14:34:48 +00004858 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004859 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004860
Gabriel Cubab6049d32023-10-30 13:44:49 -05004861 async def _cancel_pending_tasks(self, logging_text, created_tasks_info):
4862 for task, name in created_tasks_info.items():
4863 self.logger.debug(logging_text + "Cancelling task: " + name)
4864 task.cancel()
4865
tiernoda1ff8c2020-10-22 14:12:46 +00004866 @staticmethod
4867 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004868 """
4869 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4870 The default-value is used. If it is between < > it look for a value at instantiation_params
4871 :param primitive_desc: portion of VNFD/NSD that describes primitive
4872 :param params: Params provided by user
4873 :param instantiation_params: Instantiation params provided by user
4874 :return: a dictionary with the calculated params
4875 """
4876 calculated_params = {}
4877 for parameter in primitive_desc.get("parameter", ()):
4878 param_name = parameter["name"]
4879 if param_name in params:
4880 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004881 elif "default-value" in parameter or "value" in parameter:
4882 if "value" in parameter:
4883 calculated_params[param_name] = parameter["value"]
4884 else:
4885 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004886 if (
4887 isinstance(calculated_params[param_name], str)
4888 and calculated_params[param_name].startswith("<")
4889 and calculated_params[param_name].endswith(">")
4890 ):
tierno98ad6ea2019-05-30 17:16:28 +00004891 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004892 calculated_params[param_name] = instantiation_params[
4893 calculated_params[param_name][1:-1]
4894 ]
tiernoda964822019-01-14 15:53:47 +00004895 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004896 raise LcmException(
4897 "Parameter {} needed to execute primitive {} not provided".format(
4898 calculated_params[param_name], primitive_desc["name"]
4899 )
4900 )
tiernoda964822019-01-14 15:53:47 +00004901 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004902 raise LcmException(
4903 "Parameter {} needed to execute primitive {} not provided".format(
4904 param_name, primitive_desc["name"]
4905 )
4906 )
tierno59d22d22018-09-25 18:10:19 +02004907
tiernoda964822019-01-14 15:53:47 +00004908 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004909 calculated_params[param_name] = yaml.safe_dump(
4910 calculated_params[param_name], default_flow_style=True, width=256
4911 )
4912 elif isinstance(calculated_params[param_name], str) and calculated_params[
4913 param_name
4914 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004915 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004916 if parameter.get("data-type") == "INTEGER":
4917 try:
4918 calculated_params[param_name] = int(calculated_params[param_name])
4919 except ValueError: # error converting string to int
4920 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004921 "Parameter {} of primitive {} must be integer".format(
4922 param_name, primitive_desc["name"]
4923 )
4924 )
tiernofa40e692020-10-14 14:59:36 +00004925 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004926 calculated_params[param_name] = not (
4927 (str(calculated_params[param_name])).lower() == "false"
4928 )
tiernoc3f2a822019-11-05 13:45:04 +00004929
4930 # add always ns_config_info if primitive name is config
4931 if primitive_desc["name"] == "config":
4932 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004933 calculated_params["ns_config_info"] = instantiation_params[
4934 "ns_config_info"
4935 ]
tiernoda964822019-01-14 15:53:47 +00004936 return calculated_params
4937
garciadeblas5697b8b2021-03-24 09:17:02 +01004938 def _look_for_deployed_vca(
4939 self,
4940 deployed_vca,
4941 member_vnf_index,
4942 vdu_id,
4943 vdu_count_index,
4944 kdu_name=None,
4945 ee_descriptor_id=None,
4946 ):
tiernoe876f672020-02-13 14:34:48 +00004947 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4948 for vca in deployed_vca:
4949 if not vca:
4950 continue
4951 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4952 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004953 if (
4954 vdu_count_index is not None
4955 and vdu_count_index != vca["vdu_count_index"]
4956 ):
tiernoe876f672020-02-13 14:34:48 +00004957 continue
4958 if kdu_name and kdu_name != vca["kdu_name"]:
4959 continue
tiernoa278b842020-07-08 15:33:55 +00004960 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4961 continue
tiernoe876f672020-02-13 14:34:48 +00004962 break
4963 else:
4964 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004965 raise LcmException(
4966 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4967 " is not deployed".format(
4968 member_vnf_index,
4969 vdu_id,
4970 vdu_count_index,
4971 kdu_name,
4972 ee_descriptor_id,
4973 )
4974 )
tiernoe876f672020-02-13 14:34:48 +00004975 # get ee_id
4976 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004977 vca_type = vca.get(
4978 "type", "lxc_proxy_charm"
4979 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004980 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004981 raise LcmException(
4982 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4983 "execution environment".format(
4984 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4985 )
4986 )
tierno588547c2020-07-01 15:30:20 +00004987 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004988
David Garciac1fe90a2021-03-31 19:12:02 +02004989 async def _ns_execute_primitive(
4990 self,
4991 ee_id,
4992 primitive,
4993 primitive_params,
4994 retries=0,
4995 retries_interval=30,
4996 timeout=None,
4997 vca_type=None,
4998 db_dict=None,
4999 vca_id: str = None,
5000 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005001 try:
tierno98ad6ea2019-05-30 17:16:28 +00005002 if primitive == "config":
5003 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005004
tierno588547c2020-07-01 15:30:20 +00005005 vca_type = vca_type or "lxc_proxy_charm"
5006
quilesj7e13aeb2019-10-08 13:34:55 +02005007 while retries >= 0:
5008 try:
tierno067e04a2020-03-31 12:53:13 +00005009 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005010 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005011 ee_id=ee_id,
5012 primitive_name=primitive,
5013 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005014 progress_timeout=self.timeout.progress_primitive,
5015 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005016 db_dict=db_dict,
5017 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005018 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005019 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005020 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005021 )
quilesj7e13aeb2019-10-08 13:34:55 +02005022 # execution was OK
5023 break
tierno067e04a2020-03-31 12:53:13 +00005024 except asyncio.CancelledError:
5025 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005026 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005027 retries -= 1
5028 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005029 self.logger.debug(
5030 "Error executing action {} on {} -> {}".format(
5031 primitive, ee_id, e
5032 )
5033 )
quilesj7e13aeb2019-10-08 13:34:55 +02005034 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005035 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005036 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005037 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005038 e = N2VCException(
5039 message="Timed out waiting for action to complete"
5040 )
5041 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005042
garciadeblas5697b8b2021-03-24 09:17:02 +01005043 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005044
tierno067e04a2020-03-31 12:53:13 +00005045 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005046 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005047 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005048 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005049
ksaikiranr3fde2c72021-03-15 10:39:06 +05305050 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5051 """
5052 Updating the vca_status with latest juju information in nsrs record
5053 :param: nsr_id: Id of the nsr
5054 :param: nslcmop_id: Id of the nslcmop
5055 :return: None
5056 """
5057
5058 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5059 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005060 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005061 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005062 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5063 cluster_uuid, kdu_instance, cluster_type = (
5064 k8s["k8scluster-uuid"],
5065 k8s["kdu-instance"],
5066 k8s["k8scluster-type"],
5067 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005068 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005069 cluster_uuid=cluster_uuid,
5070 kdu_instance=kdu_instance,
5071 filter={"_id": nsr_id},
5072 vca_id=vca_id,
5073 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005074 )
3697083243632024-06-07 05:44:08 +00005075 if db_nsr["_admin"]["deployed"]["VCA"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01005076 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305077 table, filter = "nsrs", {"_id": nsr_id}
5078 path = "_admin.deployed.VCA.{}.".format(vca_index)
5079 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305080
5081 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5082 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5083
tierno59d22d22018-09-25 18:10:19 +02005084 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005085 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005086 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005087 if not task_is_locked_by_me:
5088 return
5089
tierno59d22d22018-09-25 18:10:19 +02005090 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5091 self.logger.debug(logging_text + "Enter")
5092 # get all needed from database
5093 db_nsr = None
5094 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005095 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005096 db_nslcmop_update = {}
5097 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005098 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005099 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005100 step = ""
tierno59d22d22018-09-25 18:10:19 +02005101 try:
kuused124bfe2019-06-18 12:09:24 +02005102 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005103 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005104 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005105
quilesj4cda56b2019-12-05 10:02:20 +00005106 self._write_ns_status(
5107 nsr_id=nsr_id,
5108 ns_state=None,
5109 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005110 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005111 )
5112
tierno59d22d22018-09-25 18:10:19 +02005113 step = "Getting information from database"
5114 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5115 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005116 if db_nslcmop["operationParams"].get("primitive_params"):
5117 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5118 db_nslcmop["operationParams"]["primitive_params"]
5119 )
tiernoda964822019-01-14 15:53:47 +00005120
tiernoe4f7e6c2018-11-27 14:55:30 +00005121 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005122 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005123 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005124 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005125 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005126 primitive = db_nslcmop["operationParams"]["primitive"]
5127 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005128 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005129 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005130 )
tierno59d22d22018-09-25 18:10:19 +02005131
tierno1b633412019-02-25 16:48:23 +00005132 if vnf_index:
5133 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005134 db_vnfr = self.db.get_one(
5135 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5136 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005137 if db_vnfr.get("kdur"):
5138 kdur_list = []
5139 for kdur in db_vnfr["kdur"]:
5140 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005141 kdur["additionalParams"] = json.loads(
5142 kdur["additionalParams"]
5143 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005144 kdur_list.append(kdur)
5145 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005146 step = "Getting vnfd from database"
5147 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005148
5149 # Sync filesystem before running a primitive
5150 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005151 else:
tierno067e04a2020-03-31 12:53:13 +00005152 step = "Getting nsd from database"
5153 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005154
David Garciac1fe90a2021-03-31 19:12:02 +02005155 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005156 # for backward compatibility
5157 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5158 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5159 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5160 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5161
tiernoda964822019-01-14 15:53:47 +00005162 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005163 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005164 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005165 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005166 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005167 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005168 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005169 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005170 else:
tiernoa278b842020-07-08 15:33:55 +00005171 descriptor_configuration = db_nsd.get("ns-configuration")
5172
garciadeblas5697b8b2021-03-24 09:17:02 +01005173 if descriptor_configuration and descriptor_configuration.get(
5174 "config-primitive"
5175 ):
tiernoa278b842020-07-08 15:33:55 +00005176 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005177 if config_primitive["name"] == primitive:
5178 config_primitive_desc = config_primitive
5179 break
tiernoda964822019-01-14 15:53:47 +00005180
garciadeblas6bed6b32020-07-20 11:05:42 +00005181 if not config_primitive_desc:
5182 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005183 raise LcmException(
5184 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5185 primitive
5186 )
5187 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005188 primitive_name = primitive
5189 ee_descriptor_id = None
5190 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005191 primitive_name = config_primitive_desc.get(
5192 "execution-environment-primitive", primitive
5193 )
5194 ee_descriptor_id = config_primitive_desc.get(
5195 "execution-environment-ref"
5196 )
tierno1b633412019-02-25 16:48:23 +00005197
tierno1b633412019-02-25 16:48:23 +00005198 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005199 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005200 vdur = next(
5201 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5202 )
bravof922c4172020-11-24 21:21:43 -03005203 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005204 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005205 kdur = next(
5206 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5207 )
bravof922c4172020-11-24 21:21:43 -03005208 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005209 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005210 desc_params = parse_yaml_strings(
5211 db_vnfr.get("additionalParamsForVnf")
5212 )
tierno1b633412019-02-25 16:48:23 +00005213 else:
bravof922c4172020-11-24 21:21:43 -03005214 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005215 if kdu_name and get_configuration(db_vnfd, kdu_name):
5216 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005217 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005218 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005219 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005220 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005221 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005222 kdu = find_in_list(
5223 nsr_deployed["K8s"],
5224 lambda kdu: kdu_name == kdu["kdu-name"]
5225 and kdu["member-vnf-index"] == vnf_index,
5226 )
5227 kdu_action = (
5228 True
5229 if primitive_name in actions
Luis Vegae11384e2023-10-10 22:36:33 +00005230 and kdu["k8scluster-type"] != "helm-chart-v3"
David Garciaae230232022-05-10 14:07:12 +02005231 else False
5232 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005233
tiernoda964822019-01-14 15:53:47 +00005234 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005235 if kdu_name and (
5236 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5237 ):
tierno067e04a2020-03-31 12:53:13 +00005238 # TODO Check if we will need something at vnf level
5239 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005240 if (
5241 kdu_name == kdu["kdu-name"]
5242 and kdu["member-vnf-index"] == vnf_index
5243 ):
tierno067e04a2020-03-31 12:53:13 +00005244 break
5245 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005246 raise LcmException(
5247 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5248 )
quilesj7e13aeb2019-10-08 13:34:55 +02005249
tierno067e04a2020-03-31 12:53:13 +00005250 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005251 msg = "unknown k8scluster-type '{}'".format(
5252 kdu.get("k8scluster-type")
5253 )
tierno067e04a2020-03-31 12:53:13 +00005254 raise LcmException(msg)
5255
garciadeblas5697b8b2021-03-24 09:17:02 +01005256 db_dict = {
5257 "collection": "nsrs",
5258 "filter": {"_id": nsr_id},
5259 "path": "_admin.deployed.K8s.{}".format(index),
5260 }
5261 self.logger.debug(
5262 logging_text
5263 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5264 )
tiernoa278b842020-07-08 15:33:55 +00005265 step = "Executing kdu {}".format(primitive_name)
garciadeblas8eb84d52024-07-19 12:08:07 +02005266 if primitive_name == "upgrade" and primitive_params:
5267 if primitive_params.get("kdu_model"):
5268 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005269 else:
5270 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005271 if kdu_model.count("/") < 2: # helm chart is not embedded
5272 parts = kdu_model.split(sep=":")
5273 if len(parts) == 2:
5274 kdu_model = parts[0]
garciadeblas8eb84d52024-07-19 12:08:07 +02005275 if primitive_params.get("kdu_atomic_upgrade"):
5276 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005277 "kdu_atomic_upgrade"
5278 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005279 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005280 else:
5281 atomic_upgrade = True
garciadeblasb891d382024-02-08 14:11:51 +01005282 # Type of upgrade: reset, reuse, reset_then_reuse
5283 reset_values = False
5284 reuse_values = False
5285 reset_then_reuse_values = False
5286 # If no option is specified, default behaviour is reuse_values
5287 # Otherwise, options will be parsed and used
5288 if (
garciadeblas8eb84d52024-07-19 12:08:07 +02005289 ("kdu_reset_values" not in primitive_params)
5290 and ("kdu_reuse_values" not in primitive_params)
5291 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasb891d382024-02-08 14:11:51 +01005292 ):
5293 reuse_values = True
5294 else:
garciadeblas8eb84d52024-07-19 12:08:07 +02005295 if primitive_params.get("kdu_reset_values"):
5296 reset_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005297 "kdu_reset_values"
5298 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005299 if primitive_params.get("kdu_reuse_values"):
5300 reuse_values = primitive_params.pop(
garciadeblasb891d382024-02-08 14:11:51 +01005301 "kdu_reuse_values"
5302 ).lower() in ("yes", "true", "1")
garciadeblas8eb84d52024-07-19 12:08:07 +02005303 if primitive_params.get("kdu_reset_then_reuse_values"):
5304 reset_then_reuse_values = primitive_params.get(
garciadeblasb891d382024-02-08 14:11:51 +01005305 "kdu_reset_then_reuse_values"
5306 ).lower() in ("yes", "true", "1")
5307 # Two true options are not possible
5308 if (
5309 sum([reset_values, reuse_values, reset_then_reuse_values])
5310 >= 2
5311 ):
5312 raise LcmException(
5313 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5314 )
garciadeblas8eb84d52024-07-19 12:08:07 +02005315 # kdur and desc_params already set from before
5316 if reset_values:
5317 desc_params = primitive_params
5318 else:
5319 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005320 detailed_status = await asyncio.wait_for(
5321 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5322 cluster_uuid=kdu.get("k8scluster-uuid"),
5323 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005324 atomic=atomic_upgrade,
garciadeblasb891d382024-02-08 14:11:51 +01005325 reset_values=reset_values,
5326 reuse_values=reuse_values,
5327 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005328 kdu_model=kdu_model,
5329 params=desc_params,
5330 db_dict=db_dict,
5331 timeout=timeout_ns_action,
5332 ),
5333 timeout=timeout_ns_action + 10,
5334 )
5335 self.logger.debug(
5336 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5337 )
tiernoa278b842020-07-08 15:33:55 +00005338 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005339 detailed_status = await asyncio.wait_for(
5340 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5341 cluster_uuid=kdu.get("k8scluster-uuid"),
5342 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005343 db_dict=db_dict,
5344 ),
5345 timeout=timeout_ns_action,
5346 )
tiernoa278b842020-07-08 15:33:55 +00005347 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005348 detailed_status = await asyncio.wait_for(
5349 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5350 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005351 kdu_instance=kdu.get("kdu-instance"),
5352 vca_id=vca_id,
5353 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005354 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005355 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005356 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005357 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5358 kdu["kdu-name"], nsr_id
5359 )
5360 params = self._map_primitive_params(
5361 config_primitive_desc, primitive_params, desc_params
5362 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005363
5364 detailed_status = await asyncio.wait_for(
5365 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5366 cluster_uuid=kdu.get("k8scluster-uuid"),
5367 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005368 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005369 params=params,
5370 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005371 timeout=timeout_ns_action,
5372 vca_id=vca_id,
5373 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005374 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005375 )
tierno067e04a2020-03-31 12:53:13 +00005376
5377 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005378 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005379 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005380 detailed_status = ""
5381 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005382 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005383 ee_id, vca_type = self._look_for_deployed_vca(
5384 nsr_deployed["VCA"],
5385 member_vnf_index=vnf_index,
5386 vdu_id=vdu_id,
5387 vdu_count_index=vdu_count_index,
5388 ee_descriptor_id=ee_descriptor_id,
5389 )
5390 for vca_index, vca_deployed in enumerate(
5391 db_nsr["_admin"]["deployed"]["VCA"]
5392 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305393 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005394 db_dict = {
5395 "collection": "nsrs",
5396 "filter": {"_id": nsr_id},
5397 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5398 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305399 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005400 (
5401 nslcmop_operation_state,
5402 detailed_status,
5403 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005404 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005405 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005406 primitive_params=self._map_primitive_params(
5407 config_primitive_desc, primitive_params, desc_params
5408 ),
tierno588547c2020-07-01 15:30:20 +00005409 timeout=timeout_ns_action,
5410 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005411 db_dict=db_dict,
5412 vca_id=vca_id,
5413 )
tierno067e04a2020-03-31 12:53:13 +00005414
5415 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005416 error_description_nslcmop = (
5417 detailed_status if nslcmop_operation_state == "FAILED" else ""
5418 )
5419 self.logger.debug(
5420 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005421 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005422 nslcmop_operation_state, detailed_status
5423 )
5424 )
tierno59d22d22018-09-25 18:10:19 +02005425 return # database update is called inside finally
5426
tiernof59ad6c2020-04-08 12:50:52 +00005427 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005428 self.logger.error(logging_text + "Exit Exception {}".format(e))
5429 exc = e
5430 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005431 self.logger.error(
5432 logging_text + "Cancelled Exception while '{}'".format(step)
5433 )
tierno59d22d22018-09-25 18:10:19 +02005434 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005435 except asyncio.TimeoutError:
5436 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5437 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005438 except Exception as e:
5439 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005440 self.logger.critical(
5441 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5442 exc_info=True,
5443 )
tierno59d22d22018-09-25 18:10:19 +02005444 finally:
tierno067e04a2020-03-31 12:53:13 +00005445 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005446 db_nslcmop_update[
5447 "detailed-status"
5448 ] = (
5449 detailed_status
5450 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005451 nslcmop_operation_state = "FAILED"
5452 if db_nsr:
5453 self._write_ns_status(
5454 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005455 ns_state=db_nsr[
5456 "nsState"
5457 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005458 current_operation="IDLE",
5459 current_operation_id=None,
5460 # error_description=error_description_nsr,
5461 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005462 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005463 )
5464
garciadeblas5697b8b2021-03-24 09:17:02 +01005465 self._write_op_status(
5466 op_id=nslcmop_id,
5467 stage="",
5468 error_message=error_description_nslcmop,
5469 operation_state=nslcmop_operation_state,
5470 other_update=db_nslcmop_update,
5471 )
tierno067e04a2020-03-31 12:53:13 +00005472
tierno59d22d22018-09-25 18:10:19 +02005473 if nslcmop_operation_state:
5474 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005475 await self.msg.aiowrite(
5476 "ns",
5477 "actioned",
5478 {
5479 "nsr_id": nsr_id,
5480 "nslcmop_id": nslcmop_id,
5481 "operationState": nslcmop_operation_state,
5482 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005483 )
tierno59d22d22018-09-25 18:10:19 +02005484 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005485 self.logger.error(
5486 logging_text + "kafka_write notification Exception {}".format(e)
5487 )
tierno59d22d22018-09-25 18:10:19 +02005488 self.logger.debug(logging_text + "Exit")
5489 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005490 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005491
elumalaica7ece02022-04-12 12:47:32 +05305492 async def terminate_vdus(
5493 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5494 ):
5495 """This method terminates VDUs
5496
5497 Args:
5498 db_vnfr: VNF instance record
5499 member_vnf_index: VNF index to identify the VDUs to be removed
5500 db_nsr: NS instance record
5501 update_db_nslcmops: Nslcmop update record
5502 """
5503 vca_scaling_info = []
5504 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5505 scaling_info["scaling_direction"] = "IN"
5506 scaling_info["vdu-delete"] = {}
5507 scaling_info["kdu-delete"] = {}
5508 db_vdur = db_vnfr.get("vdur")
5509 vdur_list = copy(db_vdur)
5510 count_index = 0
5511 for index, vdu in enumerate(vdur_list):
5512 vca_scaling_info.append(
5513 {
5514 "osm_vdu_id": vdu["vdu-id-ref"],
5515 "member-vnf-index": member_vnf_index,
5516 "type": "delete",
5517 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005518 }
5519 )
elumalaica7ece02022-04-12 12:47:32 +05305520 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5521 scaling_info["vdu"].append(
5522 {
5523 "name": vdu.get("name") or vdu.get("vdu-name"),
5524 "vdu_id": vdu["vdu-id-ref"],
5525 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005526 }
5527 )
elumalaica7ece02022-04-12 12:47:32 +05305528 for interface in vdu["interfaces"]:
5529 scaling_info["vdu"][index]["interface"].append(
5530 {
5531 "name": interface["name"],
5532 "ip_address": interface["ip-address"],
5533 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005534 }
5535 )
elumalaica7ece02022-04-12 12:47:32 +05305536 self.logger.info("NS update scaling info{}".format(scaling_info))
5537 stage[2] = "Terminating VDUs"
5538 if scaling_info.get("vdu-delete"):
5539 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005540 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305541 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005542 logging_text,
5543 db_nsr,
5544 update_db_nslcmops,
5545 db_vnfr,
5546 scaling_info,
5547 stage,
elumalaica7ece02022-04-12 12:47:32 +05305548 )
5549
preethika.p28b0bf82022-09-23 07:36:28 +00005550 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305551 """This method is to Remove VNF instances from NS.
5552
5553 Args:
5554 nsr_id: NS instance id
5555 nslcmop_id: nslcmop id of update
5556 vnf_instance_id: id of the VNF instance to be removed
5557
5558 Returns:
5559 result: (str, str) COMPLETED/FAILED, details
5560 """
5561 try:
5562 db_nsr_update = {}
5563 logging_text = "Task ns={} update ".format(nsr_id)
5564 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5565 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5566 if check_vnfr_count > 1:
5567 stage = ["", "", ""]
5568 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005569 self.logger.debug(
5570 step + " after having waited for previous tasks to be completed"
5571 )
elumalaica7ece02022-04-12 12:47:32 +05305572 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5573 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5574 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5575 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5576 """ db_vnfr = self.db.get_one(
5577 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5578
5579 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005580 await self.terminate_vdus(
5581 db_vnfr,
5582 member_vnf_index,
5583 db_nsr,
5584 update_db_nslcmops,
5585 stage,
5586 logging_text,
5587 )
elumalaica7ece02022-04-12 12:47:32 +05305588
5589 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5590 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005591 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5592 "constituent-vnfr-ref"
5593 )
elumalaica7ece02022-04-12 12:47:32 +05305594 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5595 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5596 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5597 return "COMPLETED", "Done"
5598 else:
5599 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005600 raise LcmException(
5601 "{} Cannot terminate the last VNF in this NS.".format(
5602 vnf_instance_id
5603 )
5604 )
elumalaica7ece02022-04-12 12:47:32 +05305605 except (LcmException, asyncio.CancelledError):
5606 raise
5607 except Exception as e:
5608 self.logger.debug("Error removing VNF {}".format(e))
5609 return "FAILED", "Error removing VNF {}".format(e)
5610
elumalaib9e357c2022-04-27 09:58:38 +05305611 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005612 self,
5613 nsr_id,
5614 nslcmop_id,
5615 db_vnfd,
5616 db_vnfr,
5617 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305618 ):
5619 """This method updates and redeploys VNF instances
5620
5621 Args:
5622 nsr_id: NS instance id
5623 nslcmop_id: nslcmop id
5624 db_vnfd: VNF descriptor
5625 db_vnfr: VNF instance record
5626 db_nsr: NS instance record
5627
5628 Returns:
5629 result: (str, str) COMPLETED/FAILED, details
5630 """
5631 try:
5632 count_index = 0
5633 stage = ["", "", ""]
5634 logging_text = "Task ns={} update ".format(nsr_id)
5635 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5636 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5637
5638 # Terminate old VNF resources
5639 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005640 await self.terminate_vdus(
5641 db_vnfr,
5642 member_vnf_index,
5643 db_nsr,
5644 update_db_nslcmops,
5645 stage,
5646 logging_text,
5647 )
elumalaib9e357c2022-04-27 09:58:38 +05305648
5649 # old_vnfd_id = db_vnfr["vnfd-id"]
5650 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5651 new_db_vnfd = db_vnfd
5652 # new_vnfd_ref = new_db_vnfd["id"]
5653 # new_vnfd_id = vnfd_id
5654
5655 # Create VDUR
5656 new_vnfr_cp = []
5657 for cp in new_db_vnfd.get("ext-cpd", ()):
5658 vnf_cp = {
5659 "name": cp.get("id"),
5660 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5661 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5662 "id": cp.get("id"),
5663 }
5664 new_vnfr_cp.append(vnf_cp)
5665 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5666 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5667 # 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 +00005668 new_vnfr_update = {
5669 "revision": latest_vnfd_revision,
5670 "connection-point": new_vnfr_cp,
5671 "vdur": new_vdur,
5672 "ip-address": "",
5673 }
elumalaib9e357c2022-04-27 09:58:38 +05305674 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5675 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005676 "vnfrs",
5677 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305678 )
5679
5680 # Instantiate new VNF resources
5681 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5682 vca_scaling_info = []
5683 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5684 scaling_info["scaling_direction"] = "OUT"
5685 scaling_info["vdu-create"] = {}
5686 scaling_info["kdu-create"] = {}
5687 vdud_instantiate_list = db_vnfd["vdu"]
5688 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005689 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305690 if cloud_init_text:
5691 additional_params = (
5692 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5693 or {}
5694 )
5695 cloud_init_list = []
5696 if cloud_init_text:
5697 # TODO Information of its own ip is not available because db_vnfr is not updated.
5698 additional_params["OSM"] = get_osm_params(
5699 updated_db_vnfr, vdud["id"], 1
5700 )
5701 cloud_init_list.append(
5702 self._parse_cloud_init(
5703 cloud_init_text,
5704 additional_params,
5705 db_vnfd["id"],
5706 vdud["id"],
5707 )
5708 )
5709 vca_scaling_info.append(
5710 {
5711 "osm_vdu_id": vdud["id"],
5712 "member-vnf-index": member_vnf_index,
5713 "type": "create",
5714 "vdu_index": count_index,
5715 }
5716 )
5717 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005718 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305719 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005720 "New Resources to be deployed: {}".format(scaling_info)
5721 )
elumalaib9e357c2022-04-27 09:58:38 +05305722 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005723 logging_text,
5724 db_nsr,
5725 update_db_nslcmops,
5726 updated_db_vnfr,
5727 scaling_info,
5728 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305729 )
5730 return "COMPLETED", "Done"
5731 except (LcmException, asyncio.CancelledError):
5732 raise
5733 except Exception as e:
5734 self.logger.debug("Error updating VNF {}".format(e))
5735 return "FAILED", "Error updating VNF {}".format(e)
5736
aticigdffa6212022-04-12 15:27:53 +03005737 async def _ns_charm_upgrade(
5738 self,
5739 ee_id,
5740 charm_id,
5741 charm_type,
5742 path,
5743 timeout: float = None,
5744 ) -> (str, str):
5745 """This method upgrade charms in VNF instances
5746
5747 Args:
5748 ee_id: Execution environment id
5749 path: Local path to the charm
5750 charm_id: charm-id
5751 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5752 timeout: (Float) Timeout for the ns update operation
5753
5754 Returns:
5755 result: (str, str) COMPLETED/FAILED, details
5756 """
5757 try:
5758 charm_type = charm_type or "lxc_proxy_charm"
5759 output = await self.vca_map[charm_type].upgrade_charm(
5760 ee_id=ee_id,
5761 path=path,
5762 charm_id=charm_id,
5763 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005764 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005765 )
5766
5767 if output:
5768 return "COMPLETED", output
5769
5770 except (LcmException, asyncio.CancelledError):
5771 raise
5772
5773 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005774 self.logger.debug("Error upgrading charm {}".format(path))
5775
5776 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5777
5778 async def update(self, nsr_id, nslcmop_id):
5779 """Update NS according to different update types
5780
5781 This method performs upgrade of VNF instances then updates the revision
5782 number in VNF record
5783
5784 Args:
5785 nsr_id: Network service will be updated
5786 nslcmop_id: ns lcm operation id
5787
5788 Returns:
5789 It may raise DbException, LcmException, N2VCException, K8sException
5790
5791 """
5792 # Try to lock HA task here
5793 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5794 if not task_is_locked_by_me:
5795 return
5796
5797 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5798 self.logger.debug(logging_text + "Enter")
5799
5800 # Set the required variables to be filled up later
5801 db_nsr = None
5802 db_nslcmop_update = {}
5803 vnfr_update = {}
5804 nslcmop_operation_state = None
5805 db_nsr_update = {}
5806 error_description_nslcmop = ""
5807 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305808 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005809 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005810 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005811
5812 try:
5813 # wait for any previous tasks in process
5814 step = "Waiting for previous operations to terminate"
5815 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5816 self._write_ns_status(
5817 nsr_id=nsr_id,
5818 ns_state=None,
5819 current_operation="UPDATING",
5820 current_operation_id=nslcmop_id,
5821 )
5822
5823 step = "Getting nslcmop from database"
5824 db_nslcmop = self.db.get_one(
5825 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5826 )
5827 update_type = db_nslcmop["operationParams"]["updateType"]
5828
5829 step = "Getting nsr from database"
5830 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5831 old_operational_status = db_nsr["operational-status"]
5832 db_nsr_update["operational-status"] = "updating"
5833 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5834 nsr_deployed = db_nsr["_admin"].get("deployed")
5835
5836 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005837 # Get the input parameters given through update request
5838 vnf_instance_id = db_nslcmop["operationParams"][
5839 "changeVnfPackageData"
5840 ].get("vnfInstanceId")
5841
5842 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5843 "vnfdId"
5844 )
5845 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5846
5847 step = "Getting vnfr from database"
5848 db_vnfr = self.db.get_one(
5849 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5850 )
5851
5852 step = "Getting vnfds from database"
5853 # Latest VNFD
5854 latest_vnfd = self.db.get_one(
5855 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5856 )
5857 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5858
5859 # Current VNFD
5860 current_vnf_revision = db_vnfr.get("revision", 1)
5861 current_vnfd = self.db.get_one(
5862 "vnfds_revisions",
5863 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5864 fail_on_empty=False,
5865 )
5866 # Charm artifact paths will be filled up later
5867 (
5868 current_charm_artifact_path,
5869 target_charm_artifact_path,
5870 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005871 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005872 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005873
5874 step = "Checking if revision has changed in VNFD"
5875 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305876 change_type = "policy_updated"
5877
aticigdffa6212022-04-12 15:27:53 +03005878 # There is new revision of VNFD, update operation is required
5879 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005880 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005881
5882 step = "Removing the VNFD packages if they exist in the local path"
5883 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5884 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5885
5886 step = "Get the VNFD packages from FSMongo"
5887 self.fs.sync(from_path=latest_vnfd_path)
5888 self.fs.sync(from_path=current_vnfd_path)
5889
5890 step = (
5891 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5892 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005893 current_base_folder = current_vnfd["_admin"]["storage"]
5894 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005895
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005896 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005897 get_iterable(nsr_deployed, "VCA")
5898 ):
5899 vnf_index = db_vnfr.get("member-vnf-index-ref")
5900
5901 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005902 if vca_deployed.get("member-vnf-index") == vnf_index:
5903 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5904 vca_type = vca_deployed.get("type")
5905 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005906
5907 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005908 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005909
5910 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005911 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03005912 search_key = "kdu_name"
5913 else:
5914 search_key = "vnfd_id"
5915
5916 entity_id = vca_deployed.get(search_key)
5917
aticigdffa6212022-04-12 15:27:53 +03005918 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005919 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005920 )
5921
5922 if "execution-environment-list" in descriptor_config:
5923 ee_list = descriptor_config.get(
5924 "execution-environment-list", []
5925 )
5926 else:
5927 ee_list = []
5928
5929 # There could be several charm used in the same VNF
5930 for ee_item in ee_list:
5931 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005932 step = "Getting charm name"
5933 charm_name = ee_item["juju"].get("charm")
5934
5935 step = "Setting Charm artifact paths"
5936 current_charm_artifact_path.append(
5937 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005938 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005939 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005940 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005941 current_vnf_revision,
5942 )
5943 )
5944 target_charm_artifact_path.append(
5945 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005946 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005947 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005948 vca_type,
aticigd7083542022-05-30 20:45:55 +03005949 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005950 )
5951 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005952 elif ee_item.get("helm-chart"):
5953 # add chart to list and all parameters
5954 step = "Getting helm chart name"
5955 chart_name = ee_item.get("helm-chart")
Luis Vegae11384e2023-10-10 22:36:33 +00005956 vca_type = "helm-v3"
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005957 step = "Setting Helm chart artifact paths"
5958
garciadeblasfb1e25f2022-11-18 14:36:22 +01005959 helm_artifacts.append(
5960 {
5961 "current_artifact_path": get_charm_artifact_path(
5962 current_base_folder,
5963 chart_name,
5964 vca_type,
5965 current_vnf_revision,
5966 ),
5967 "target_artifact_path": get_charm_artifact_path(
5968 latest_base_folder,
5969 chart_name,
5970 vca_type,
5971 latest_vnfd_revision,
5972 ),
5973 "ee_id": ee_id,
5974 "vca_index": vca_index,
5975 "vdu_index": vdu_count_index,
5976 }
5977 )
aticigdffa6212022-04-12 15:27:53 +03005978
5979 charm_artifact_paths = zip(
5980 current_charm_artifact_path, target_charm_artifact_path
5981 )
5982
5983 step = "Checking if software version has changed in VNFD"
5984 if find_software_version(current_vnfd) != find_software_version(
5985 latest_vnfd
5986 ):
aticigdffa6212022-04-12 15:27:53 +03005987 step = "Checking if existing VNF has charm"
5988 for current_charm_path, target_charm_path in list(
5989 charm_artifact_paths
5990 ):
5991 if current_charm_path:
5992 raise LcmException(
5993 "Software version change is not supported as VNF instance {} has charm.".format(
5994 vnf_instance_id
5995 )
5996 )
5997
kayal20010cd8af32024-03-13 10:23:16 +05305998 step = "Checking whether the descriptor has SFC"
5999 if db_nsr.get("nsd", {}).get("vnffgd"):
6000 raise LcmException(
6001 "Ns update is not allowed for NS with SFC"
6002 )
6003
aticigdffa6212022-04-12 15:27:53 +03006004 # There is no change in the charm package, then redeploy the VNF
6005 # based on new descriptor
6006 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306007 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006008 (result, detailed_status) = await self._ns_redeploy_vnf(
6009 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306010 )
6011 if result == "FAILED":
6012 nslcmop_operation_state = result
6013 error_description_nslcmop = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306014 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306015 db_nslcmop_update["detailed-status"] = detailed_status
elumalai0c9435e2023-11-16 14:36:05 +05306016 db_nsr_update["detailed-status"] = detailed_status
6017 scaling_aspect = get_scaling_aspect(latest_vnfd)
6018 scaling_group_desc = db_nsr.get("_admin").get(
6019 "scaling-group", None
6020 )
6021 if scaling_group_desc:
6022 for aspect in scaling_aspect:
6023 scaling_group_id = aspect.get("id")
6024 for scale_index, scaling_group in enumerate(
6025 scaling_group_desc
6026 ):
6027 if scaling_group.get("name") == scaling_group_id:
6028 db_nsr_update[
6029 "_admin.scaling-group.{}.nb-scale-op".format(
6030 scale_index
6031 )
6032 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306033 self.logger.debug(
6034 logging_text
6035 + " step {} Done with result {} {}".format(
6036 step, nslcmop_operation_state, detailed_status
6037 )
6038 )
aticigdffa6212022-04-12 15:27:53 +03006039
6040 else:
6041 step = "Checking if any charm package has changed or not"
6042 for current_charm_path, target_charm_path in list(
6043 charm_artifact_paths
6044 ):
6045 if (
6046 current_charm_path
6047 and target_charm_path
6048 and self.check_charm_hash_changed(
6049 current_charm_path, target_charm_path
6050 )
6051 ):
aticigdffa6212022-04-12 15:27:53 +03006052 step = "Checking whether VNF uses juju bundle"
6053 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006054 raise LcmException(
6055 "Charm upgrade is not supported for the instance which"
6056 " uses juju-bundle: {}".format(
6057 check_juju_bundle_existence(current_vnfd)
6058 )
6059 )
6060
6061 step = "Upgrading Charm"
6062 (
6063 result,
6064 detailed_status,
6065 ) = await self._ns_charm_upgrade(
6066 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006067 charm_id=vca_id,
6068 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006069 path=self.fs.path + target_charm_path,
6070 timeout=timeout_seconds,
6071 )
6072
6073 if result == "FAILED":
6074 nslcmop_operation_state = result
6075 error_description_nslcmop = detailed_status
6076
6077 db_nslcmop_update["detailed-status"] = detailed_status
6078 self.logger.debug(
6079 logging_text
6080 + " step {} Done with result {} {}".format(
6081 step, nslcmop_operation_state, detailed_status
6082 )
6083 )
6084
6085 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306086 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6087 result = "COMPLETED"
6088 detailed_status = "Done"
6089 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006090
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006091 # helm base EE
6092 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006093 if not (
6094 item["current_artifact_path"]
6095 and item["target_artifact_path"]
6096 and self.check_charm_hash_changed(
6097 item["current_artifact_path"],
6098 item["target_artifact_path"],
6099 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006100 ):
6101 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006102 db_update_entry = "_admin.deployed.VCA.{}.".format(
6103 item["vca_index"]
6104 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006105 vnfr_id = db_vnfr["_id"]
6106 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6107 db_dict = {
6108 "collection": "nsrs",
6109 "filter": {"_id": nsr_id},
6110 "path": db_update_entry,
6111 }
6112 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006113 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006114 namespace=namespace,
6115 helm_id=helm_id,
6116 db_dict=db_dict,
6117 config=osm_config,
6118 artifact_path=item["target_artifact_path"],
6119 vca_type=vca_type,
6120 )
6121 vnf_id = db_vnfr.get("vnfd-ref")
6122 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6123 self.logger.debug("get ssh key block")
6124 rw_mgmt_ip = None
6125 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006126 config_descriptor,
6127 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006128 ):
6129 # Needed to inject a ssh key
6130 user = deep_get(
6131 config_descriptor,
6132 ("config-access", "ssh-access", "default-user"),
6133 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006134 step = (
6135 "Install configuration Software, getting public ssh key"
6136 )
6137 pub_key = await self.vca_map[
6138 vca_type
6139 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006140 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6141 )
6142
garciadeblasfb1e25f2022-11-18 14:36:22 +01006143 step = (
6144 "Insert public key into VM user={} ssh_key={}".format(
6145 user, pub_key
6146 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006147 )
6148 self.logger.debug(logging_text + step)
6149
6150 # wait for RO (ip-address) Insert pub_key into VM
6151 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6152 logging_text,
6153 nsr_id,
6154 vnfr_id,
6155 None,
6156 item["vdu_index"],
6157 user=user,
6158 pub_key=pub_key,
6159 )
6160
6161 initial_config_primitive_list = config_descriptor.get(
6162 "initial-config-primitive"
6163 )
6164 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006165 (
6166 p
6167 for p in initial_config_primitive_list
6168 if p["name"] == "config"
6169 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006170 None,
6171 )
6172 if not config_primitive:
6173 continue
6174
6175 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6176 if rw_mgmt_ip:
6177 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6178 if db_vnfr.get("additionalParamsForVnf"):
6179 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006180 parse_yaml_strings(
6181 db_vnfr["additionalParamsForVnf"].copy()
6182 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006183 )
6184 primitive_params_ = self._map_primitive_params(
6185 config_primitive, {}, deploy_params
6186 )
6187
6188 step = "execute primitive '{}' params '{}'".format(
6189 config_primitive["name"], primitive_params_
6190 )
6191 self.logger.debug(logging_text + step)
6192 await self.vca_map[vca_type].exec_primitive(
6193 ee_id=ee_id,
6194 primitive_name=config_primitive["name"],
6195 params_dict=primitive_params_,
6196 db_dict=db_dict,
6197 vca_id=vca_id,
6198 vca_type=vca_type,
6199 )
6200
6201 step = "Updating policies"
6202 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6203 detailed_status = "Done"
6204 db_nslcmop_update["detailed-status"] = "Done"
6205
aticigdffa6212022-04-12 15:27:53 +03006206 # If nslcmop_operation_state is None, so any operation is not failed.
6207 if not nslcmop_operation_state:
6208 nslcmop_operation_state = "COMPLETED"
6209
6210 # If update CHANGE_VNFPKG nslcmop_operation is successful
6211 # vnf revision need to be updated
6212 vnfr_update["revision"] = latest_vnfd_revision
6213 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6214
6215 self.logger.debug(
6216 logging_text
6217 + " task Done with result {} {}".format(
6218 nslcmop_operation_state, detailed_status
6219 )
6220 )
6221 elif update_type == "REMOVE_VNF":
6222 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306223 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6224 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6225 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6226 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006227 (result, detailed_status) = await self.remove_vnf(
6228 nsr_id, nslcmop_id, vnf_instance_id
6229 )
elumalaica7ece02022-04-12 12:47:32 +05306230 if result == "FAILED":
6231 nslcmop_operation_state = result
6232 error_description_nslcmop = detailed_status
6233 db_nslcmop_update["detailed-status"] = detailed_status
6234 change_type = "vnf_terminated"
6235 if not nslcmop_operation_state:
6236 nslcmop_operation_state = "COMPLETED"
6237 self.logger.debug(
6238 logging_text
6239 + " task Done with result {} {}".format(
6240 nslcmop_operation_state, detailed_status
6241 )
6242 )
aticigdffa6212022-04-12 15:27:53 +03006243
k4.rahulb827de92022-05-02 16:35:02 +00006244 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006245 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6246 "vnfInstanceId"
6247 ]
6248 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6249 "changeStateTo"
6250 ]
6251 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6252 "additionalParam"
6253 ]
k4.rahulb827de92022-05-02 16:35:02 +00006254 (result, detailed_status) = await self.rebuild_start_stop(
6255 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006256 )
k4.rahulb827de92022-05-02 16:35:02 +00006257 if result == "FAILED":
6258 nslcmop_operation_state = result
6259 error_description_nslcmop = detailed_status
6260 db_nslcmop_update["detailed-status"] = detailed_status
6261 if not nslcmop_operation_state:
6262 nslcmop_operation_state = "COMPLETED"
6263 self.logger.debug(
6264 logging_text
6265 + " task Done with result {} {}".format(
6266 nslcmop_operation_state, detailed_status
6267 )
6268 )
Rahul Kumarad400e42024-05-24 14:41:41 +05306269 elif update_type == "VERTICAL_SCALE":
6270 self.logger.debug(
6271 "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
6272 )
6273 # Get the input parameters given through update request
6274 vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6275 "vnfInstanceId"
6276 )
6277
6278 vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
6279 "vnfdId"
6280 )
6281 step = "Getting vnfr from database"
6282 db_vnfr = self.db.get_one(
6283 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
6284 )
6285 self.logger.debug(step)
6286 step = "Getting vnfds from database"
6287 self.logger.debug("Start" + step)
6288 # Latest VNFD
6289 latest_vnfd = self.db.get_one(
6290 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6291 )
6292 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6293 # Current VNFD
6294 current_vnf_revision = db_vnfr.get("revision", 1)
6295 current_vnfd = self.db.get_one(
6296 "vnfds_revisions",
6297 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6298 fail_on_empty=False,
6299 )
6300 self.logger.debug("End" + step)
6301 # verify flavor changes
6302 step = "Checking for flavor change"
6303 if find_software_version(current_vnfd) != find_software_version(
6304 latest_vnfd
6305 ):
6306 self.logger.debug("Start" + step)
6307 if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
6308 "virtual-compute-desc"
6309 ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
6310 "virtual-storage-desc"
6311 ):
6312 raise LcmException(
6313 "No change in flavor check vnfd {}".format(vnfd_id)
6314 )
6315 else:
6316 raise LcmException(
6317 "No change in software_version of vnfd {}".format(vnfd_id)
6318 )
6319
6320 self.logger.debug("End" + step)
6321
6322 (result, detailed_status) = await self.vertical_scale(
6323 nsr_id, nslcmop_id
6324 )
6325 self.logger.debug(
6326 "vertical_scale result: {} detailed_status :{}".format(
6327 result, detailed_status
6328 )
6329 )
6330 if result == "FAILED":
6331 nslcmop_operation_state = result
6332 error_description_nslcmop = detailed_status
6333 db_nslcmop_update["detailed-status"] = detailed_status
6334 if not nslcmop_operation_state:
6335 nslcmop_operation_state = "COMPLETED"
6336 self.logger.debug(
6337 logging_text
6338 + " task Done with result {} {}".format(
6339 nslcmop_operation_state, detailed_status
6340 )
6341 )
k4.rahulb827de92022-05-02 16:35:02 +00006342
aticigdffa6212022-04-12 15:27:53 +03006343 # If nslcmop_operation_state is None, so any operation is not failed.
6344 # All operations are executed in overall.
6345 if not nslcmop_operation_state:
6346 nslcmop_operation_state = "COMPLETED"
6347 db_nsr_update["operational-status"] = old_operational_status
6348
6349 except (DbException, LcmException, N2VCException, K8sException) as e:
6350 self.logger.error(logging_text + "Exit Exception {}".format(e))
6351 exc = e
6352 except asyncio.CancelledError:
6353 self.logger.error(
6354 logging_text + "Cancelled Exception while '{}'".format(step)
6355 )
6356 exc = "Operation was cancelled"
6357 except asyncio.TimeoutError:
6358 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6359 exc = "Timeout"
6360 except Exception as e:
6361 exc = traceback.format_exc()
6362 self.logger.critical(
6363 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6364 exc_info=True,
6365 )
6366 finally:
6367 if exc:
6368 db_nslcmop_update[
6369 "detailed-status"
6370 ] = (
6371 detailed_status
6372 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6373 nslcmop_operation_state = "FAILED"
6374 db_nsr_update["operational-status"] = old_operational_status
6375 if db_nsr:
6376 self._write_ns_status(
6377 nsr_id=nsr_id,
6378 ns_state=db_nsr["nsState"],
6379 current_operation="IDLE",
6380 current_operation_id=None,
6381 other_update=db_nsr_update,
6382 )
6383
6384 self._write_op_status(
6385 op_id=nslcmop_id,
6386 stage="",
6387 error_message=error_description_nslcmop,
6388 operation_state=nslcmop_operation_state,
6389 other_update=db_nslcmop_update,
6390 )
6391
6392 if nslcmop_operation_state:
6393 try:
elumalaica7ece02022-04-12 12:47:32 +05306394 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306395 "nsr_id": nsr_id,
6396 "nslcmop_id": nslcmop_id,
6397 "operationState": nslcmop_operation_state,
6398 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006399 if (
6400 change_type in ("vnf_terminated", "policy_updated")
6401 and member_vnf_index
6402 ):
elumalaica7ece02022-04-12 12:47:32 +05306403 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006404 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006405 except Exception as e:
6406 self.logger.error(
6407 logging_text + "kafka_write notification Exception {}".format(e)
6408 )
6409 self.logger.debug(logging_text + "Exit")
6410 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6411 return nslcmop_operation_state, detailed_status
6412
tierno59d22d22018-09-25 18:10:19 +02006413 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006414 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006415 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006416 if not task_is_locked_by_me:
6417 return
6418
tierno59d22d22018-09-25 18:10:19 +02006419 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006420 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006421 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006422 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006423 self.logger.debug(logging_text + "Enter")
6424 # get all needed from database
6425 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006426 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006427 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006428 exc = None
tierno9ab95942018-10-10 16:44:22 +02006429 # in case of error, indicates what part of scale was failed to put nsr at error status
6430 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006431 old_operational_status = ""
6432 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006433 nsi_id = None
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006434 prom_job_name = ""
tierno59d22d22018-09-25 18:10:19 +02006435 try:
kuused124bfe2019-06-18 12:09:24 +02006436 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006437 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006438 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6439 self._write_ns_status(
6440 nsr_id=nsr_id,
6441 ns_state=None,
6442 current_operation="SCALING",
6443 current_operation_id=nslcmop_id,
6444 )
quilesj4cda56b2019-12-05 10:02:20 +00006445
ikalyvas02d9e7b2019-05-27 18:16:01 +03006446 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006447 self.logger.debug(
6448 step + " after having waited for previous tasks to be completed"
6449 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006450 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006451
ikalyvas02d9e7b2019-05-27 18:16:01 +03006452 step = "Getting nsr from database"
6453 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006454 old_operational_status = db_nsr["operational-status"]
6455 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006456
kayal20010cd8af32024-03-13 10:23:16 +05306457 step = "Checking whether the descriptor has SFC"
6458 if db_nsr.get("nsd", {}).get("vnffgd"):
6459 raise LcmException("Scaling is not allowed for NS with SFC")
6460
tierno59d22d22018-09-25 18:10:19 +02006461 step = "Parsing scaling parameters"
6462 db_nsr_update["operational-status"] = "scaling"
6463 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006464 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006465
garciadeblas5697b8b2021-03-24 09:17:02 +01006466 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6467 "scaleByStepData"
6468 ]["member-vnf-index"]
6469 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6470 "scaleByStepData"
6471 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006472 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006473 # for backward compatibility
6474 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6475 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6476 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6477 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6478
tierno59d22d22018-09-25 18:10:19 +02006479 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006480 db_vnfr = self.db.get_one(
6481 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6482 )
bravof922c4172020-11-24 21:21:43 -03006483
David Garciac1fe90a2021-03-31 19:12:02 +02006484 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6485
tierno59d22d22018-09-25 18:10:19 +02006486 step = "Getting vnfd from database"
6487 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006488
aktas13251562021-02-12 22:19:10 +03006489 base_folder = db_vnfd["_admin"]["storage"]
6490
tierno59d22d22018-09-25 18:10:19 +02006491 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006492 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006493 get_scaling_aspect(db_vnfd),
6494 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006495 )
6496 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006497 raise LcmException(
6498 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6499 "at vnfd:scaling-group-descriptor".format(scaling_group)
6500 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006501
tierno15b1cf12019-08-29 13:21:40 +00006502 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006503 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006504 nb_scale_op = 0
6505 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006506 self.update_db_2(
6507 "nsrs",
6508 nsr_id,
6509 {
6510 "_admin.scaling-group": [
36970ef037852024-04-01 15:41:31 +00006511 {
6512 "name": scaling_group,
6513 "vnf_index": vnf_index,
6514 "nb-scale-op": 0,
6515 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006516 ]
6517 },
6518 )
tierno59d22d22018-09-25 18:10:19 +02006519 admin_scale_index = 0
6520 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006521 for admin_scale_index, admin_scale_info in enumerate(
6522 db_nsr["_admin"]["scaling-group"]
6523 ):
36970ef037852024-04-01 15:41:31 +00006524 if (
6525 admin_scale_info["name"] == scaling_group
6526 and admin_scale_info["vnf_index"] == vnf_index
6527 ):
tierno59d22d22018-09-25 18:10:19 +02006528 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6529 break
tierno9ab95942018-10-10 16:44:22 +02006530 else: # not found, set index one plus last element and add new entry with the name
6531 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006532 db_nsr_update[
6533 "_admin.scaling-group.{}.name".format(admin_scale_index)
6534 ] = scaling_group
36970ef037852024-04-01 15:41:31 +00006535 db_nsr_update[
6536 "_admin.scaling-group.{}.vnf_index".format(admin_scale_index)
6537 ] = vnf_index
aktas5f75f102021-03-15 11:26:10 +03006538
6539 vca_scaling_info = []
6540 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006541 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006542 if "aspect-delta-details" not in scaling_descriptor:
6543 raise LcmException(
6544 "Aspect delta details not fount in scaling descriptor {}".format(
6545 scaling_descriptor["name"]
6546 )
6547 )
tierno59d22d22018-09-25 18:10:19 +02006548 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006549 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006550
aktas5f75f102021-03-15 11:26:10 +03006551 scaling_info["scaling_direction"] = "OUT"
6552 scaling_info["vdu-create"] = {}
6553 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006554 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006555 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006556 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006557 # vdu_index also provides the number of instance of the targeted vdu
6558 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00006559 if vdu_index <= len(db_vnfr["vdur"]):
6560 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6561 prom_job_name = (
6562 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6563 )
6564 prom_job_name = prom_job_name.replace("_", "")
6565 prom_job_name = prom_job_name.replace("-", "")
6566 else:
6567 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006568 cloud_init_text = self._get_vdu_cloud_init_content(
6569 vdud, db_vnfd
6570 )
tierno72ef84f2020-10-06 08:22:07 +00006571 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006572 additional_params = (
6573 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6574 or {}
6575 )
bravof832f8992020-12-07 12:57:31 -03006576 cloud_init_list = []
6577
6578 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6579 max_instance_count = 10
6580 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006581 max_instance_count = vdu_profile.get(
6582 "max-number-of-instances", 10
6583 )
6584
6585 default_instance_num = get_number_of_instances(
6586 db_vnfd, vdud["id"]
6587 )
aktas5f75f102021-03-15 11:26:10 +03006588 instances_number = vdu_delta.get("number-of-instances", 1)
6589 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006590
aktas5f75f102021-03-15 11:26:10 +03006591 new_instance_count = nb_scale_op + default_instance_num
6592 # Control if new count is over max and vdu count is less than max.
6593 # Then assign new instance count
6594 if new_instance_count > max_instance_count > vdu_count:
6595 instances_number = new_instance_count - max_instance_count
6596 else:
6597 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006598
aktas5f75f102021-03-15 11:26:10 +03006599 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006600 raise LcmException(
6601 "reached the limit of {} (max-instance-count) "
6602 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006603 "scaling-group-descriptor '{}'".format(
6604 nb_scale_op, scaling_group
6605 )
bravof922c4172020-11-24 21:21:43 -03006606 )
bravof832f8992020-12-07 12:57:31 -03006607 for x in range(vdu_delta.get("number-of-instances", 1)):
6608 if cloud_init_text:
6609 # TODO Information of its own ip is not available because db_vnfr is not updated.
6610 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006611 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006612 )
bravof832f8992020-12-07 12:57:31 -03006613 cloud_init_list.append(
6614 self._parse_cloud_init(
6615 cloud_init_text,
6616 additional_params,
6617 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006618 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006619 )
6620 )
aktas5f75f102021-03-15 11:26:10 +03006621 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006622 {
6623 "osm_vdu_id": vdu_delta["id"],
6624 "member-vnf-index": vnf_index,
6625 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006626 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006627 }
6628 )
aktas5f75f102021-03-15 11:26:10 +03006629 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6630 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006631 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006632 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006633 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006634
6635 # Might have different kdus in the same delta
6636 # Should have list for each kdu
6637 if not scaling_info["kdu-create"].get(kdu_name, None):
6638 scaling_info["kdu-create"][kdu_name] = []
6639
6640 kdur = get_kdur(db_vnfr, kdu_name)
6641 if kdur.get("helm-chart"):
6642 k8s_cluster_type = "helm-chart-v3"
6643 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006644 elif kdur.get("juju-bundle"):
6645 k8s_cluster_type = "juju-bundle"
6646 else:
6647 raise LcmException(
6648 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6649 "juju-bundle. Maybe an old NBI version is running".format(
6650 db_vnfr["member-vnf-index-ref"], kdu_name
6651 )
6652 )
6653
6654 max_instance_count = 10
6655 if kdu_profile and "max-number-of-instances" in kdu_profile:
6656 max_instance_count = kdu_profile.get(
6657 "max-number-of-instances", 10
6658 )
6659
6660 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6661 deployed_kdu, _ = get_deployed_kdu(
6662 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006663 )
aktas5f75f102021-03-15 11:26:10 +03006664 if deployed_kdu is None:
6665 raise LcmException(
6666 "KDU '{}' for vnf '{}' not deployed".format(
6667 kdu_name, vnf_index
6668 )
6669 )
6670 kdu_instance = deployed_kdu.get("kdu-instance")
6671 instance_num = await self.k8scluster_map[
6672 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006673 ].get_scale_count(
6674 resource_name,
6675 kdu_instance,
6676 vca_id=vca_id,
6677 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6678 kdu_model=deployed_kdu.get("kdu-model"),
6679 )
aktas5f75f102021-03-15 11:26:10 +03006680 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006681 "number-of-instances", 1
6682 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006683
aktas5f75f102021-03-15 11:26:10 +03006684 # Control if new count is over max and instance_num is less than max.
6685 # Then assign max instance number to kdu replica count
6686 if kdu_replica_count > max_instance_count > instance_num:
6687 kdu_replica_count = max_instance_count
6688 if kdu_replica_count > max_instance_count:
6689 raise LcmException(
6690 "reached the limit of {} (max-instance-count) "
6691 "scaling-out operations for the "
6692 "scaling-group-descriptor '{}'".format(
6693 instance_num, scaling_group
6694 )
6695 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006696
aktas5f75f102021-03-15 11:26:10 +03006697 for x in range(kdu_delta.get("number-of-instances", 1)):
6698 vca_scaling_info.append(
6699 {
6700 "osm_kdu_id": kdu_name,
6701 "member-vnf-index": vnf_index,
6702 "type": "create",
6703 "kdu_index": instance_num + x - 1,
6704 }
6705 )
6706 scaling_info["kdu-create"][kdu_name].append(
6707 {
6708 "member-vnf-index": vnf_index,
6709 "type": "create",
6710 "k8s-cluster-type": k8s_cluster_type,
6711 "resource-name": resource_name,
6712 "scale": kdu_replica_count,
6713 }
6714 )
6715 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006716 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006717
6718 scaling_info["scaling_direction"] = "IN"
6719 scaling_info["vdu-delete"] = {}
6720 scaling_info["kdu-delete"] = {}
6721
bravof832f8992020-12-07 12:57:31 -03006722 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006723 for vdu_delta in delta.get("vdu-delta", {}):
6724 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006725 min_instance_count = 0
6726 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6727 if vdu_profile and "min-number-of-instances" in vdu_profile:
6728 min_instance_count = vdu_profile["min-number-of-instances"]
6729
garciadeblas5697b8b2021-03-24 09:17:02 +01006730 default_instance_num = get_number_of_instances(
6731 db_vnfd, vdu_delta["id"]
6732 )
aktas5f75f102021-03-15 11:26:10 +03006733 instance_num = vdu_delta.get("number-of-instances", 1)
6734 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006735
aktas5f75f102021-03-15 11:26:10 +03006736 new_instance_count = nb_scale_op + default_instance_num
6737
6738 if new_instance_count < min_instance_count < vdu_count:
6739 instances_number = min_instance_count - new_instance_count
6740 else:
6741 instances_number = instance_num
6742
6743 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006744 raise LcmException(
6745 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006746 "scaling-group-descriptor '{}'".format(
6747 nb_scale_op, scaling_group
6748 )
bravof832f8992020-12-07 12:57:31 -03006749 )
aktas13251562021-02-12 22:19:10 +03006750 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006751 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006752 {
6753 "osm_vdu_id": vdu_delta["id"],
6754 "member-vnf-index": vnf_index,
6755 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006756 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006757 }
6758 )
aktas5f75f102021-03-15 11:26:10 +03006759 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6760 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006761 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006762 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006763 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006764
6765 if not scaling_info["kdu-delete"].get(kdu_name, None):
6766 scaling_info["kdu-delete"][kdu_name] = []
6767
6768 kdur = get_kdur(db_vnfr, kdu_name)
6769 if kdur.get("helm-chart"):
6770 k8s_cluster_type = "helm-chart-v3"
6771 self.logger.debug("kdur: {}".format(kdur))
aktas5f75f102021-03-15 11:26:10 +03006772 elif kdur.get("juju-bundle"):
6773 k8s_cluster_type = "juju-bundle"
6774 else:
6775 raise LcmException(
6776 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6777 "juju-bundle. Maybe an old NBI version is running".format(
6778 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6779 )
6780 )
6781
6782 min_instance_count = 0
6783 if kdu_profile and "min-number-of-instances" in kdu_profile:
6784 min_instance_count = kdu_profile["min-number-of-instances"]
6785
6786 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6787 deployed_kdu, _ = get_deployed_kdu(
6788 nsr_deployed, kdu_name, vnf_index
6789 )
6790 if deployed_kdu is None:
6791 raise LcmException(
6792 "KDU '{}' for vnf '{}' not deployed".format(
6793 kdu_name, vnf_index
6794 )
6795 )
6796 kdu_instance = deployed_kdu.get("kdu-instance")
6797 instance_num = await self.k8scluster_map[
6798 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006799 ].get_scale_count(
6800 resource_name,
6801 kdu_instance,
6802 vca_id=vca_id,
6803 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6804 kdu_model=deployed_kdu.get("kdu-model"),
6805 )
aktas5f75f102021-03-15 11:26:10 +03006806 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006807 "number-of-instances", 1
6808 )
tierno59d22d22018-09-25 18:10:19 +02006809
aktas5f75f102021-03-15 11:26:10 +03006810 if kdu_replica_count < min_instance_count < instance_num:
6811 kdu_replica_count = min_instance_count
6812 if kdu_replica_count < min_instance_count:
6813 raise LcmException(
6814 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6815 "scaling-group-descriptor '{}'".format(
6816 instance_num, scaling_group
6817 )
6818 )
6819
6820 for x in range(kdu_delta.get("number-of-instances", 1)):
6821 vca_scaling_info.append(
6822 {
6823 "osm_kdu_id": kdu_name,
6824 "member-vnf-index": vnf_index,
6825 "type": "delete",
6826 "kdu_index": instance_num - x - 1,
6827 }
6828 )
6829 scaling_info["kdu-delete"][kdu_name].append(
6830 {
6831 "member-vnf-index": vnf_index,
6832 "type": "delete",
6833 "k8s-cluster-type": k8s_cluster_type,
6834 "resource-name": resource_name,
6835 "scale": kdu_replica_count,
6836 }
6837 )
6838
tierno59d22d22018-09-25 18:10:19 +02006839 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006840 vdu_delete = copy(scaling_info.get("vdu-delete"))
6841 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006842 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006843 if vdu_delete.get(vdur["vdu-id-ref"]):
6844 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006845 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006846 {
6847 "name": vdur.get("name") or vdur.get("vdu-name"),
6848 "vdu_id": vdur["vdu-id-ref"],
6849 "interface": [],
6850 }
6851 )
tierno59d22d22018-09-25 18:10:19 +02006852 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006853 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006854 {
6855 "name": interface["name"],
6856 "ip_address": interface["ip-address"],
6857 "mac_address": interface.get("mac-address"),
6858 }
6859 )
tierno2357f4e2020-10-19 16:38:59 +00006860 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006861
kuuseac3a8882019-10-03 10:48:06 +02006862 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006863 step = "Executing pre-scale vnf-config-primitive"
6864 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006865 for scaling_config_action in scaling_descriptor[
6866 "scaling-config-action"
6867 ]:
6868 if (
6869 scaling_config_action.get("trigger") == "pre-scale-in"
6870 and scaling_type == "SCALE_IN"
6871 ) or (
6872 scaling_config_action.get("trigger") == "pre-scale-out"
6873 and scaling_type == "SCALE_OUT"
6874 ):
6875 vnf_config_primitive = scaling_config_action[
6876 "vnf-config-primitive-name-ref"
6877 ]
6878 step = db_nslcmop_update[
6879 "detailed-status"
6880 ] = "executing pre-scale scaling-config-action '{}'".format(
6881 vnf_config_primitive
6882 )
tiernoda964822019-01-14 15:53:47 +00006883
tierno59d22d22018-09-25 18:10:19 +02006884 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006885 for config_primitive in (
6886 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6887 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006888 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006889 break
6890 else:
6891 raise LcmException(
6892 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006893 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006894 "primitive".format(scaling_group, vnf_config_primitive)
6895 )
tiernoda964822019-01-14 15:53:47 +00006896
aktas5f75f102021-03-15 11:26:10 +03006897 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006898 if db_vnfr.get("additionalParamsForVnf"):
6899 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006900
tierno9ab95942018-10-10 16:44:22 +02006901 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006902 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006903 primitive_params = self._map_primitive_params(
6904 config_primitive, {}, vnfr_params
6905 )
kuuseac3a8882019-10-03 10:48:06 +02006906
tierno7c4e24c2020-05-13 08:41:35 +00006907 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006908 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006909 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006910 vnf_index,
6911 vnf_config_primitive,
6912 primitive_params,
6913 "PRE-SCALE",
6914 )
tierno7c4e24c2020-05-13 08:41:35 +00006915 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006916 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006917 result = "COMPLETED"
6918 result_detail = "Done"
6919 self.logger.debug(
6920 logging_text
6921 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6922 vnf_config_primitive, result, result_detail
6923 )
6924 )
kuuseac3a8882019-10-03 10:48:06 +02006925 else:
tierno7c4e24c2020-05-13 08:41:35 +00006926 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006927 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006928 op_index = (
6929 len(db_nslcmop.get("_admin", {}).get("operations"))
6930 - 1
6931 )
6932 self.logger.debug(
6933 logging_text
6934 + "vnf_config_primitive={} New sub-operation".format(
6935 vnf_config_primitive
6936 )
6937 )
kuuseac3a8882019-10-03 10:48:06 +02006938 else:
tierno7c4e24c2020-05-13 08:41:35 +00006939 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006940 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6941 op_index
6942 ]
6943 vnf_index = op.get("member_vnf_index")
6944 vnf_config_primitive = op.get("primitive")
6945 primitive_params = op.get("primitive_params")
6946 self.logger.debug(
6947 logging_text
6948 + "vnf_config_primitive={} Sub-operation retry".format(
6949 vnf_config_primitive
6950 )
6951 )
tierno588547c2020-07-01 15:30:20 +00006952 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006953 ee_descriptor_id = config_primitive.get(
6954 "execution-environment-ref"
6955 )
6956 primitive_name = config_primitive.get(
6957 "execution-environment-primitive", vnf_config_primitive
6958 )
6959 ee_id, vca_type = self._look_for_deployed_vca(
6960 nsr_deployed["VCA"],
6961 member_vnf_index=vnf_index,
6962 vdu_id=None,
6963 vdu_count_index=None,
6964 ee_descriptor_id=ee_descriptor_id,
6965 )
kuuseac3a8882019-10-03 10:48:06 +02006966 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006967 ee_id,
6968 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006969 primitive_params,
6970 vca_type=vca_type,
6971 vca_id=vca_id,
6972 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006973 self.logger.debug(
6974 logging_text
6975 + "vnf_config_primitive={} Done with result {} {}".format(
6976 vnf_config_primitive, result, result_detail
6977 )
6978 )
kuuseac3a8882019-10-03 10:48:06 +02006979 # Update operationState = COMPLETED | FAILED
6980 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006981 db_nslcmop, op_index, result, result_detail
6982 )
kuuseac3a8882019-10-03 10:48:06 +02006983
tierno59d22d22018-09-25 18:10:19 +02006984 if result == "FAILED":
6985 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006986 db_nsr_update["config-status"] = old_config_status
6987 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006988 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006989
garciadeblas5697b8b2021-03-24 09:17:02 +01006990 db_nsr_update[
6991 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6992 ] = nb_scale_op
6993 db_nsr_update[
6994 "_admin.scaling-group.{}.time".format(admin_scale_index)
6995 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006996
aktas13251562021-02-12 22:19:10 +03006997 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006998 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006999 step = db_nslcmop_update[
7000 "detailed-status"
7001 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007002 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007003 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007004 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007005 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007006 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007007 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007008 )
aktas5f75f102021-03-15 11:26:10 +03007009 if vca_info.get("osm_vdu_id"):
7010 vdu_id = vca_info["osm_vdu_id"]
7011 vdu_index = int(vca_info["vdu_index"])
7012 stage[
7013 1
7014 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7015 member_vnf_index, vdu_id, vdu_index
7016 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007017 stage[2] = step = "Scaling in VCA"
7018 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007019 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7020 config_update = db_nsr["configurationStatus"]
7021 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007022 if (
7023 (vca or vca.get("ee_id"))
7024 and vca["member-vnf-index"] == member_vnf_index
7025 and vca["vdu_count_index"] == vdu_index
7026 ):
aktas13251562021-02-12 22:19:10 +03007027 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007028 config_descriptor = get_configuration(
7029 db_vnfd, vca.get("vdu_id")
7030 )
aktas13251562021-02-12 22:19:10 +03007031 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007032 config_descriptor = get_configuration(
7033 db_vnfd, vca.get("kdu_name")
7034 )
aktas13251562021-02-12 22:19:10 +03007035 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007036 config_descriptor = get_configuration(
7037 db_vnfd, db_vnfd["id"]
7038 )
7039 operation_params = (
7040 db_nslcmop.get("operationParams") or {}
7041 )
7042 exec_terminate_primitives = not operation_params.get(
7043 "skip_terminate_primitives"
7044 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007045 task = asyncio.ensure_future(
7046 asyncio.wait_for(
7047 self.destroy_N2VC(
7048 logging_text,
7049 db_nslcmop,
7050 vca,
7051 config_descriptor,
7052 vca_index,
7053 destroy_ee=True,
7054 exec_primitives=exec_terminate_primitives,
7055 scaling_in=True,
7056 vca_id=vca_id,
7057 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007058 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007059 )
7060 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007061 tasks_dict_info[task] = "Terminating VCA {}".format(
7062 vca.get("ee_id")
7063 )
aktas13251562021-02-12 22:19:10 +03007064 del vca_update[vca_index]
7065 del config_update[vca_index]
7066 # wait for pending tasks of terminate primitives
7067 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007068 self.logger.debug(
7069 logging_text
7070 + "Waiting for tasks {}".format(
7071 list(tasks_dict_info.keys())
7072 )
7073 )
7074 error_list = await self._wait_for_tasks(
7075 logging_text,
7076 tasks_dict_info,
7077 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007078 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007079 ),
7080 stage,
7081 nslcmop_id,
7082 )
aktas13251562021-02-12 22:19:10 +03007083 tasks_dict_info.clear()
7084 if error_list:
7085 raise LcmException("; ".join(error_list))
7086
7087 db_vca_and_config_update = {
7088 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007089 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007090 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007091 self.update_db_2(
7092 "nsrs", db_nsr["_id"], db_vca_and_config_update
7093 )
aktas13251562021-02-12 22:19:10 +03007094 scale_process = None
7095 # SCALE-IN VCA - END
7096
kuuseac3a8882019-10-03 10:48:06 +02007097 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007098 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007099 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007100 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007101 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007102 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007103 )
aktas5f75f102021-03-15 11:26:10 +03007104 scaling_info.pop("vdu-create", None)
7105 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007106
tierno9ab95942018-10-10 16:44:22 +02007107 scale_process = None
aktas13251562021-02-12 22:19:10 +03007108 # SCALE RO - END
7109
aktas5f75f102021-03-15 11:26:10 +03007110 # SCALE KDU - BEGIN
7111 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7112 scale_process = "KDU"
7113 await self._scale_kdu(
7114 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7115 )
7116 scaling_info.pop("kdu-create", None)
7117 scaling_info.pop("kdu-delete", None)
7118
7119 scale_process = None
7120 # SCALE KDU - END
7121
7122 if db_nsr_update:
7123 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7124
aktas13251562021-02-12 22:19:10 +03007125 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007126 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007127 step = db_nslcmop_update[
7128 "detailed-status"
7129 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007130 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007131 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007132 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007133 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007134 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007135 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007136 )
aktas13251562021-02-12 22:19:10 +03007137 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007138 if vca_info.get("osm_vdu_id"):
7139 vdu_index = int(vca_info["vdu_index"])
7140 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7141 if db_vnfr.get("additionalParamsForVnf"):
7142 deploy_params.update(
7143 parse_yaml_strings(
7144 db_vnfr["additionalParamsForVnf"].copy()
7145 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007146 )
aktas5f75f102021-03-15 11:26:10 +03007147 descriptor_config = get_configuration(
7148 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007149 )
aktas5f75f102021-03-15 11:26:10 +03007150 if descriptor_config:
7151 vdu_id = None
7152 vdu_name = None
7153 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007154 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007155 self._deploy_n2vc(
7156 logging_text=logging_text
7157 + "member_vnf_index={} ".format(member_vnf_index),
7158 db_nsr=db_nsr,
7159 db_vnfr=db_vnfr,
7160 nslcmop_id=nslcmop_id,
7161 nsr_id=nsr_id,
7162 nsi_id=nsi_id,
7163 vnfd_id=vnfd_id,
7164 vdu_id=vdu_id,
7165 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007166 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007167 member_vnf_index=member_vnf_index,
7168 vdu_index=vdu_index,
7169 vdu_name=vdu_name,
7170 deploy_params=deploy_params,
7171 descriptor_config=descriptor_config,
7172 base_folder=base_folder,
7173 task_instantiation_info=tasks_dict_info,
7174 stage=stage,
7175 )
7176 vdu_id = vca_info["osm_vdu_id"]
7177 vdur = find_in_list(
7178 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007179 )
aktas5f75f102021-03-15 11:26:10 +03007180 descriptor_config = get_configuration(db_vnfd, vdu_id)
7181 if vdur.get("additionalParams"):
7182 deploy_params_vdu = parse_yaml_strings(
7183 vdur["additionalParams"]
7184 )
7185 else:
7186 deploy_params_vdu = deploy_params
7187 deploy_params_vdu["OSM"] = get_osm_params(
7188 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007189 )
aktas5f75f102021-03-15 11:26:10 +03007190 if descriptor_config:
7191 vdu_name = None
7192 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007193 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007194 stage[
7195 1
7196 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007197 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007198 )
7199 stage[2] = step = "Scaling out VCA"
7200 self._write_op_status(op_id=nslcmop_id, stage=stage)
7201 self._deploy_n2vc(
7202 logging_text=logging_text
7203 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7204 member_vnf_index, vdu_id, vdu_index
7205 ),
7206 db_nsr=db_nsr,
7207 db_vnfr=db_vnfr,
7208 nslcmop_id=nslcmop_id,
7209 nsr_id=nsr_id,
7210 nsi_id=nsi_id,
7211 vnfd_id=vnfd_id,
7212 vdu_id=vdu_id,
7213 kdu_name=kdu_name,
7214 member_vnf_index=member_vnf_index,
7215 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007216 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007217 vdu_name=vdu_name,
7218 deploy_params=deploy_params_vdu,
7219 descriptor_config=descriptor_config,
7220 base_folder=base_folder,
7221 task_instantiation_info=tasks_dict_info,
7222 stage=stage,
7223 )
aktas13251562021-02-12 22:19:10 +03007224 # SCALE-UP VCA - END
7225 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007226
kuuseac3a8882019-10-03 10:48:06 +02007227 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007228 # execute primitive service POST-SCALING
7229 step = "Executing post-scale vnf-config-primitive"
7230 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007231 for scaling_config_action in scaling_descriptor[
7232 "scaling-config-action"
7233 ]:
7234 if (
7235 scaling_config_action.get("trigger") == "post-scale-in"
7236 and scaling_type == "SCALE_IN"
7237 ) or (
7238 scaling_config_action.get("trigger") == "post-scale-out"
7239 and scaling_type == "SCALE_OUT"
7240 ):
7241 vnf_config_primitive = scaling_config_action[
7242 "vnf-config-primitive-name-ref"
7243 ]
7244 step = db_nslcmop_update[
7245 "detailed-status"
7246 ] = "executing post-scale scaling-config-action '{}'".format(
7247 vnf_config_primitive
7248 )
tiernoda964822019-01-14 15:53:47 +00007249
aktas5f75f102021-03-15 11:26:10 +03007250 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007251 if db_vnfr.get("additionalParamsForVnf"):
7252 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7253
tierno59d22d22018-09-25 18:10:19 +02007254 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007255 for config_primitive in (
7256 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7257 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007258 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007259 break
7260 else:
tiernoa278b842020-07-08 15:33:55 +00007261 raise LcmException(
7262 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7263 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007264 "config-primitive".format(
7265 scaling_group, vnf_config_primitive
7266 )
7267 )
tierno9ab95942018-10-10 16:44:22 +02007268 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007269 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007270 primitive_params = self._map_primitive_params(
7271 config_primitive, {}, vnfr_params
7272 )
tiernod6de1992018-10-11 13:05:52 +02007273
tierno7c4e24c2020-05-13 08:41:35 +00007274 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007275 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007276 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007277 vnf_index,
7278 vnf_config_primitive,
7279 primitive_params,
7280 "POST-SCALE",
7281 )
quilesj4cda56b2019-12-05 10:02:20 +00007282 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007283 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007284 result = "COMPLETED"
7285 result_detail = "Done"
7286 self.logger.debug(
7287 logging_text
7288 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7289 vnf_config_primitive, result, result_detail
7290 )
7291 )
kuuseac3a8882019-10-03 10:48:06 +02007292 else:
quilesj4cda56b2019-12-05 10:02:20 +00007293 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007294 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007295 op_index = (
7296 len(db_nslcmop.get("_admin", {}).get("operations"))
7297 - 1
7298 )
7299 self.logger.debug(
7300 logging_text
7301 + "vnf_config_primitive={} New sub-operation".format(
7302 vnf_config_primitive
7303 )
7304 )
kuuseac3a8882019-10-03 10:48:06 +02007305 else:
tierno7c4e24c2020-05-13 08:41:35 +00007306 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007307 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7308 op_index
7309 ]
7310 vnf_index = op.get("member_vnf_index")
7311 vnf_config_primitive = op.get("primitive")
7312 primitive_params = op.get("primitive_params")
7313 self.logger.debug(
7314 logging_text
7315 + "vnf_config_primitive={} Sub-operation retry".format(
7316 vnf_config_primitive
7317 )
7318 )
tierno588547c2020-07-01 15:30:20 +00007319 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007320 ee_descriptor_id = config_primitive.get(
7321 "execution-environment-ref"
7322 )
7323 primitive_name = config_primitive.get(
7324 "execution-environment-primitive", vnf_config_primitive
7325 )
7326 ee_id, vca_type = self._look_for_deployed_vca(
7327 nsr_deployed["VCA"],
7328 member_vnf_index=vnf_index,
7329 vdu_id=None,
7330 vdu_count_index=None,
7331 ee_descriptor_id=ee_descriptor_id,
7332 )
kuuseac3a8882019-10-03 10:48:06 +02007333 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007334 ee_id,
7335 primitive_name,
7336 primitive_params,
7337 vca_type=vca_type,
7338 vca_id=vca_id,
7339 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007340 self.logger.debug(
7341 logging_text
7342 + "vnf_config_primitive={} Done with result {} {}".format(
7343 vnf_config_primitive, result, result_detail
7344 )
7345 )
kuuseac3a8882019-10-03 10:48:06 +02007346 # Update operationState = COMPLETED | FAILED
7347 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007348 db_nslcmop, op_index, result, result_detail
7349 )
kuuseac3a8882019-10-03 10:48:06 +02007350
tierno59d22d22018-09-25 18:10:19 +02007351 if result == "FAILED":
7352 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007353 db_nsr_update["config-status"] = old_config_status
7354 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007355 # POST-SCALE END
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007356 # Check if each vnf has exporter for metric collection if so update prometheus job records
Rahul Kumar54671c52024-05-09 15:34:01 +05307357 if scaling_type == "SCALE_OUT" and bool(self.service_kpi.old_sa):
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007358 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7359 vnfr_id = db_vnfr["id"]
7360 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7361 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7362 self.logger.debug("exporter config :{}".format(exporter_config))
7363 artifact_path = "{}/{}/{}".format(
7364 base_folder["folder"],
7365 base_folder["pkg-dir"],
7366 "exporter-endpoint",
7367 )
7368 ee_id = None
7369 ee_config_descriptor = exporter_config
7370 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7371 logging_text,
7372 nsr_id,
7373 vnfr_id,
7374 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7375 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7376 user=None,
7377 pub_key=None,
7378 )
7379 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7380 self.logger.debug("Artifact_path:{}".format(artifact_path))
7381 vdu_id_for_prom = None
7382 vdu_index_for_prom = None
7383 for x in get_iterable(db_vnfr, "vdur"):
7384 vdu_id_for_prom = x.get("vdu-id-ref")
7385 vdu_index_for_prom = x.get("count-index")
7386 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7387 vnfr_id = vnfr_id.replace("_", "")
7388 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7389 ee_id=ee_id,
7390 artifact_path=artifact_path,
7391 ee_config_descriptor=ee_config_descriptor,
7392 vnfr_id=vnfr_id,
7393 nsr_id=nsr_id,
7394 target_ip=rw_mgmt_ip,
7395 element_type="VDU",
7396 vdu_id=vdu_id_for_prom,
7397 vdu_index=vdu_index_for_prom,
7398 )
tierno59d22d22018-09-25 18:10:19 +02007399
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007400 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7401 if prometheus_jobs:
7402 db_nsr_update[
7403 "_admin.deployed.prometheus_jobs"
7404 ] = prometheus_jobs
7405 self.update_db_2(
7406 "nsrs",
7407 nsr_id,
7408 db_nsr_update,
7409 )
7410
7411 for job in prometheus_jobs:
7412 self.db.set_one(
7413 "prometheus_jobs",
7414 {"job_name": ""},
7415 job,
7416 upsert=True,
7417 fail_on_empty=False,
7418 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007419 db_nsr_update[
7420 "detailed-status"
7421 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7422 db_nsr_update["operational-status"] = (
7423 "running"
7424 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007425 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007426 )
tiernod6de1992018-10-11 13:05:52 +02007427 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007428 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007429 except (
7430 ROclient.ROClientException,
7431 DbException,
7432 LcmException,
7433 NgRoException,
7434 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007435 self.logger.error(logging_text + "Exit Exception {}".format(e))
7436 exc = e
7437 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007438 self.logger.error(
7439 logging_text + "Cancelled Exception while '{}'".format(step)
7440 )
tierno59d22d22018-09-25 18:10:19 +02007441 exc = "Operation was cancelled"
7442 except Exception as e:
7443 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007444 self.logger.critical(
7445 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7446 exc_info=True,
7447 )
tierno59d22d22018-09-25 18:10:19 +02007448 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05007449 error_list = list()
7450 if exc:
7451 error_list.append(str(exc))
garciadeblas5697b8b2021-03-24 09:17:02 +01007452 self._write_ns_status(
7453 nsr_id=nsr_id,
7454 ns_state=None,
7455 current_operation="IDLE",
7456 current_operation_id=None,
7457 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007458 try:
7459 if tasks_dict_info:
7460 stage[1] = "Waiting for instantiate pending tasks."
7461 self.logger.debug(logging_text + stage[1])
7462 exc = await self._wait_for_tasks(
7463 logging_text,
7464 tasks_dict_info,
7465 self.timeout.ns_deploy,
7466 stage,
7467 nslcmop_id,
7468 nsr_id=nsr_id,
7469 )
7470 except asyncio.CancelledError:
7471 error_list.append("Cancelled")
7472 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
7473 await self._wait_for_tasks(
garciadeblas5697b8b2021-03-24 09:17:02 +01007474 logging_text,
7475 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007476 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007477 stage,
7478 nslcmop_id,
7479 nsr_id=nsr_id,
7480 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05007481 if error_list:
7482 error_detail = "; ".join(error_list)
garciadeblas5697b8b2021-03-24 09:17:02 +01007483 db_nslcmop_update[
7484 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05007485 ] = error_description_nslcmop = "FAILED {}: {}".format(
7486 step, error_detail
7487 )
tiernoa17d4f42020-04-28 09:59:23 +00007488 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007489 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007490 db_nsr_update["operational-status"] = old_operational_status
7491 db_nsr_update["config-status"] = old_config_status
7492 db_nsr_update["detailed-status"] = ""
7493 if scale_process:
7494 if "VCA" in scale_process:
7495 db_nsr_update["config-status"] = "failed"
7496 if "RO" in scale_process:
7497 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007498 db_nsr_update[
7499 "detailed-status"
7500 ] = "FAILED scaling nslcmop={} {}: {}".format(
Gabriel Cubab6049d32023-10-30 13:44:49 -05007501 nslcmop_id, step, error_detail
garciadeblas5697b8b2021-03-24 09:17:02 +01007502 )
tiernoa17d4f42020-04-28 09:59:23 +00007503 else:
7504 error_description_nslcmop = None
7505 nslcmop_operation_state = "COMPLETED"
7506 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2c8ab4d2023-11-09 08:34:27 +00007507 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7508 self.db.del_one(
7509 "prometheus_jobs",
7510 {"job_name": prom_job_name},
7511 fail_on_empty=False,
7512 )
quilesj4cda56b2019-12-05 10:02:20 +00007513
garciadeblas5697b8b2021-03-24 09:17:02 +01007514 self._write_op_status(
7515 op_id=nslcmop_id,
7516 stage="",
7517 error_message=error_description_nslcmop,
7518 operation_state=nslcmop_operation_state,
7519 other_update=db_nslcmop_update,
7520 )
tiernoa17d4f42020-04-28 09:59:23 +00007521 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007522 self._write_ns_status(
7523 nsr_id=nsr_id,
7524 ns_state=None,
7525 current_operation="IDLE",
7526 current_operation_id=None,
7527 other_update=db_nsr_update,
7528 )
tiernoa17d4f42020-04-28 09:59:23 +00007529
tierno59d22d22018-09-25 18:10:19 +02007530 if nslcmop_operation_state:
7531 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007532 msg = {
7533 "nsr_id": nsr_id,
7534 "nslcmop_id": nslcmop_id,
7535 "operationState": nslcmop_operation_state,
7536 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007537 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007538 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007539 self.logger.error(
7540 logging_text + "kafka_write notification Exception {}".format(e)
7541 )
tierno59d22d22018-09-25 18:10:19 +02007542 self.logger.debug(logging_text + "Exit")
7543 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007544
aktas5f75f102021-03-15 11:26:10 +03007545 async def _scale_kdu(
7546 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7547 ):
7548 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7549 for kdu_name in _scaling_info:
7550 for kdu_scaling_info in _scaling_info[kdu_name]:
7551 deployed_kdu, index = get_deployed_kdu(
7552 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7553 )
7554 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7555 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007556 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007557 scale = int(kdu_scaling_info["scale"])
7558 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7559
7560 db_dict = {
7561 "collection": "nsrs",
7562 "filter": {"_id": nsr_id},
7563 "path": "_admin.deployed.K8s.{}".format(index),
7564 }
7565
7566 step = "scaling application {}".format(
7567 kdu_scaling_info["resource-name"]
7568 )
7569 self.logger.debug(logging_text + step)
7570
7571 if kdu_scaling_info["type"] == "delete":
7572 kdu_config = get_configuration(db_vnfd, kdu_name)
7573 if (
7574 kdu_config
7575 and kdu_config.get("terminate-config-primitive")
7576 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7577 ):
7578 terminate_config_primitive_list = kdu_config.get(
7579 "terminate-config-primitive"
7580 )
7581 terminate_config_primitive_list.sort(
7582 key=lambda val: int(val["seq"])
7583 )
7584
7585 for (
7586 terminate_config_primitive
7587 ) in terminate_config_primitive_list:
7588 primitive_params_ = self._map_primitive_params(
7589 terminate_config_primitive, {}, {}
7590 )
7591 step = "execute terminate config primitive"
7592 self.logger.debug(logging_text + step)
7593 await asyncio.wait_for(
7594 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7595 cluster_uuid=cluster_uuid,
7596 kdu_instance=kdu_instance,
7597 primitive_name=terminate_config_primitive["name"],
7598 params=primitive_params_,
7599 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007600 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007601 vca_id=vca_id,
7602 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007603 timeout=self.timeout.primitive
7604 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007605 )
7606
7607 await asyncio.wait_for(
7608 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007609 kdu_instance=kdu_instance,
7610 scale=scale,
7611 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007612 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007613 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007614 cluster_uuid=cluster_uuid,
7615 kdu_model=kdu_model,
7616 atomic=True,
7617 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007618 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007619 timeout=self.timeout.scale_on_error
7620 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007621 )
7622
7623 if kdu_scaling_info["type"] == "create":
7624 kdu_config = get_configuration(db_vnfd, kdu_name)
7625 if (
7626 kdu_config
7627 and kdu_config.get("initial-config-primitive")
7628 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7629 ):
7630 initial_config_primitive_list = kdu_config.get(
7631 "initial-config-primitive"
7632 )
7633 initial_config_primitive_list.sort(
7634 key=lambda val: int(val["seq"])
7635 )
7636
7637 for initial_config_primitive in initial_config_primitive_list:
7638 primitive_params_ = self._map_primitive_params(
7639 initial_config_primitive, {}, {}
7640 )
7641 step = "execute initial config primitive"
7642 self.logger.debug(logging_text + step)
7643 await asyncio.wait_for(
7644 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7645 cluster_uuid=cluster_uuid,
7646 kdu_instance=kdu_instance,
7647 primitive_name=initial_config_primitive["name"],
7648 params=primitive_params_,
7649 db_dict=db_dict,
7650 vca_id=vca_id,
7651 ),
7652 timeout=600,
7653 )
7654
garciadeblas5697b8b2021-03-24 09:17:02 +01007655 async def _scale_ng_ro(
7656 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7657 ):
tierno2357f4e2020-10-19 16:38:59 +00007658 nsr_id = db_nslcmop["nsInstanceId"]
7659 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7660 db_vnfrs = {}
7661
7662 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007663 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007664
7665 # for each vnf in ns, read vnfd
7666 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7667 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7668 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007669 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007670 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007671 # read from db
7672 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007673 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007674 n2vc_key = self.n2vc.get_public_key()
7675 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007676 self.scale_vnfr(
7677 db_vnfr,
7678 vdu_scaling_info.get("vdu-create"),
7679 vdu_scaling_info.get("vdu-delete"),
7680 mark_delete=True,
7681 )
tierno2357f4e2020-10-19 16:38:59 +00007682 # db_vnfr has been updated, update db_vnfrs to use it
7683 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007684 await self._instantiate_ng_ro(
7685 logging_text,
7686 nsr_id,
7687 db_nsd,
7688 db_nsr,
7689 db_nslcmop,
7690 db_vnfrs,
7691 db_vnfds,
7692 n2vc_key_list,
7693 stage=stage,
7694 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007695 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007696 )
tierno2357f4e2020-10-19 16:38:59 +00007697 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007698 self.scale_vnfr(
7699 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7700 )
tierno2357f4e2020-10-19 16:38:59 +00007701
bravof73bac502021-05-11 07:38:47 -04007702 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007703 self,
7704 ee_id: str,
7705 artifact_path: str,
7706 ee_config_descriptor: dict,
7707 vnfr_id: str,
7708 nsr_id: str,
7709 target_ip: str,
7710 element_type: str,
7711 vnf_member_index: str = "",
7712 vdu_id: str = "",
7713 vdu_index: int = None,
7714 kdu_name: str = "",
7715 kdu_index: int = None,
7716 ) -> dict:
7717 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7718 This method will wait until the corresponding VDU or KDU is fully instantiated
7719
7720 Args:
7721 ee_id (str): Execution Environment ID
7722 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7723 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7724 vnfr_id (str): VNFR ID where this EE applies
7725 nsr_id (str): NSR ID where this EE applies
7726 target_ip (str): VDU/KDU instance IP address
7727 element_type (str): NS or VNF or VDU or KDU
7728 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7729 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7730 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7731 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7732 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7733
7734 Raises:
7735 LcmException: When the VDU or KDU instance was not found in an hour
7736
7737 Returns:
7738 _type_: Prometheus jobs
7739 """
7740 # default the vdur and kdur names to an empty string, to avoid any later
7741 # problem with Prometheus when the element type is not VDU or KDU
7742 vdur_name = ""
7743 kdur_name = ""
7744
tiernob996d942020-07-03 14:52:28 +00007745 # look if exist a file called 'prometheus*.j2' and
7746 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007747 job_file = next(
7748 (
7749 f
7750 for f in artifact_content
7751 if f.startswith("prometheus") and f.endswith(".j2")
7752 ),
7753 None,
7754 )
tiernob996d942020-07-03 14:52:28 +00007755 if not job_file:
7756 return
k4.rahul74944982023-04-19 17:00:52 +05307757 self.logger.debug("Artifact path{}".format(artifact_path))
7758 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007759 with self.fs.file_open((artifact_path, job_file), "r") as f:
7760 job_data = f.read()
7761
Pedro Escaleira120695e2022-06-11 21:17:26 +01007762 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7763 if element_type in ("VDU", "KDU"):
7764 for _ in range(360):
7765 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7766 if vdu_id and vdu_index is not None:
7767 vdur = next(
7768 (
7769 x
7770 for x in get_iterable(db_vnfr, "vdur")
7771 if (
7772 x.get("vdu-id-ref") == vdu_id
7773 and x.get("count-index") == vdu_index
7774 )
7775 ),
7776 {},
7777 )
7778 if vdur.get("name"):
7779 vdur_name = vdur.get("name")
7780 break
7781 if kdu_name and kdu_index is not None:
7782 kdur = next(
7783 (
7784 x
7785 for x in get_iterable(db_vnfr, "kdur")
7786 if (
7787 x.get("kdu-name") == kdu_name
7788 and x.get("count-index") == kdu_index
7789 )
7790 ),
7791 {},
7792 )
7793 if kdur.get("name"):
7794 kdur_name = kdur.get("name")
7795 break
7796
Gabriel Cubae7898982023-05-11 01:57:21 -05007797 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007798 else:
7799 if vdu_id and vdu_index is not None:
7800 raise LcmException(
7801 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7802 )
7803 if kdu_name and kdu_index is not None:
7804 raise LcmException(
7805 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7806 )
7807
k4.rahul74944982023-04-19 17:00:52 +05307808 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007809 _, namespace, helm_id = get_ee_id_parts(
7810 ee_id
7811 ) # get namespace and EE gRPC service name
7812 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307813 host_port = "80"
7814 vnfr_id = vnfr_id.replace("-", "")
7815 variables = {
7816 "JOB_NAME": vnfr_id,
7817 "TARGET_IP": target_ip,
7818 "EXPORTER_POD_IP": host_name,
7819 "EXPORTER_POD_PORT": host_port,
7820 "NSR_ID": nsr_id,
7821 "VNF_MEMBER_INDEX": vnf_member_index,
7822 "VDUR_NAME": vdur_name,
7823 "KDUR_NAME": kdur_name,
7824 "ELEMENT_TYPE": element_type,
7825 }
7826 else:
7827 metric_path = ee_config_descriptor["metric-path"]
7828 target_port = ee_config_descriptor["metric-port"]
7829 vnfr_id = vnfr_id.replace("-", "")
7830 variables = {
7831 "JOB_NAME": vnfr_id,
7832 "TARGET_IP": target_ip,
7833 "TARGET_PORT": target_port,
7834 "METRIC_PATH": metric_path,
7835 }
7836
bravof73bac502021-05-11 07:38:47 -04007837 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007838 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7839 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007840 if (
7841 not isinstance(job.get("job_name"), str)
7842 or vnfr_id not in job["job_name"]
7843 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307844 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007845 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007846 job["vnfr_id"] = vnfr_id
7847 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007848
preethika.p28b0bf82022-09-23 07:36:28 +00007849 async def rebuild_start_stop(
7850 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7851 ):
k4.rahulb827de92022-05-02 16:35:02 +00007852 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7853 self.logger.info(logging_text + "Enter")
7854 stage = ["Preparing the environment", ""]
7855 # database nsrs record
7856 db_nsr_update = {}
7857 vdu_vim_name = None
7858 vim_vm_id = None
7859 # in case of error, indicates what part of scale was failed to put nsr at error status
7860 start_deploy = time()
7861 try:
7862 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7863 vim_account_id = db_vnfr.get("vim-account-id")
7864 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007865 vdu_id = additional_param["vdu_id"]
7866 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007867 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007868 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007869 )
k4.rahulb827de92022-05-02 16:35:02 +00007870 if vdur:
7871 vdu_vim_name = vdur["name"]
7872 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7873 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007874 else:
7875 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007876 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7877 # wait for any previous tasks in process
7878 stage[1] = "Waiting for previous operations to terminate"
7879 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007880 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007881
7882 stage[1] = "Reading from database."
7883 self.logger.info(stage[1])
7884 self._write_ns_status(
7885 nsr_id=nsr_id,
7886 ns_state=None,
7887 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007888 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007889 )
7890 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7891
7892 # read from db: ns
7893 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7894 db_nsr_update["operational-status"] = operation_type
7895 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7896 # Payload for RO
7897 desc = {
7898 operation_type: {
7899 "vim_vm_id": vim_vm_id,
7900 "vnf_id": vnf_id,
7901 "vdu_index": additional_param["count-index"],
7902 "vdu_id": vdur["id"],
7903 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007904 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007905 }
7906 }
7907 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7908 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7909 self.logger.info("ro nsr id: {}".format(nsr_id))
7910 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7911 self.logger.info("response from RO: {}".format(result_dict))
7912 action_id = result_dict["action_id"]
7913 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007914 nsr_id,
7915 action_id,
7916 nslcmop_id,
7917 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007918 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007919 None,
7920 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007921 )
7922 return "COMPLETED", "Done"
7923 except (ROclient.ROClientException, DbException, LcmException) as e:
7924 self.logger.error("Exit Exception {}".format(e))
7925 exc = e
7926 except asyncio.CancelledError:
7927 self.logger.error("Cancelled Exception while '{}'".format(stage))
7928 exc = "Operation was cancelled"
7929 except Exception as e:
7930 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007931 self.logger.critical(
7932 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7933 )
k4.rahulb827de92022-05-02 16:35:02 +00007934 return "FAILED", "Error in operate VNF {}".format(exc)
7935
elumalai80bcf1c2022-04-28 18:05:01 +05307936 async def migrate(self, nsr_id, nslcmop_id):
7937 """
7938 Migrate VNFs and VDUs instances in a NS
7939
7940 :param: nsr_id: NS Instance ID
7941 :param: nslcmop_id: nslcmop ID of migrate
7942
7943 """
7944 # Try to lock HA task here
7945 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7946 if not task_is_locked_by_me:
7947 return
7948 logging_text = "Task ns={} migrate ".format(nsr_id)
7949 self.logger.debug(logging_text + "Enter")
7950 # get all needed from database
7951 db_nslcmop = None
7952 db_nslcmop_update = {}
7953 nslcmop_operation_state = None
7954 db_nsr_update = {}
7955 target = {}
7956 exc = None
7957 # in case of error, indicates what part of scale was failed to put nsr at error status
7958 start_deploy = time()
7959
7960 try:
7961 # wait for any previous tasks in process
7962 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007963 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307964
7965 self._write_ns_status(
7966 nsr_id=nsr_id,
7967 ns_state=None,
7968 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007969 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307970 )
7971 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007972 self.logger.debug(
7973 step + " after having waited for previous tasks to be completed"
7974 )
elumalai80bcf1c2022-04-28 18:05:01 +05307975 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7976 migrate_params = db_nslcmop.get("operationParams")
7977
7978 target = {}
7979 target.update(migrate_params)
7980 desc = await self.RO.migrate(nsr_id, target)
7981 self.logger.debug("RO return > {}".format(desc))
7982 action_id = desc["action_id"]
7983 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007984 nsr_id,
7985 action_id,
7986 nslcmop_id,
7987 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007988 self.timeout.migrate,
preethika.p28b0bf82022-09-23 07:36:28 +00007989 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307990 )
7991 except (ROclient.ROClientException, DbException, LcmException) as e:
7992 self.logger.error("Exit Exception {}".format(e))
7993 exc = e
7994 except asyncio.CancelledError:
7995 self.logger.error("Cancelled Exception while '{}'".format(step))
7996 exc = "Operation was cancelled"
7997 except Exception as e:
7998 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007999 self.logger.critical(
8000 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8001 )
elumalai80bcf1c2022-04-28 18:05:01 +05308002 finally:
8003 self._write_ns_status(
8004 nsr_id=nsr_id,
8005 ns_state=None,
8006 current_operation="IDLE",
8007 current_operation_id=None,
8008 )
8009 if exc:
aticig349aa462022-05-19 12:29:35 +03008010 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308011 nslcmop_operation_state = "FAILED"
8012 else:
8013 nslcmop_operation_state = "COMPLETED"
8014 db_nslcmop_update["detailed-status"] = "Done"
8015 db_nsr_update["detailed-status"] = "Done"
8016
8017 self._write_op_status(
8018 op_id=nslcmop_id,
8019 stage="",
8020 error_message="",
8021 operation_state=nslcmop_operation_state,
8022 other_update=db_nslcmop_update,
8023 )
8024 if nslcmop_operation_state:
8025 try:
8026 msg = {
8027 "nsr_id": nsr_id,
8028 "nslcmop_id": nslcmop_id,
8029 "operationState": nslcmop_operation_state,
8030 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008031 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308032 except Exception as e:
8033 self.logger.error(
8034 logging_text + "kafka_write notification Exception {}".format(e)
8035 )
8036 self.logger.debug(logging_text + "Exit")
8037 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008038
garciadeblas07f4e4c2022-06-09 09:42:58 +02008039 async def heal(self, nsr_id, nslcmop_id):
8040 """
8041 Heal NS
8042
8043 :param nsr_id: ns instance to heal
8044 :param nslcmop_id: operation to run
8045 :return:
8046 """
8047
8048 # Try to lock HA task here
8049 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8050 if not task_is_locked_by_me:
8051 return
8052
8053 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8054 stage = ["", "", ""]
8055 tasks_dict_info = {}
8056 # ^ stage, step, VIM progress
8057 self.logger.debug(logging_text + "Enter")
8058 # get all needed from database
8059 db_nsr = None
8060 db_nslcmop_update = {}
8061 db_nsr_update = {}
8062 db_vnfrs = {} # vnf's info indexed by _id
8063 exc = None
8064 old_operational_status = ""
8065 old_config_status = ""
8066 nsi_id = None
8067 try:
8068 # wait for any previous tasks in process
8069 step = "Waiting for previous operations to terminate"
8070 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8071 self._write_ns_status(
8072 nsr_id=nsr_id,
8073 ns_state=None,
8074 current_operation="HEALING",
8075 current_operation_id=nslcmop_id,
8076 )
8077
8078 step = "Getting nslcmop from database"
8079 self.logger.debug(
8080 step + " after having waited for previous tasks to be completed"
8081 )
8082 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8083
8084 step = "Getting nsr from database"
8085 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8086 old_operational_status = db_nsr["operational-status"]
8087 old_config_status = db_nsr["config-status"]
8088
8089 db_nsr_update = {
369700ee77792024-04-01 11:23:08 +00008090 "operational-status": "healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008091 "_admin.deployed.RO.operational-status": "healing",
8092 }
8093 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8094
8095 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008096 await self.heal_RO(
8097 logging_text=logging_text,
8098 nsr_id=nsr_id,
8099 db_nslcmop=db_nslcmop,
8100 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008101 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008102 # VCA tasks
8103 # read from db: nsd
8104 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8105 self.logger.debug(logging_text + stage[1])
8106 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8107 self.fs.sync(db_nsr["nsd-id"])
8108 db_nsr["nsd"] = nsd
8109 # read from db: vnfr's of this ns
8110 step = "Getting vnfrs from db"
8111 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8112 for vnfr in db_vnfrs_list:
8113 db_vnfrs[vnfr["_id"]] = vnfr
8114 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8115
8116 # Check for each target VNF
8117 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8118 for target_vnf in target_list:
8119 # Find this VNF in the list from DB
8120 vnfr_id = target_vnf.get("vnfInstanceId", None)
8121 if vnfr_id:
8122 db_vnfr = db_vnfrs[vnfr_id]
8123 vnfd_id = db_vnfr.get("vnfd-id")
8124 vnfd_ref = db_vnfr.get("vnfd-ref")
8125 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8126 base_folder = vnfd["_admin"]["storage"]
8127 vdu_id = None
8128 vdu_index = 0
8129 vdu_name = None
8130 kdu_name = None
8131 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8132 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8133
8134 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008135 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8136 "vdu", []
8137 )
garciadeblas50639832022-09-01 13:09:47 +02008138 if not target_vdu_list:
8139 # Codigo nuevo para crear diccionario
8140 target_vdu_list = []
8141 for existing_vdu in db_vnfr.get("vdur"):
8142 vdu_name = existing_vdu.get("vdu-name", None)
8143 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008144 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8145 "run-day1", False
8146 )
8147 vdu_to_be_healed = {
8148 "vdu-id": vdu_name,
8149 "count-index": vdu_index,
8150 "run-day1": vdu_run_day1,
8151 }
garciadeblas50639832022-09-01 13:09:47 +02008152 target_vdu_list.append(vdu_to_be_healed)
8153 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008154 deploy_params_vdu = target_vdu
8155 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008156 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8157 "additionalParams", {}
8158 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008159 deploy_params_vdu["run-day1"] = target_vnf[
8160 "additionalParams"
8161 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008162 vdu_name = target_vdu.get("vdu-id", None)
8163 # TODO: Get vdu_id from vdud.
8164 vdu_id = vdu_name
8165 # For multi instance VDU count-index is mandatory
8166 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008167 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008168
8169 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8170 stage[1] = "Deploying Execution Environments."
8171 self.logger.debug(logging_text + stage[1])
8172
8173 # VNF Level charm. Normal case when proxy charms.
8174 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8175 descriptor_config = get_configuration(vnfd, vnfd_ref)
8176 if descriptor_config:
8177 # Continue if healed machine is management machine
8178 vnf_ip_address = db_vnfr.get("ip-address")
8179 target_instance = None
8180 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008181 if (
8182 instance["vdu-name"] == vdu_name
8183 and instance["count-index"] == vdu_index
8184 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008185 target_instance = instance
8186 break
8187 if vnf_ip_address == target_instance.get("ip-address"):
8188 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008189 logging_text=logging_text
8190 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8191 member_vnf_index, vdu_name, vdu_index
8192 ),
8193 db_nsr=db_nsr,
8194 db_vnfr=db_vnfr,
8195 nslcmop_id=nslcmop_id,
8196 nsr_id=nsr_id,
8197 nsi_id=nsi_id,
8198 vnfd_id=vnfd_ref,
8199 vdu_id=None,
8200 kdu_name=None,
8201 member_vnf_index=member_vnf_index,
8202 vdu_index=0,
8203 vdu_name=None,
8204 deploy_params=deploy_params_vdu,
8205 descriptor_config=descriptor_config,
8206 base_folder=base_folder,
8207 task_instantiation_info=tasks_dict_info,
8208 stage=stage,
8209 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008210
8211 # VDU Level charm. Normal case with native charms.
8212 descriptor_config = get_configuration(vnfd, vdu_name)
8213 if descriptor_config:
8214 self._heal_n2vc(
8215 logging_text=logging_text
8216 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8217 member_vnf_index, vdu_name, vdu_index
8218 ),
8219 db_nsr=db_nsr,
8220 db_vnfr=db_vnfr,
8221 nslcmop_id=nslcmop_id,
8222 nsr_id=nsr_id,
8223 nsi_id=nsi_id,
8224 vnfd_id=vnfd_ref,
8225 vdu_id=vdu_id,
8226 kdu_name=kdu_name,
8227 member_vnf_index=member_vnf_index,
8228 vdu_index=vdu_index,
8229 vdu_name=vdu_name,
8230 deploy_params=deploy_params_vdu,
8231 descriptor_config=descriptor_config,
8232 base_folder=base_folder,
8233 task_instantiation_info=tasks_dict_info,
8234 stage=stage,
8235 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008236 except (
8237 ROclient.ROClientException,
8238 DbException,
8239 LcmException,
8240 NgRoException,
8241 ) as e:
8242 self.logger.error(logging_text + "Exit Exception {}".format(e))
8243 exc = e
8244 except asyncio.CancelledError:
8245 self.logger.error(
8246 logging_text + "Cancelled Exception while '{}'".format(step)
8247 )
8248 exc = "Operation was cancelled"
8249 except Exception as e:
8250 exc = traceback.format_exc()
8251 self.logger.critical(
8252 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8253 exc_info=True,
8254 )
8255 finally:
Gabriel Cubab6049d32023-10-30 13:44:49 -05008256 error_list = list()
36970544ef442024-04-01 10:58:42 +00008257 if db_vnfrs_list and target_list:
8258 for vnfrs in db_vnfrs_list:
8259 for vnf_instance in target_list:
8260 if vnfrs["_id"] == vnf_instance.get("vnfInstanceId"):
8261 self.db.set_list(
8262 "vnfrs",
8263 {"_id": vnfrs["_id"]},
8264 {"_admin.modified": time()},
8265 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008266 if exc:
8267 error_list.append(str(exc))
8268 try:
8269 if tasks_dict_info:
8270 stage[1] = "Waiting for healing pending tasks."
8271 self.logger.debug(logging_text + stage[1])
8272 exc = await self._wait_for_tasks(
8273 logging_text,
8274 tasks_dict_info,
8275 self.timeout.ns_deploy,
8276 stage,
8277 nslcmop_id,
8278 nsr_id=nsr_id,
8279 )
8280 except asyncio.CancelledError:
8281 error_list.append("Cancelled")
8282 await self._cancel_pending_tasks(logging_text, tasks_dict_info)
8283 await self._wait_for_tasks(
garciadeblas07f4e4c2022-06-09 09:42:58 +02008284 logging_text,
8285 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008286 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008287 stage,
8288 nslcmop_id,
8289 nsr_id=nsr_id,
8290 )
Gabriel Cubab6049d32023-10-30 13:44:49 -05008291 if error_list:
8292 error_detail = "; ".join(error_list)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008293 db_nslcmop_update[
8294 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008295 ] = error_description_nslcmop = "FAILED {}: {}".format(
8296 step, error_detail
8297 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008298 nslcmop_operation_state = "FAILED"
8299 if db_nsr:
8300 db_nsr_update["operational-status"] = old_operational_status
8301 db_nsr_update["config-status"] = old_config_status
8302 db_nsr_update[
8303 "detailed-status"
Gabriel Cubab6049d32023-10-30 13:44:49 -05008304 ] = "FAILED healing nslcmop={} {}: {}".format(
8305 nslcmop_id, step, error_detail
8306 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008307 for task, task_name in tasks_dict_info.items():
8308 if not task.done() or task.cancelled() or task.exception():
8309 if task_name.startswith(self.task_name_deploy_vca):
8310 # A N2VC task is pending
8311 db_nsr_update["config-status"] = "failed"
8312 else:
8313 # RO task is pending
8314 db_nsr_update["operational-status"] = "failed"
8315 else:
8316 error_description_nslcmop = None
8317 nslcmop_operation_state = "COMPLETED"
8318 db_nslcmop_update["detailed-status"] = "Done"
8319 db_nsr_update["detailed-status"] = "Done"
8320 db_nsr_update["operational-status"] = "running"
8321 db_nsr_update["config-status"] = "configured"
8322
8323 self._write_op_status(
8324 op_id=nslcmop_id,
8325 stage="",
8326 error_message=error_description_nslcmop,
8327 operation_state=nslcmop_operation_state,
8328 other_update=db_nslcmop_update,
8329 )
8330 if db_nsr:
8331 self._write_ns_status(
8332 nsr_id=nsr_id,
8333 ns_state=None,
8334 current_operation="IDLE",
8335 current_operation_id=None,
8336 other_update=db_nsr_update,
8337 )
8338
8339 if nslcmop_operation_state:
8340 try:
8341 msg = {
8342 "nsr_id": nsr_id,
8343 "nslcmop_id": nslcmop_id,
8344 "operationState": nslcmop_operation_state,
8345 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008346 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008347 except Exception as e:
8348 self.logger.error(
8349 logging_text + "kafka_write notification Exception {}".format(e)
8350 )
8351 self.logger.debug(logging_text + "Exit")
8352 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8353
8354 async def heal_RO(
8355 self,
8356 logging_text,
8357 nsr_id,
8358 db_nslcmop,
8359 stage,
8360 ):
8361 """
8362 Heal at RO
8363 :param logging_text: preffix text to use at logging
8364 :param nsr_id: nsr identity
8365 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8366 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8367 :return: None or exception
8368 """
preethika.p28b0bf82022-09-23 07:36:28 +00008369
garciadeblas07f4e4c2022-06-09 09:42:58 +02008370 def get_vim_account(vim_account_id):
8371 nonlocal db_vims
8372 if vim_account_id in db_vims:
8373 return db_vims[vim_account_id]
8374 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8375 db_vims[vim_account_id] = db_vim
8376 return db_vim
8377
8378 try:
8379 start_heal = time()
8380 ns_params = db_nslcmop.get("operationParams")
8381 if ns_params and ns_params.get("timeout_ns_heal"):
8382 timeout_ns_heal = ns_params["timeout_ns_heal"]
8383 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008384 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008385
8386 db_vims = {}
8387
8388 nslcmop_id = db_nslcmop["_id"]
8389 target = {
8390 "action_id": nslcmop_id,
8391 }
preethika.p28b0bf82022-09-23 07:36:28 +00008392 self.logger.warning(
8393 "db_nslcmop={} and timeout_ns_heal={}".format(
8394 db_nslcmop, timeout_ns_heal
8395 )
8396 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008397 target.update(db_nslcmop.get("operationParams", {}))
8398
8399 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8400 desc = await self.RO.recreate(nsr_id, target)
8401 self.logger.debug("RO return > {}".format(desc))
8402 action_id = desc["action_id"]
8403 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8404 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008405 nsr_id,
8406 action_id,
8407 nslcmop_id,
8408 start_heal,
8409 timeout_ns_heal,
8410 stage,
8411 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008412 )
8413
8414 # Updating NSR
8415 db_nsr_update = {
8416 "_admin.deployed.RO.operational-status": "running",
8417 "detailed-status": " ".join(stage),
8418 }
8419 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8420 self._write_op_status(nslcmop_id, stage)
8421 self.logger.debug(
8422 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8423 )
8424
8425 except Exception as e:
8426 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008427 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008428 self.logger.error(
8429 "Error healing at VIM {}".format(e),
8430 exc_info=not isinstance(
8431 e,
8432 (
8433 ROclient.ROClientException,
8434 LcmException,
8435 DbException,
8436 NgRoException,
8437 ),
8438 ),
8439 )
8440 raise
8441
8442 def _heal_n2vc(
8443 self,
8444 logging_text,
8445 db_nsr,
8446 db_vnfr,
8447 nslcmop_id,
8448 nsr_id,
8449 nsi_id,
8450 vnfd_id,
8451 vdu_id,
8452 kdu_name,
8453 member_vnf_index,
8454 vdu_index,
8455 vdu_name,
8456 deploy_params,
8457 descriptor_config,
8458 base_folder,
8459 task_instantiation_info,
8460 stage,
8461 ):
8462 # launch instantiate_N2VC in a asyncio task and register task object
8463 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8464 # if not found, create one entry and update database
8465 # fill db_nsr._admin.deployed.VCA.<index>
8466
8467 self.logger.debug(
8468 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8469 )
aticig9bc63ac2022-07-27 09:32:06 +03008470
8471 charm_name = ""
8472 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008473 if "execution-environment-list" in descriptor_config:
8474 ee_list = descriptor_config.get("execution-environment-list", [])
8475 elif "juju" in descriptor_config:
8476 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008477 if "execution-environment-list" not in descriptor_config:
8478 # charm name is only required for ns charms
8479 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008480 else: # other types as script are not supported
8481 ee_list = []
8482
8483 for ee_item in ee_list:
8484 self.logger.debug(
8485 logging_text
8486 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8487 ee_item.get("juju"), ee_item.get("helm-chart")
8488 )
8489 )
8490 ee_descriptor_id = ee_item.get("id")
Gabriel Cuba879483e2024-03-19 18:01:13 -05008491 vca_name, charm_name, vca_type = self.get_vca_info(
8492 ee_item, db_nsr, get_charm_name
8493 )
8494 if not vca_type:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008495 self.logger.debug(
Gabriel Cuba879483e2024-03-19 18:01:13 -05008496 logging_text + "skipping, non juju/charm/helm configuration"
garciadeblas07f4e4c2022-06-09 09:42:58 +02008497 )
8498 continue
8499
8500 vca_index = -1
8501 for vca_index, vca_deployed in enumerate(
8502 db_nsr["_admin"]["deployed"]["VCA"]
8503 ):
8504 if not vca_deployed:
8505 continue
8506 if (
8507 vca_deployed.get("member-vnf-index") == member_vnf_index
8508 and vca_deployed.get("vdu_id") == vdu_id
8509 and vca_deployed.get("kdu_name") == kdu_name
8510 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8511 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8512 ):
8513 break
8514 else:
8515 # not found, create one.
8516 target = (
8517 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8518 )
8519 if vdu_id:
8520 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8521 elif kdu_name:
8522 target += "/kdu/{}".format(kdu_name)
8523 vca_deployed = {
8524 "target_element": target,
8525 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8526 "member-vnf-index": member_vnf_index,
8527 "vdu_id": vdu_id,
8528 "kdu_name": kdu_name,
8529 "vdu_count_index": vdu_index,
8530 "operational-status": "init", # TODO revise
8531 "detailed-status": "", # TODO revise
8532 "step": "initial-deploy", # TODO revise
8533 "vnfd_id": vnfd_id,
8534 "vdu_name": vdu_name,
8535 "type": vca_type,
8536 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008537 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008538 }
8539 vca_index += 1
8540
8541 # create VCA and configurationStatus in db
8542 db_dict = {
8543 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8544 "configurationStatus.{}".format(vca_index): dict(),
8545 }
8546 self.update_db_2("nsrs", nsr_id, db_dict)
8547
8548 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8549
8550 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8551 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8552 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8553
8554 # Launch task
8555 task_n2vc = asyncio.ensure_future(
8556 self.heal_N2VC(
8557 logging_text=logging_text,
8558 vca_index=vca_index,
8559 nsi_id=nsi_id,
8560 db_nsr=db_nsr,
8561 db_vnfr=db_vnfr,
8562 vdu_id=vdu_id,
8563 kdu_name=kdu_name,
8564 vdu_index=vdu_index,
8565 deploy_params=deploy_params,
8566 config_descriptor=descriptor_config,
8567 base_folder=base_folder,
8568 nslcmop_id=nslcmop_id,
8569 stage=stage,
8570 vca_type=vca_type,
8571 vca_name=vca_name,
8572 ee_config_descriptor=ee_item,
8573 )
8574 )
8575 self.lcm_tasks.register(
8576 "ns",
8577 nsr_id,
8578 nslcmop_id,
8579 "instantiate_N2VC-{}".format(vca_index),
8580 task_n2vc,
8581 )
8582 task_instantiation_info[
8583 task_n2vc
8584 ] = self.task_name_deploy_vca + " {}.{}".format(
8585 member_vnf_index or "", vdu_id or ""
8586 )
8587
8588 async def heal_N2VC(
8589 self,
8590 logging_text,
8591 vca_index,
8592 nsi_id,
8593 db_nsr,
8594 db_vnfr,
8595 vdu_id,
8596 kdu_name,
8597 vdu_index,
8598 config_descriptor,
8599 deploy_params,
8600 base_folder,
8601 nslcmop_id,
8602 stage,
8603 vca_type,
8604 vca_name,
8605 ee_config_descriptor,
8606 ):
8607 nsr_id = db_nsr["_id"]
8608 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8609 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8610 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8611 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8612 db_dict = {
8613 "collection": "nsrs",
8614 "filter": {"_id": nsr_id},
8615 "path": db_update_entry,
8616 }
8617 step = ""
8618 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008619 element_type = "NS"
8620 element_under_configuration = nsr_id
8621
8622 vnfr_id = None
8623 if db_vnfr:
8624 vnfr_id = db_vnfr["_id"]
8625 osm_config["osm"]["vnf_id"] = vnfr_id
8626
8627 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8628
8629 if vca_type == "native_charm":
8630 index_number = 0
8631 else:
8632 index_number = vdu_index or 0
8633
8634 if vnfr_id:
8635 element_type = "VNF"
8636 element_under_configuration = vnfr_id
8637 namespace += ".{}-{}".format(vnfr_id, index_number)
8638 if vdu_id:
8639 namespace += ".{}-{}".format(vdu_id, index_number)
8640 element_type = "VDU"
8641 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8642 osm_config["osm"]["vdu_id"] = vdu_id
8643 elif kdu_name:
8644 namespace += ".{}".format(kdu_name)
8645 element_type = "KDU"
8646 element_under_configuration = kdu_name
8647 osm_config["osm"]["kdu_name"] = kdu_name
8648
8649 # Get artifact path
8650 if base_folder["pkg-dir"]:
8651 artifact_path = "{}/{}/{}/{}".format(
8652 base_folder["folder"],
8653 base_folder["pkg-dir"],
8654 "charms"
8655 if vca_type
8656 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8657 else "helm-charts",
8658 vca_name,
8659 )
8660 else:
8661 artifact_path = "{}/Scripts/{}/{}/".format(
8662 base_folder["folder"],
8663 "charms"
8664 if vca_type
8665 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8666 else "helm-charts",
8667 vca_name,
8668 )
8669
8670 self.logger.debug("Artifact path > {}".format(artifact_path))
8671
8672 # get initial_config_primitive_list that applies to this element
8673 initial_config_primitive_list = config_descriptor.get(
8674 "initial-config-primitive"
8675 )
8676
8677 self.logger.debug(
8678 "Initial config primitive list > {}".format(
8679 initial_config_primitive_list
8680 )
8681 )
8682
8683 # add config if not present for NS charm
8684 ee_descriptor_id = ee_config_descriptor.get("id")
8685 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8686 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8687 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8688 )
8689
8690 self.logger.debug(
8691 "Initial config primitive list #2 > {}".format(
8692 initial_config_primitive_list
8693 )
8694 )
8695 # n2vc_redesign STEP 3.1
8696 # find old ee_id if exists
8697 ee_id = vca_deployed.get("ee_id")
8698
8699 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8700 # create or register execution environment in VCA. Only for native charms when healing
8701 if vca_type == "native_charm":
8702 step = "Waiting to VM being up and getting IP address"
8703 self.logger.debug(logging_text + step)
8704 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8705 logging_text,
8706 nsr_id,
8707 vnfr_id,
8708 vdu_id,
8709 vdu_index,
8710 user=None,
8711 pub_key=None,
8712 )
8713 credentials = {"hostname": rw_mgmt_ip}
8714 # get username
8715 username = deep_get(
8716 config_descriptor, ("config-access", "ssh-access", "default-user")
8717 )
8718 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8719 # merged. Meanwhile let's get username from initial-config-primitive
8720 if not username and initial_config_primitive_list:
8721 for config_primitive in initial_config_primitive_list:
8722 for param in config_primitive.get("parameter", ()):
8723 if param["name"] == "ssh-username":
8724 username = param["value"]
8725 break
8726 if not username:
8727 raise LcmException(
8728 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8729 "'config-access.ssh-access.default-user'"
8730 )
8731 credentials["username"] = username
8732
8733 # n2vc_redesign STEP 3.2
8734 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8735 self._write_configuration_status(
8736 nsr_id=nsr_id,
8737 vca_index=vca_index,
8738 status="REGISTERING",
8739 element_under_configuration=element_under_configuration,
8740 element_type=element_type,
8741 )
8742
8743 step = "register execution environment {}".format(credentials)
8744 self.logger.debug(logging_text + step)
8745 ee_id = await self.vca_map[vca_type].register_execution_environment(
8746 credentials=credentials,
8747 namespace=namespace,
8748 db_dict=db_dict,
8749 vca_id=vca_id,
8750 )
8751
8752 # update ee_id en db
8753 db_dict_ee_id = {
8754 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8755 }
8756 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8757
8758 # for compatibility with MON/POL modules, the need model and application name at database
8759 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8760 # Not sure if this need to be done when healing
8761 """
8762 ee_id_parts = ee_id.split(".")
8763 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8764 if len(ee_id_parts) >= 2:
8765 model_name = ee_id_parts[0]
8766 application_name = ee_id_parts[1]
8767 db_nsr_update[db_update_entry + "model"] = model_name
8768 db_nsr_update[db_update_entry + "application"] = application_name
8769 """
8770
8771 # n2vc_redesign STEP 3.3
8772 # Install configuration software. Only for native charms.
8773 step = "Install configuration Software"
8774
8775 self._write_configuration_status(
8776 nsr_id=nsr_id,
8777 vca_index=vca_index,
8778 status="INSTALLING SW",
8779 element_under_configuration=element_under_configuration,
8780 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008781 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008782 other_update=None,
8783 )
8784
8785 # TODO check if already done
8786 self.logger.debug(logging_text + step)
8787 config = None
8788 if vca_type == "native_charm":
8789 config_primitive = next(
8790 (p for p in initial_config_primitive_list if p["name"] == "config"),
8791 None,
8792 )
8793 if config_primitive:
8794 config = self._map_primitive_params(
8795 config_primitive, {}, deploy_params
8796 )
8797 await self.vca_map[vca_type].install_configuration_sw(
8798 ee_id=ee_id,
8799 artifact_path=artifact_path,
8800 db_dict=db_dict,
8801 config=config,
8802 num_units=1,
8803 vca_id=vca_id,
8804 vca_type=vca_type,
8805 )
8806
8807 # write in db flag of configuration_sw already installed
8808 self.update_db_2(
8809 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8810 )
8811
8812 # Not sure if this need to be done when healing
8813 """
8814 # add relations for this VCA (wait for other peers related with this VCA)
8815 await self._add_vca_relations(
8816 logging_text=logging_text,
8817 nsr_id=nsr_id,
8818 vca_type=vca_type,
8819 vca_index=vca_index,
8820 )
8821 """
8822
8823 # if SSH access is required, then get execution environment SSH public
8824 # if native charm we have waited already to VM be UP
Luis Vegae11384e2023-10-10 22:36:33 +00008825 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm-v3"):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008826 pub_key = None
8827 user = None
8828 # self.logger.debug("get ssh key block")
8829 if deep_get(
8830 config_descriptor, ("config-access", "ssh-access", "required")
8831 ):
8832 # self.logger.debug("ssh key needed")
8833 # Needed to inject a ssh key
8834 user = deep_get(
8835 config_descriptor,
8836 ("config-access", "ssh-access", "default-user"),
8837 )
8838 step = "Install configuration Software, getting public ssh key"
8839 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8840 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8841 )
8842
8843 step = "Insert public key into VM user={} ssh_key={}".format(
8844 user, pub_key
8845 )
8846 else:
8847 # self.logger.debug("no need to get ssh key")
8848 step = "Waiting to VM being up and getting IP address"
8849 self.logger.debug(logging_text + step)
8850
8851 # n2vc_redesign STEP 5.1
8852 # wait for RO (ip-address) Insert pub_key into VM
8853 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008854 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008855 if vnfr_id:
8856 if kdu_name:
8857 rw_mgmt_ip = await self.wait_kdu_up(
8858 logging_text, nsr_id, vnfr_id, kdu_name
8859 )
8860 else:
8861 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8862 logging_text,
8863 nsr_id,
8864 vnfr_id,
8865 vdu_id,
8866 vdu_index,
8867 user=user,
8868 pub_key=pub_key,
8869 )
8870 else:
8871 rw_mgmt_ip = None # This is for a NS configuration
8872
8873 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8874
8875 # store rw_mgmt_ip in deploy params for later replacement
8876 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8877
8878 # Day1 operations.
8879 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008880 runDay1 = deploy_params.get("run-day1", False)
8881 self.logger.debug(
8882 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8883 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008884 if runDay1:
8885 # n2vc_redesign STEP 6 Execute initial config primitive
8886 step = "execute initial config primitive"
8887
8888 # wait for dependent primitives execution (NS -> VNF -> VDU)
8889 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008890 await self._wait_dependent_n2vc(
8891 nsr_id, vca_deployed_list, vca_index
8892 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008893
8894 # stage, in function of element type: vdu, kdu, vnf or ns
8895 my_vca = vca_deployed_list[vca_index]
8896 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8897 # VDU or KDU
8898 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8899 elif my_vca.get("member-vnf-index"):
8900 # VNF
8901 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8902 else:
8903 # NS
8904 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8905
8906 self._write_configuration_status(
8907 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8908 )
8909
8910 self._write_op_status(op_id=nslcmop_id, stage=stage)
8911
8912 check_if_terminated_needed = True
8913 for initial_config_primitive in initial_config_primitive_list:
8914 # adding information on the vca_deployed if it is a NS execution environment
8915 if not vca_deployed["member-vnf-index"]:
8916 deploy_params["ns_config_info"] = json.dumps(
8917 self._get_ns_config_info(nsr_id)
8918 )
8919 # TODO check if already done
8920 primitive_params_ = self._map_primitive_params(
8921 initial_config_primitive, {}, deploy_params
8922 )
8923
8924 step = "execute primitive '{}' params '{}'".format(
8925 initial_config_primitive["name"], primitive_params_
8926 )
8927 self.logger.debug(logging_text + step)
8928 await self.vca_map[vca_type].exec_primitive(
8929 ee_id=ee_id,
8930 primitive_name=initial_config_primitive["name"],
8931 params_dict=primitive_params_,
8932 db_dict=db_dict,
8933 vca_id=vca_id,
8934 vca_type=vca_type,
8935 )
8936 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8937 if check_if_terminated_needed:
8938 if config_descriptor.get("terminate-config-primitive"):
8939 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008940 "nsrs",
8941 nsr_id,
8942 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008943 )
8944 check_if_terminated_needed = False
8945
8946 # TODO register in database that primitive is done
8947
8948 # STEP 7 Configure metrics
8949 # Not sure if this need to be done when healing
8950 """
8951 if vca_type == "helm" or vca_type == "helm-v3":
8952 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8953 ee_id=ee_id,
8954 artifact_path=artifact_path,
8955 ee_config_descriptor=ee_config_descriptor,
8956 vnfr_id=vnfr_id,
8957 nsr_id=nsr_id,
8958 target_ip=rw_mgmt_ip,
8959 )
8960 if prometheus_jobs:
8961 self.update_db_2(
8962 "nsrs",
8963 nsr_id,
8964 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8965 )
8966
8967 for job in prometheus_jobs:
8968 self.db.set_one(
8969 "prometheus_jobs",
8970 {"job_name": job["job_name"]},
8971 job,
8972 upsert=True,
8973 fail_on_empty=False,
8974 )
8975
8976 """
8977 step = "instantiated at VCA"
8978 self.logger.debug(logging_text + step)
8979
8980 self._write_configuration_status(
8981 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8982 )
8983
8984 except Exception as e: # TODO not use Exception but N2VC exception
8985 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8986 if not isinstance(
8987 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8988 ):
8989 self.logger.error(
8990 "Exception while {} : {}".format(step, e), exc_info=True
8991 )
8992 self._write_configuration_status(
8993 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8994 )
8995 raise LcmException("{} {}".format(step, e)) from e
8996
8997 async def _wait_heal_ro(
8998 self,
8999 nsr_id,
9000 timeout=600,
9001 ):
9002 start_time = time()
9003 while time() <= start_time + timeout:
9004 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009005 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9006 "operational-status"
9007 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009008 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9009 if operational_status_ro != "healing":
9010 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009011 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009012 else: # timeout_ns_deploy
9013 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309014
9015 async def vertical_scale(self, nsr_id, nslcmop_id):
9016 """
9017 Vertical Scale the VDUs in a NS
9018
9019 :param: nsr_id: NS Instance ID
9020 :param: nslcmop_id: nslcmop ID of migrate
9021
9022 """
govindarajul4ff4b512022-05-02 20:02:41 +05309023 logging_text = "Task ns={} vertical scale ".format(nsr_id)
Rahul Kumarad400e42024-05-24 14:41:41 +05309024 self.logger.info(logging_text + "Enter")
9025 stage = ["Preparing the environment", ""]
govindarajul4ff4b512022-05-02 20:02:41 +05309026 # get all needed from database
9027 db_nslcmop = None
govindarajul4ff4b512022-05-02 20:02:41 +05309028 db_nsr_update = {}
9029 target = {}
9030 exc = None
9031 # in case of error, indicates what part of scale was failed to put nsr at error status
9032 start_deploy = time()
9033
9034 try:
Rahul Kumarad400e42024-05-24 14:41:41 +05309035 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9036 operationParams = db_nslcmop.get("operationParams")
9037 vertical_scale_data = operationParams["verticalScaleVnf"]
9038 vnfd_id = vertical_scale_data["vnfdId"]
9039 count_index = vertical_scale_data["countIndex"]
9040 vdu_id_ref = vertical_scale_data["vduId"]
9041 vnfr_id = vertical_scale_data["vnfInstanceId"]
9042 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9043 db_flavor = db_nsr.get("flavor")
9044 db_flavor_index = str(len(db_flavor))
9045
9046 def set_flavor_refrence_to_vdur(diff=0):
9047 """
9048 Utility function to add and remove the
9049 ref to new ns-flavor-id to vdurs
9050 :param: diff: default 0
9051 """
9052 q_filter = {}
9053 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
9054 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9055 if (
9056 vdur.get("count-index") == count_index
9057 and vdur.get("vdu-id-ref") == vdu_id_ref
9058 ):
9059 filter_text = {
9060 "_id": vnfr_id,
9061 "vdur.count-index": count_index,
9062 "vdur.vdu-id-ref": vdu_id_ref,
9063 }
9064 q_filter.update(filter_text)
9065 db_update = {}
9066 db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
9067 int(db_flavor_index) - diff
9068 )
9069 self.db.set_one(
9070 "vnfrs",
9071 q_filter=q_filter,
9072 update_dict=db_update,
9073 fail_on_empty=True,
9074 )
9075
govindarajul4ff4b512022-05-02 20:02:41 +05309076 # wait for any previous tasks in process
Rahul Kumarad400e42024-05-24 14:41:41 +05309077 stage[1] = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009078 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309079
9080 self._write_ns_status(
9081 nsr_id=nsr_id,
9082 ns_state=None,
Rahul Kumarad400e42024-05-24 14:41:41 +05309083 current_operation="VERTICALSCALE",
preethika.p28b0bf82022-09-23 07:36:28 +00009084 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309085 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309086 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
preethika.p28b0bf82022-09-23 07:36:28 +00009087 self.logger.debug(
Rahul Kumarad400e42024-05-24 14:41:41 +05309088 stage[1] + " after having waited for previous tasks to be completed"
preethika.p28b0bf82022-09-23 07:36:28 +00009089 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309090 self.update_db_2("nsrs", nsr_id, db_nsr_update)
9091 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
9092 virtual_compute = vnfd["virtual-compute-desc"][0]
9093 virtual_memory = round(
9094 float(virtual_compute["virtual-memory"]["size"]) * 1024
9095 )
9096 virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
9097 virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009098 flavor_dict_update = {
9099 "id": db_flavor_index,
Rahul Kumarad400e42024-05-24 14:41:41 +05309100 "memory-mb": virtual_memory,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009101 "name": f"{vdu_id_ref}-{count_index}-flv",
Rahul Kumarad400e42024-05-24 14:41:41 +05309102 "storage-gb": str(virtual_storage),
9103 "vcpu-count": virtual_cpu,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009104 }
9105 db_flavor.append(flavor_dict_update)
9106 db_update = {}
9107 db_update["flavor"] = db_flavor
Rahul Kumarad400e42024-05-24 14:41:41 +05309108 q_filter = {
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009109 "_id": nsr_id,
9110 }
Rahul Kumarad400e42024-05-24 14:41:41 +05309111 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009112 self.db.set_one(
9113 "nsrs",
Rahul Kumarad400e42024-05-24 14:41:41 +05309114 q_filter=q_filter,
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009115 update_dict=db_update,
9116 fail_on_empty=True,
9117 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309118 set_flavor_refrence_to_vdur()
govindarajul4ff4b512022-05-02 20:02:41 +05309119 target = {}
Rahul Kumarad400e42024-05-24 14:41:41 +05309120 new_operationParams = {
9121 "lcmOperationType": "verticalscale",
9122 "verticalScale": "CHANGE_VNFFLAVOR",
9123 "nsInstanceId": nsr_id,
9124 "changeVnfFlavorData": {
9125 "vnfInstanceId": vnfr_id,
9126 "additionalParams": {
9127 "vduid": vdu_id_ref,
9128 "vduCountIndex": count_index,
9129 "virtualMemory": virtual_memory,
9130 "numVirtualCpu": int(virtual_cpu),
9131 "sizeOfStorage": int(virtual_storage),
9132 },
9133 },
9134 }
9135 target.update(new_operationParams)
9136
9137 stage[1] = "Sending vertical scale request to RO... {}".format(target)
9138 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
9139 self.logger.info("RO target > {}".format(target))
govindarajul4ff4b512022-05-02 20:02:41 +05309140 desc = await self.RO.vertical_scale(nsr_id, target)
Rahul Kumarad400e42024-05-24 14:41:41 +05309141 self.logger.info("RO.vertical_scale return value - {}".format(desc))
govindarajul4ff4b512022-05-02 20:02:41 +05309142 action_id = desc["action_id"]
9143 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009144 nsr_id,
9145 action_id,
9146 nslcmop_id,
9147 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009148 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009149 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309150 )
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009151 except (
9152 NgRoException,
9153 ROclient.ROClientException,
9154 DbException,
9155 LcmException,
9156 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309157 self.logger.error("Exit Exception {}".format(e))
9158 exc = e
9159 except asyncio.CancelledError:
Rahul Kumarad400e42024-05-24 14:41:41 +05309160 self.logger.error("Cancelled Exception while '{}'".format(stage))
govindarajul4ff4b512022-05-02 20:02:41 +05309161 exc = "Operation was cancelled"
9162 except Exception as e:
9163 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009164 self.logger.critical(
9165 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9166 )
govindarajul4ff4b512022-05-02 20:02:41 +05309167 finally:
govindarajul4ff4b512022-05-02 20:02:41 +05309168 if exc:
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009169 self.logger.critical(
Rahul Kumarad400e42024-05-24 14:41:41 +05309170 "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009171 )
9172 self.db.set_one(
Rahul Kumarad400e42024-05-24 14:41:41 +05309173 "nsrs",
9174 {"_id": nsr_id},
9175 None,
9176 pull={"flavor": {"id": db_flavor_index}},
Rahul Kumar8f6b0e72023-11-08 05:15:07 +00009177 )
Rahul Kumarad400e42024-05-24 14:41:41 +05309178 set_flavor_refrence_to_vdur(diff=1)
9179 return "FAILED", "Error in verticalscale VNF {}".format(exc)
9180 else:
9181 return "COMPLETED", "Done"