blob: 0f7ab269c80b3f015fa8477d9752ae562ac0b143 [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
rahul91dcb0a2023-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,
57 LcmExceptionNoMgmtIP,
58 LcmBase,
59 deep_get,
60 get_iterable,
61 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030062 check_juju_bundle_existence,
63 get_charm_artifact_path,
Gabriel Cubae539a8d2022-10-10 11:34:51 -050064 get_ee_id_parts,
Gabriel Cubac7737442023-02-14 13:09:18 -050065 vld_to_ro_ip_profile,
garciadeblas5697b8b2021-03-24 09:17:02 +010066)
David Garciab4ebcd02021-10-28 02:00:43 +020067from osm_lcm.data_utils.nsd import (
68 get_ns_configuration_relation_list,
69 get_vnf_profile,
70 get_vnf_profiles,
71)
garciadeblas5697b8b2021-03-24 09:17:02 +010072from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020073 get_kdu,
74 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020075 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010076 get_vdu_list,
77 get_vdu_profile,
78 get_ee_sorted_initial_config_primitive_list,
79 get_ee_sorted_terminate_config_primitive_list,
80 get_kdu_list,
81 get_virtual_link_profiles,
82 get_vdu,
83 get_configuration,
84 get_vdu_index,
85 get_scaling_aspect,
86 get_number_of_instances,
87 get_juju_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020088 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030089 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050090 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010091)
bravof922c4172020-11-24 21:21:43 -030092from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030093from osm_lcm.data_utils.vnfr import (
94 get_osm_params,
95 get_vdur_index,
96 get_kdur,
97 get_volumes_from_instantiation_params,
98)
bravof922c4172020-11-24 21:21:43 -030099from osm_lcm.data_utils.dict_utils import parse_yaml_strings
100from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +0200101from n2vc.definitions import RelationEndpoint
calvinosanch9f9c6f22019-11-04 13:37:39 +0100102from n2vc.k8s_helm_conn import K8sHelmConnector
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000103from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -0500104from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200105
tierno27246d82018-09-27 15:59:09 +0200106from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200107from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200108
bravof922c4172020-11-24 21:21:43 -0300109from osm_lcm.data_utils.database.database import Database
110from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000111from osm_lcm.data_utils.wim import (
112 get_sdn_ports,
113 get_target_wim_attrs,
114 select_feasible_wim_account,
115)
bravof922c4172020-11-24 21:21:43 -0300116
quilesj7e13aeb2019-10-08 13:34:55 +0200117from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000118from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200119
tierno588547c2020-07-01 15:30:20 +0000120from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200121from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400122from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000123
tierno27246d82018-09-27 15:59:09 +0200124from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200125from time import time
tierno27246d82018-09-27 15:59:09 +0200126from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000127
k4.rahulcf47a3b2023-04-27 12:08:48 +0530128from random import SystemRandom
tierno59d22d22018-09-25 18:10:19 +0200129
tierno69f0d382020-05-07 13:08:09 +0000130__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200131
132
133class NsLcm(LcmBase):
kuuseac3a8882019-10-03 10:48:06 +0200134 SUBOPERATION_STATUS_NOT_FOUND = -1
135 SUBOPERATION_STATUS_NEW = -2
136 SUBOPERATION_STATUS_SKIP = -3
Gabriel Cubaeb585dd2023-04-25 16:48:41 -0500137 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000138 task_name_deploy_vca = "Deploying VCA"
garciadeblas9148fa82023-05-30 12:51:14 +0200139 rel_operation_types = {
140 "GE": ">=",
141 "LE": "<=",
142 "GT": ">",
143 "LT": "<",
144 "EQ": "==",
145 "NE": "!=",
146 }
kuuseac3a8882019-10-03 10:48:06 +0200147
Gabriel Cubae7898982023-05-11 01:57:21 -0500148 def __init__(self, msg, lcm_tasks, config: LcmCfg):
tierno59d22d22018-09-25 18:10:19 +0200149 """
150 Init, Connect to database, filesystem storage, and messaging
151 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
152 :return: None
153 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100154 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200155
bravof922c4172020-11-24 21:21:43 -0300156 self.db = Database().instance.db
157 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200158 self.lcm_tasks = lcm_tasks
Luis Vegaa27dc532022-11-11 20:10:49 +0000159 self.timeout = config.timeout
160 self.ro_config = config.RO
161 self.vca_config = config.VCA
tierno59d22d22018-09-25 18:10:19 +0200162
quilesj7e13aeb2019-10-08 13:34:55 +0200163 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100164 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200165 log=self.logger,
bravof922c4172020-11-24 21:21:43 -0300166 on_update_db=self._on_update_n2vc_db,
167 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100168 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200169 )
quilesj7e13aeb2019-10-08 13:34:55 +0200170
tierno588547c2020-07-01 15:30:20 +0000171 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000172 log=self.logger,
tierno588547c2020-07-01 15:30:20 +0000173 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100174 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000175 )
176
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000177 self.k8sclusterhelm2 = K8sHelmConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000178 kubectl_command=self.vca_config.kubectlpath,
179 helm_command=self.vca_config.helmpath,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100180 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100181 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300182 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100183 db=self.db,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100184 )
185
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000186 self.k8sclusterhelm3 = K8sHelm3Connector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000187 kubectl_command=self.vca_config.kubectlpath,
188 helm_command=self.vca_config.helm3path,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000189 fs=self.fs,
190 log=self.logger,
191 db=self.db,
192 on_update_db=None,
193 )
194
Adam Israelbaacc302019-12-01 12:41:39 -0500195 self.k8sclusterjuju = K8sJujuConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000196 kubectl_command=self.vca_config.kubectlpath,
197 juju_command=self.vca_config.jujupath,
Adam Israelbaacc302019-12-01 12:41:39 -0500198 log=self.logger,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530199 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300200 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100201 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500202 )
203
tiernoa2143262020-03-27 16:20:40 +0000204 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000205 "helm-chart": self.k8sclusterhelm2,
206 "helm-chart-v3": self.k8sclusterhelm3,
207 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000208 "juju-bundle": self.k8sclusterjuju,
209 "juju": self.k8sclusterjuju,
210 }
tierno588547c2020-07-01 15:30:20 +0000211
212 self.vca_map = {
213 "lxc_proxy_charm": self.n2vc,
214 "native_charm": self.n2vc,
215 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000216 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100217 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000218 }
219
quilesj7e13aeb2019-10-08 13:34:55 +0200220 # create RO client
Gabriel Cubae7898982023-05-11 01:57:21 -0500221 self.RO = NgRoClient(**self.ro_config.to_dict())
tierno59d22d22018-09-25 18:10:19 +0200222
garciadeblas07f4e4c2022-06-09 09:42:58 +0200223 self.op_status_map = {
224 "instantiation": self.RO.status,
225 "termination": self.RO.status,
226 "migrate": self.RO.status,
227 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000228 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000229 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200230 }
231
tierno2357f4e2020-10-19 16:38:59 +0000232 @staticmethod
233 def increment_ip_mac(ip_mac, vm_index=1):
234 if not isinstance(ip_mac, str):
235 return ip_mac
236 try:
rahul91dcb0a2023-08-30 14:48:01 +0530237 next_ipv6 = None
238 next_ipv4 = None
239 dual_ip = ip_mac.split(";")
240 if len(dual_ip) == 2:
241 for ip in dual_ip:
242 if ipaddress.ip_address(ip).version == 6:
243 ipv6 = ipaddress.IPv6Address(ip)
244 next_ipv6 = str(ipaddress.IPv6Address(int(ipv6) + 1))
245 elif ipaddress.ip_address(ip).version == 4:
246 ipv4 = ipaddress.IPv4Address(ip)
247 next_ipv4 = str(ipaddress.IPv4Address(int(ipv4) + 1))
248 return [next_ipv4, next_ipv6]
tierno2357f4e2020-10-19 16:38:59 +0000249 # try with ipv4 look for last dot
250 i = ip_mac.rfind(".")
251 if i > 0:
252 i += 1
253 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
254 # try with ipv6 or mac look for last colon. Operate in hex
255 i = ip_mac.rfind(":")
256 if i > 0:
257 i += 1
258 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100259 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
260 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
261 )
tierno2357f4e2020-10-19 16:38:59 +0000262 except Exception:
263 pass
264 return None
265
quilesj3655ae02019-12-12 16:08:35 +0000266 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj3655ae02019-12-12 16:08:35 +0000267 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
268
269 try:
270 # TODO filter RO descriptor fields...
271
272 # write to database
273 db_dict = dict()
274 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
garciadeblas5697b8b2021-03-24 09:17:02 +0100275 db_dict["deploymentStatus"] = ro_descriptor
quilesj3655ae02019-12-12 16:08:35 +0000276 self.update_db_2("nsrs", nsrs_id, db_dict)
277
278 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100279 self.logger.warn(
280 "Cannot write database RO deployment for ns={} -> {}".format(nsrs_id, e)
281 )
quilesj3655ae02019-12-12 16:08:35 +0000282
David Garciac1fe90a2021-03-31 19:12:02 +0200283 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000284 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100285 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000286 path = path[:-1]
287
quilesj3655ae02019-12-12 16:08:35 +0000288 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
289 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000290 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100291 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000292
293 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100294 nsr = self.db.get_one(table="nsrs", q_filter=filter)
295 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000296
297 # get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100298 status_dict = await self.n2vc.get_status(
299 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
300 )
quilesj3655ae02019-12-12 16:08:35 +0000301
302 # vcaStatus
303 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100304 db_dict["vcaStatus"] = status_dict
quilesj3655ae02019-12-12 16:08:35 +0000305
306 # update configurationStatus for this VCA
307 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100308 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000309
garciadeblas5697b8b2021-03-24 09:17:02 +0100310 vca_list = deep_get(
311 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
312 )
313 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000314
garciadeblas5697b8b2021-03-24 09:17:02 +0100315 configuration_status_list = nsr.get("configurationStatus")
316 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000317
garciadeblas5697b8b2021-03-24 09:17:02 +0100318 if config_status == "BROKEN" and vca_status != "failed":
319 db_dict["configurationStatus"][vca_index] = "READY"
320 elif config_status != "BROKEN" and vca_status == "failed":
321 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000322 except Exception as e:
323 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100324 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000325
326 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
327 # if nsState = 'DEGRADED' check if all is OK
328 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100329 if current_ns_status in ("READY", "DEGRADED"):
330 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000331 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100332 if status_dict.get("machines"):
333 for machine_id in status_dict.get("machines"):
334 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000335 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100336 if machine.get("agent-status"):
337 s = machine.get("agent-status").get("status")
338 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000339 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100340 error_description += (
341 "machine {} agent-status={} ; ".format(
342 machine_id, s
343 )
344 )
quilesj3655ae02019-12-12 16:08:35 +0000345 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100346 if machine.get("instance-status"):
347 s = machine.get("instance-status").get("status")
348 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000349 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100350 error_description += (
351 "machine {} instance-status={} ; ".format(
352 machine_id, s
353 )
354 )
quilesj3655ae02019-12-12 16:08:35 +0000355 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100356 if status_dict.get("applications"):
357 for app_id in status_dict.get("applications"):
358 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000359 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100360 if app.get("status"):
361 s = app.get("status").get("status")
362 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000363 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100364 error_description += (
365 "application {} status={} ; ".format(app_id, s)
366 )
quilesj3655ae02019-12-12 16:08:35 +0000367
368 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100369 db_dict["errorDescription"] = error_description
370 if current_ns_status == "READY" and is_degraded:
371 db_dict["nsState"] = "DEGRADED"
372 if current_ns_status == "DEGRADED" and not is_degraded:
373 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000374
375 # write to database
376 self.update_db_2("nsrs", nsr_id, db_dict)
377
tierno51183952020-04-03 15:48:18 +0000378 except (asyncio.CancelledError, asyncio.TimeoutError):
379 raise
quilesj3655ae02019-12-12 16:08:35 +0000380 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100381 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200382
garciadeblas5697b8b2021-03-24 09:17:02 +0100383 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100384 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100385 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530386 """
387 Updating vca status in NSR record
388 :param cluster_uuid: UUID of a k8s cluster
389 :param kdu_instance: The unique name of the KDU instance
390 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100391 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530392 :return: none
393 """
394
395 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
396 # .format(cluster_uuid, kdu_instance, filter))
397
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100398 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530399 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100400 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
401 cluster_uuid=cluster_uuid,
402 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200403 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100404 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200405 vca_id=vca_id,
406 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100407
ksaikiranr656b6dd2021-02-19 10:25:18 +0530408 # vcaStatus
409 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100410 db_dict["vcaStatus"] = {nsr_id: vca_status}
ksaikiranr656b6dd2021-02-19 10:25:18 +0530411
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100412 self.logger.debug(
413 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200414 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530415
416 # write to database
417 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530418 except (asyncio.CancelledError, asyncio.TimeoutError):
419 raise
420 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100421 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530422
tierno72ef84f2020-10-06 08:22:07 +0000423 @staticmethod
424 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
425 try:
garciadeblasef91e082022-08-02 15:12:18 +0200426 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000427 undefined=StrictUndefined,
428 autoescape=select_autoescape(default_for_string=True, default=True),
429 )
tierno72ef84f2020-10-06 08:22:07 +0000430 template = env.from_string(cloud_init_text)
431 return template.render(additional_params or {})
432 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100433 raise LcmException(
434 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
435 "file, must be provided in the instantiation parameters inside the "
436 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
437 )
tierno72ef84f2020-10-06 08:22:07 +0000438 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100439 raise LcmException(
440 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
441 vnfd_id, vdu_id, e
442 )
443 )
tierno72ef84f2020-10-06 08:22:07 +0000444
bravof922c4172020-11-24 21:21:43 -0300445 def _get_vdu_cloud_init_content(self, vdu, vnfd):
446 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000447 try:
tierno72ef84f2020-10-06 08:22:07 +0000448 if vdu.get("cloud-init-file"):
449 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300450 if base_folder["pkg-dir"]:
451 cloud_init_file = "{}/{}/cloud_init/{}".format(
452 base_folder["folder"],
453 base_folder["pkg-dir"],
454 vdu["cloud-init-file"],
455 )
456 else:
457 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
458 base_folder["folder"],
459 vdu["cloud-init-file"],
460 )
tierno72ef84f2020-10-06 08:22:07 +0000461 with self.fs.file_open(cloud_init_file, "r") as ci_file:
462 cloud_init_content = ci_file.read()
463 elif vdu.get("cloud-init"):
464 cloud_init_content = vdu["cloud-init"]
465
466 return cloud_init_content
467 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100468 raise LcmException(
469 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
470 vnfd["id"], vdu["id"], cloud_init_file, e
471 )
472 )
tierno72ef84f2020-10-06 08:22:07 +0000473
tierno72ef84f2020-10-06 08:22:07 +0000474 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100475 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300476 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100477 )
tierno72ef84f2020-10-06 08:22:07 +0000478 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300479 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000480
gcalvino35be9152018-12-20 09:33:12 +0100481 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200482 """
483 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
484 :param vnfd: input vnfd
485 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000486 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100487 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200488 :return: copy of vnfd
489 """
tierno72ef84f2020-10-06 08:22:07 +0000490 vnfd_RO = deepcopy(vnfd)
491 # remove unused by RO configuration, monitoring, scaling and internal keys
492 vnfd_RO.pop("_id", None)
493 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000494 vnfd_RO.pop("monitoring-param", None)
495 vnfd_RO.pop("scaling-group-descriptor", None)
496 vnfd_RO.pop("kdu", None)
497 vnfd_RO.pop("k8s-cluster", None)
498 if new_id:
499 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000500
tierno72ef84f2020-10-06 08:22:07 +0000501 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
502 for vdu in get_iterable(vnfd_RO, "vdu"):
503 vdu.pop("cloud-init-file", None)
504 vdu.pop("cloud-init", None)
505 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200506
tierno2357f4e2020-10-19 16:38:59 +0000507 @staticmethod
508 def ip_profile_2_RO(ip_profile):
509 RO_ip_profile = deepcopy(ip_profile)
510 if "dns-server" in RO_ip_profile:
511 if isinstance(RO_ip_profile["dns-server"], list):
512 RO_ip_profile["dns-address"] = []
513 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100514 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000515 else:
516 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
517 if RO_ip_profile.get("ip-version") == "ipv4":
518 RO_ip_profile["ip-version"] = "IPv4"
519 if RO_ip_profile.get("ip-version") == "ipv6":
520 RO_ip_profile["ip-version"] = "IPv6"
521 if "dhcp-params" in RO_ip_profile:
522 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
523 return RO_ip_profile
524
bravof922c4172020-11-24 21:21:43 -0300525 def _get_ro_vim_id_for_vim_account(self, vim_account):
526 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
527 if db_vim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100528 raise LcmException(
529 "VIM={} is not available. operationalState={}".format(
530 vim_account, db_vim["_admin"]["operationalState"]
531 )
532 )
bravof922c4172020-11-24 21:21:43 -0300533 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
534 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200535
bravof922c4172020-11-24 21:21:43 -0300536 def get_ro_wim_id_for_wim_account(self, wim_account):
537 if isinstance(wim_account, str):
538 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
539 if db_wim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100540 raise LcmException(
541 "WIM={} is not available. operationalState={}".format(
542 wim_account, db_wim["_admin"]["operationalState"]
543 )
544 )
bravof922c4172020-11-24 21:21:43 -0300545 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
546 return RO_wim_id
547 else:
548 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200549
tierno2357f4e2020-10-19 16:38:59 +0000550 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000551 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000552 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000553 db_update = {"_admin.modified": time()}
554 if vdu_create:
555 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100556 vdur = next(
557 (
558 vdur
559 for vdur in reversed(db_vnfr["vdur"])
560 if vdur["vdu-id-ref"] == vdu_id
561 ),
562 None,
563 )
tierno2357f4e2020-10-19 16:38:59 +0000564 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000565 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300566 self.logger.debug(
567 "No vdur in the database. Using the vdur-template to scale"
568 )
vegall8d625f12022-03-22 16:23:30 +0000569 vdur_template = db_vnfr.get("vdur-template")
570 if not vdur_template:
571 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300572 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
573 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000574 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100575 )
vegall8d625f12022-03-22 16:23:30 +0000576 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300577 # Delete a template from the database after using it
578 self.db.set_one(
579 "vnfrs",
580 {"_id": db_vnfr["_id"]},
581 None,
582 pull={"vdur-template": {"_id": vdur["_id"]}},
583 )
tierno2357f4e2020-10-19 16:38:59 +0000584 for count in range(vdu_count):
585 vdur_copy = deepcopy(vdur)
586 vdur_copy["status"] = "BUILD"
587 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100588 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000589 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000590 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100591 vdur_copy["id"] = "{}-{}".format(
592 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
593 )
tierno2357f4e2020-10-19 16:38:59 +0000594 vdur_copy.pop("vim_info", None)
595 for iface in vdur_copy["interfaces"]:
596 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100597 iface["ip-address"] = self.increment_ip_mac(
598 iface["ip-address"], count + 1
599 )
tierno2357f4e2020-10-19 16:38:59 +0000600 else:
601 iface.pop("ip-address", None)
602 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100603 iface["mac-address"] = self.increment_ip_mac(
604 iface["mac-address"], count + 1
605 )
tierno2357f4e2020-10-19 16:38:59 +0000606 else:
607 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000608 if db_vnfr["vdur"]:
609 iface.pop(
610 "mgmt_vnf", None
611 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000612 db_vdu_push_list.append(vdur_copy)
613 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200614 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000615 if len(db_vnfr["vdur"]) == 1:
616 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300617 self.logger.debug(
618 "Scaling to 0 !, creating the template with the last vdur"
619 )
vegall8d625f12022-03-22 16:23:30 +0000620 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000621 for vdu_id, vdu_count in vdu_delete.items():
622 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100623 indexes_to_delete = [
624 iv[0]
625 for iv in enumerate(db_vnfr["vdur"])
626 if iv[1]["vdu-id-ref"] == vdu_id
627 ]
628 db_update.update(
629 {
630 "vdur.{}.status".format(i): "DELETING"
631 for i in indexes_to_delete[-vdu_count:]
632 }
633 )
tierno2357f4e2020-10-19 16:38:59 +0000634 else:
635 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100636 vdus_to_delete = [
637 v
638 for v in reversed(db_vnfr["vdur"])
639 if v["vdu-id-ref"] == vdu_id
640 ]
tierno2357f4e2020-10-19 16:38:59 +0000641 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100642 self.db.set_one(
643 "vnfrs",
644 {"_id": db_vnfr["_id"]},
645 None,
646 pull={"vdur": {"_id": vdu["_id"]}},
647 )
vegall8d625f12022-03-22 16:23:30 +0000648 db_push = {}
649 if db_vdu_push_list:
650 db_push["vdur"] = db_vdu_push_list
651 if template_vdur:
652 db_push["vdur-template"] = template_vdur
653 if not db_push:
654 db_push = None
655 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000656 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
657 # modify passed dictionary db_vnfr
658 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
659 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200660
tiernof578e552018-11-08 19:07:20 +0100661 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
662 """
663 Updates database nsr with the RO info for the created vld
664 :param ns_update_nsr: dictionary to be filled with the updated info
665 :param db_nsr: content of db_nsr. This is also modified
666 :param nsr_desc_RO: nsr descriptor from RO
667 :return: Nothing, LcmException is raised on errors
668 """
669
670 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
671 for net_RO in get_iterable(nsr_desc_RO, "nets"):
672 if vld["id"] != net_RO.get("ns_net_osm_id"):
673 continue
674 vld["vim-id"] = net_RO.get("vim_net_id")
675 vld["name"] = net_RO.get("vim_name")
676 vld["status"] = net_RO.get("status")
677 vld["status-detailed"] = net_RO.get("error_msg")
678 ns_update_nsr["vld.{}".format(vld_index)] = vld
679 break
680 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100681 raise LcmException(
682 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
683 )
tiernof578e552018-11-08 19:07:20 +0100684
tiernoe876f672020-02-13 14:34:48 +0000685 def set_vnfr_at_error(self, db_vnfrs, error_text):
686 try:
687 for db_vnfr in db_vnfrs.values():
688 vnfr_update = {"status": "ERROR"}
689 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
690 if "status" not in vdur:
691 vdur["status"] = "ERROR"
692 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
693 if error_text:
694 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100695 vnfr_update[
696 "vdur.{}.status-detailed".format(vdu_index)
697 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000698 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
699 except DbException as e:
700 self.logger.error("Cannot update vnf. {}".format(e))
701
tierno59d22d22018-09-25 18:10:19 +0200702 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
703 """
704 Updates database vnfr with the RO info, e.g. ip_address, vim_id... Descriptor db_vnfrs is also updated
tierno27246d82018-09-27 15:59:09 +0200705 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
706 :param nsr_desc_RO: nsr descriptor from RO
707 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200708 """
709 for vnf_index, db_vnfr in db_vnfrs.items():
710 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200711 if vnf_RO["member_vnf_index"] != vnf_index:
712 continue
713 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100714 if vnf_RO.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100715 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO[
716 "ip_address"
717 ].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100718 elif not db_vnfr.get("ip-address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100719 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
720 raise LcmExceptionNoMgmtIP(
721 "ns member_vnf_index '{}' has no IP address".format(
722 vnf_index
723 )
724 )
tierno59d22d22018-09-25 18:10:19 +0200725
tierno27246d82018-09-27 15:59:09 +0200726 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
727 vdur_RO_count_index = 0
728 if vdur.get("pdu-type"):
729 continue
730 for vdur_RO in get_iterable(vnf_RO, "vms"):
731 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
732 continue
733 if vdur["count-index"] != vdur_RO_count_index:
734 vdur_RO_count_index += 1
735 continue
736 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000737 if vdur_RO.get("ip_address"):
738 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000739 else:
740 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200741 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
742 vdur["name"] = vdur_RO.get("vim_name")
743 vdur["status"] = vdur_RO.get("status")
744 vdur["status-detailed"] = vdur_RO.get("error_msg")
745 for ifacer in get_iterable(vdur, "interfaces"):
746 for interface_RO in get_iterable(vdur_RO, "interfaces"):
747 if ifacer["name"] == interface_RO.get("internal_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100748 ifacer["ip-address"] = interface_RO.get(
749 "ip_address"
750 )
751 ifacer["mac-address"] = interface_RO.get(
752 "mac_address"
753 )
tierno27246d82018-09-27 15:59:09 +0200754 break
755 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100756 raise LcmException(
757 "ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
758 "from VIM info".format(
759 vnf_index, vdur["vdu-id-ref"], ifacer["name"]
760 )
761 )
tierno27246d82018-09-27 15:59:09 +0200762 vnfr_update["vdur.{}".format(vdu_index)] = vdur
763 break
764 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100765 raise LcmException(
766 "ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
767 "VIM info".format(
768 vnf_index, vdur["vdu-id-ref"], vdur["count-index"]
769 )
770 )
tiernof578e552018-11-08 19:07:20 +0100771
772 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
773 for net_RO in get_iterable(nsr_desc_RO, "nets"):
774 if vld["id"] != net_RO.get("vnf_net_osm_id"):
775 continue
776 vld["vim-id"] = net_RO.get("vim_net_id")
777 vld["name"] = net_RO.get("vim_name")
778 vld["status"] = net_RO.get("status")
779 vld["status-detailed"] = net_RO.get("error_msg")
780 vnfr_update["vld.{}".format(vld_index)] = vld
781 break
782 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100783 raise LcmException(
784 "ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
785 vnf_index, vld["id"]
786 )
787 )
tiernof578e552018-11-08 19:07:20 +0100788
tierno27246d82018-09-27 15:59:09 +0200789 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
790 break
tierno59d22d22018-09-25 18:10:19 +0200791
792 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100793 raise LcmException(
794 "ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(
795 vnf_index
796 )
797 )
tierno59d22d22018-09-25 18:10:19 +0200798
tierno5ee02052019-12-05 19:55:02 +0000799 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000800 """
801 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000802 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000803 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
804 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
805 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
806 """
tierno5ee02052019-12-05 19:55:02 +0000807 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
808 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000809 mapping = {}
810 ns_config_info = {"osm-config-mapping": mapping}
811 for vca in vca_deployed_list:
812 if not vca["member-vnf-index"]:
813 continue
814 if not vca["vdu_id"]:
815 mapping[vca["member-vnf-index"]] = vca["application"]
816 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100817 mapping[
818 "{}.{}.{}".format(
819 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
820 )
821 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000822 return ns_config_info
823
garciadeblas5697b8b2021-03-24 09:17:02 +0100824 async def _instantiate_ng_ro(
825 self,
826 logging_text,
827 nsr_id,
828 nsd,
829 db_nsr,
830 db_nslcmop,
831 db_vnfrs,
832 db_vnfds,
833 n2vc_key_list,
834 stage,
835 start_deploy,
836 timeout_ns_deploy,
837 ):
tierno2357f4e2020-10-19 16:38:59 +0000838 db_vims = {}
839
840 def get_vim_account(vim_account_id):
841 nonlocal db_vims
842 if vim_account_id in db_vims:
843 return db_vims[vim_account_id]
844 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
845 db_vims[vim_account_id] = db_vim
846 return db_vim
847
848 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100849 def parse_vld_instantiation_params(
850 target_vim, target_vld, vld_params, target_sdn
851 ):
tierno2357f4e2020-10-19 16:38:59 +0000852 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500853 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
854 vld_params["ip-profile"]
855 )
tierno2357f4e2020-10-19 16:38:59 +0000856 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100857 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
858 "provider-network"
859 ]
tierno2357f4e2020-10-19 16:38:59 +0000860 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100861 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
862 "provider-network"
863 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000864
865 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
866 # if wim_account_id is specified in vld_params, validate if it is feasible.
867 wim_account_id, db_wim = select_feasible_wim_account(
868 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
869 )
870
871 if wim_account_id:
872 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
873 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
874 # update vld_params with correct WIM account Id
875 vld_params["wimAccountId"] = wim_account_id
876
877 target_wim = "wim:{}".format(wim_account_id)
878 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
879 sdn_ports = get_sdn_ports(vld_params, db_wim)
880 if len(sdn_ports) > 0:
881 target_vld["vim_info"][target_wim] = target_wim_attrs
882 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
883
884 self.logger.debug(
885 "Target VLD with WIM data: {:s}".format(str(target_vld))
886 )
887
tierno2357f4e2020-10-19 16:38:59 +0000888 for param in ("vim-network-name", "vim-network-id"):
889 if vld_params.get(param):
890 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300891 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300892 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100893 populate_dict(
894 target_vld["vim_info"],
895 (other_target_vim, param.replace("-", "_")),
896 vim_net,
897 )
tierno2357f4e2020-10-19 16:38:59 +0000898 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100899 target_vld["vim_info"][target_vim][
900 param.replace("-", "_")
901 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300902 if vld_params.get("common_id"):
903 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000904
aticig15db6142022-01-24 12:51:26 +0300905 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
906 def update_ns_vld_target(target, ns_params):
907 for vnf_params in ns_params.get("vnf", ()):
908 if vnf_params.get("vimAccountId"):
909 target_vnf = next(
910 (
911 vnfr
912 for vnfr in db_vnfrs.values()
913 if vnf_params["member-vnf-index"]
914 == vnfr["member-vnf-index-ref"]
915 ),
916 None,
917 )
918 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100919 if not vdur:
Pedro Escaleira855b0632023-04-20 15:22:16 +0100920 continue
aticig15db6142022-01-24 12:51:26 +0300921 for a_index, a_vld in enumerate(target["ns"]["vld"]):
922 target_vld = find_in_list(
923 get_iterable(vdur, "interfaces"),
924 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
925 )
aticig84bd9a72022-06-14 03:01:36 +0300926
927 vld_params = find_in_list(
928 get_iterable(ns_params, "vld"),
929 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
930 )
aticig15db6142022-01-24 12:51:26 +0300931 if target_vld:
932 if vnf_params.get("vimAccountId") not in a_vld.get(
933 "vim_info", {}
934 ):
aticig84bd9a72022-06-14 03:01:36 +0300935 target_vim_network_list = [
936 v for _, v in a_vld.get("vim_info").items()
937 ]
938 target_vim_network_name = next(
939 (
940 item.get("vim_network_name", "")
941 for item in target_vim_network_list
942 ),
943 "",
944 )
945
aticig15db6142022-01-24 12:51:26 +0300946 target["ns"]["vld"][a_index].get("vim_info").update(
947 {
948 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300949 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300950 }
951 }
952 )
953
aticig84bd9a72022-06-14 03:01:36 +0300954 if vld_params:
955 for param in ("vim-network-name", "vim-network-id"):
956 if vld_params.get(param) and isinstance(
957 vld_params[param], dict
958 ):
959 for vim, vim_net in vld_params[
960 param
961 ].items():
962 other_target_vim = "vim:" + vim
963 populate_dict(
964 target["ns"]["vld"][a_index].get(
965 "vim_info"
966 ),
967 (
968 other_target_vim,
969 param.replace("-", "_"),
970 ),
971 vim_net,
972 )
973
tierno69f0d382020-05-07 13:08:09 +0000974 nslcmop_id = db_nslcmop["_id"]
975 target = {
976 "name": db_nsr["name"],
977 "ns": {"vld": []},
978 "vnf": [],
979 "image": deepcopy(db_nsr["image"]),
980 "flavor": deepcopy(db_nsr["flavor"]),
981 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000982 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000983 }
984 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000985 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000986 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000987 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000988 if db_nsr.get("shared-volumes"):
989 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
990 for shared_volumes in target["shared-volumes"]:
991 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100992 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100993 target["affinity-or-anti-affinity-group"] = deepcopy(
994 db_nsr["affinity-or-anti-affinity-group"]
995 )
996 for affinity_or_anti_affinity_group in target[
997 "affinity-or-anti-affinity-group"
998 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100999 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +00001000
tierno2357f4e2020-10-19 16:38:59 +00001001 if db_nslcmop.get("lcmOperationType") != "instantiate":
1002 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +01001003 db_nslcmop_instantiate = self.db.get_list(
1004 "nslcmops",
1005 {
1006 "nsInstanceId": db_nslcmop["nsInstanceId"],
1007 "lcmOperationType": "instantiate",
1008 },
1009 )[-1]
tierno2357f4e2020-10-19 16:38:59 +00001010 ns_params = db_nslcmop_instantiate.get("operationParams")
1011 else:
1012 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -03001013 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
1014 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +00001015
1016 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +00001017 for vld_index, vld in enumerate(db_nsr.get("vld")):
1018 target_vim = "vim:{}".format(ns_params["vimAccountId"])
1019 target_vld = {
1020 "id": vld["id"],
1021 "name": vld["name"],
1022 "mgmt-network": vld.get("mgmt-network", False),
1023 "type": vld.get("type"),
1024 "vim_info": {
bravof922c4172020-11-24 21:21:43 -03001025 target_vim: {
1026 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +01001027 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -03001028 }
garciadeblas5697b8b2021-03-24 09:17:02 +01001029 },
tierno2357f4e2020-10-19 16:38:59 +00001030 }
1031 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +00001032 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +00001033 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +03001034 if vim_config := db_vim.get("config"):
1035 if sdnc_id := vim_config.get("sdn-controller"):
1036 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
1037 target_sdn = "sdn:{}".format(sdnc_id)
1038 target_vld["vim_info"][target_sdn] = {
1039 "sdn": True,
1040 "target_vim": target_vim,
1041 "vlds": [sdn_vld],
1042 "type": vld.get("type"),
1043 }
tierno2357f4e2020-10-19 16:38:59 +00001044
bravof922c4172020-11-24 21:21:43 -03001045 nsd_vnf_profiles = get_vnf_profiles(nsd)
1046 for nsd_vnf_profile in nsd_vnf_profiles:
1047 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
1048 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001049 cp2target[
1050 "member_vnf:{}.{}".format(
1051 cp["constituent-cpd-id"][0][
1052 "constituent-base-element-id"
1053 ],
1054 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
1055 )
1056 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +00001057
1058 # check at nsd descriptor, if there is an ip-profile
1059 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +00001060 nsd_vlp = find_in_list(
1061 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001062 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
1063 == vld["id"],
1064 )
1065 if (
1066 nsd_vlp
1067 and nsd_vlp.get("virtual-link-protocol-data")
1068 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1069 ):
Gabriel Cubac7737442023-02-14 13:09:18 -05001070 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +01001071 "l3-protocol-data"
1072 ]
bravof922c4172020-11-24 21:21:43 -03001073
tierno2357f4e2020-10-19 16:38:59 +00001074 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +01001075 vld_instantiation_params = find_in_list(
1076 get_iterable(ns_params, "vld"),
1077 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
1078 )
tierno2357f4e2020-10-19 16:38:59 +00001079 if vld_instantiation_params:
1080 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -03001081 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +00001082 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +03001083 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
1084 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -03001085
tierno69f0d382020-05-07 13:08:09 +00001086 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +01001087 vnfd = find_in_list(
1088 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
1089 )
1090 vnf_params = find_in_list(
1091 get_iterable(ns_params, "vnf"),
1092 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
1093 )
tierno69f0d382020-05-07 13:08:09 +00001094 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +00001095 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +00001096 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +00001097 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +01001098 vnf_cp = find_in_list(
1099 vnfd.get("int-virtual-link-desc", ()),
1100 lambda cpd: cpd.get("id") == vld["id"],
1101 )
tierno69f0d382020-05-07 13:08:09 +00001102 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01001103 ns_cp = "member_vnf:{}.{}".format(
1104 vnfr["member-vnf-index-ref"], vnf_cp["id"]
1105 )
tierno69f0d382020-05-07 13:08:09 +00001106 if cp2target.get(ns_cp):
1107 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -03001108
garciadeblas5697b8b2021-03-24 09:17:02 +01001109 vld["vim_info"] = {
1110 target_vim: {"vim_network_name": vld.get("vim-network-name")}
1111 }
tierno2357f4e2020-10-19 16:38:59 +00001112 # check if this network needs SDN assist
1113 target_sdn = None
1114 if vld.get("pci-interfaces"):
1115 db_vim = get_vim_account(vnfr["vim-account-id"])
1116 sdnc_id = db_vim["config"].get("sdn-controller")
1117 if sdnc_id:
1118 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
1119 target_sdn = "sdn:{}".format(sdnc_id)
1120 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001121 "sdn": True,
1122 "target_vim": target_vim,
1123 "vlds": [sdn_vld],
1124 "type": vld.get("type"),
1125 }
tierno69f0d382020-05-07 13:08:09 +00001126
tierno2357f4e2020-10-19 16:38:59 +00001127 # check at vnfd descriptor, if there is an ip-profile
1128 vld_params = {}
bravof922c4172020-11-24 21:21:43 -03001129 vnfd_vlp = find_in_list(
1130 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001131 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -03001132 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001133 if (
1134 vnfd_vlp
1135 and vnfd_vlp.get("virtual-link-protocol-data")
1136 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1137 ):
Gabriel Cubac7737442023-02-14 13:09:18 -05001138 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +01001139 "l3-protocol-data"
1140 ]
tierno2357f4e2020-10-19 16:38:59 +00001141 # update vld_params with instantiation params
1142 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01001143 vld_instantiation_params = find_in_list(
1144 get_iterable(vnf_params, "internal-vld"),
1145 lambda i_vld: i_vld["name"] == vld["id"],
1146 )
tierno2357f4e2020-10-19 16:38:59 +00001147 if vld_instantiation_params:
1148 vld_params.update(vld_instantiation_params)
1149 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1150
1151 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001152 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001153 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1154 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001155 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001156
bravof922c4172020-11-24 21:21:43 -03001157 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1158
1159 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001160 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1161 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001162 if (
1163 vdu_configuration
1164 and vdu_configuration.get("config-access")
1165 and vdu_configuration.get("config-access").get("ssh-access")
1166 ):
bravof922c4172020-11-24 21:21:43 -03001167 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001168 vdur["ssh-access-required"] = vdu_configuration[
1169 "config-access"
1170 ]["ssh-access"]["required"]
1171 elif (
1172 vnf_configuration
1173 and vnf_configuration.get("config-access")
1174 and vnf_configuration.get("config-access").get("ssh-access")
1175 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1176 ):
bravof922c4172020-11-24 21:21:43 -03001177 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001178 vdur["ssh-access-required"] = vnf_configuration[
1179 "config-access"
1180 ]["ssh-access"]["required"]
1181 elif ssh_keys_instantiation and find_in_list(
1182 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1183 ):
bravof922c4172020-11-24 21:21:43 -03001184 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001185
bravof922c4172020-11-24 21:21:43 -03001186 self.logger.debug("NS > vdur > {}".format(vdur))
1187
1188 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001189 # cloud-init
1190 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001191 vdur["cloud-init"] = "{}:file:{}".format(
1192 vnfd["_id"], vdud.get("cloud-init-file")
1193 )
tierno2357f4e2020-10-19 16:38:59 +00001194 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1195 if vdur["cloud-init"] not in target["cloud_init_content"]:
1196 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001197 if base_folder["pkg-dir"]:
1198 cloud_init_file = "{}/{}/cloud_init/{}".format(
1199 base_folder["folder"],
1200 base_folder["pkg-dir"],
1201 vdud.get("cloud-init-file"),
1202 )
1203 else:
1204 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1205 base_folder["folder"],
1206 vdud.get("cloud-init-file"),
1207 )
tierno2357f4e2020-10-19 16:38:59 +00001208 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001209 target["cloud_init_content"][
1210 vdur["cloud-init"]
1211 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001212 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001213 vdur["cloud-init"] = "{}:vdu:{}".format(
1214 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1215 )
tierno2357f4e2020-10-19 16:38:59 +00001216 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001217 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1218 "cloud-init"
1219 ]
tierno2357f4e2020-10-19 16:38:59 +00001220 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001221 deploy_params_vdu = self._format_additional_params(
1222 vdur.get("additionalParams") or {}
1223 )
1224 deploy_params_vdu["OSM"] = get_osm_params(
1225 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1226 )
tierno2357f4e2020-10-19 16:38:59 +00001227 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001228
1229 # flavor
1230 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001231 if target_vim not in ns_flavor["vim_info"]:
1232 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001233
1234 # deal with images
1235 # in case alternative images are provided we must check if they should be applied
1236 # for the vim_type, modify the vim_type taking into account
1237 ns_image_id = int(vdur["ns-image-id"])
1238 if vdur.get("alt-image-ids"):
1239 db_vim = get_vim_account(vnfr["vim-account-id"])
1240 vim_type = db_vim["vim_type"]
1241 for alt_image_id in vdur.get("alt-image-ids"):
1242 ns_alt_image = target["image"][int(alt_image_id)]
1243 if vim_type == ns_alt_image.get("vim-type"):
1244 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001245 self.logger.debug(
1246 "use alternative image id: {}".format(alt_image_id)
1247 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001248 ns_image_id = alt_image_id
1249 vdur["ns-image-id"] = ns_image_id
1250 break
1251 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001252 if target_vim not in ns_image["vim_info"]:
1253 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001254
Alexis Romero305b5c42022-03-11 15:29:18 +01001255 # Affinity groups
1256 if vdur.get("affinity-or-anti-affinity-group-id"):
1257 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1258 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1259 if target_vim not in ns_ags["vim_info"]:
1260 ns_ags["vim_info"][target_vim] = {}
1261
vegall63162192023-03-06 14:19:16 +00001262 # shared-volumes
1263 if vdur.get("shared-volumes-id"):
1264 for sv_id in vdur["shared-volumes-id"]:
1265 ns_sv = find_in_list(
1266 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1267 )
1268 if ns_sv:
1269 ns_sv["vim_info"][target_vim] = {}
1270
tierno2357f4e2020-10-19 16:38:59 +00001271 vdur["vim_info"] = {target_vim: {}}
1272 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001273 if vnf_params:
1274 vdu_instantiation_params = find_in_list(
1275 get_iterable(vnf_params, "vdu"),
1276 lambda i_vdu: i_vdu["id"] == vdud["id"],
1277 )
1278 if vdu_instantiation_params:
1279 # Parse the vdu_volumes from the instantiation params
1280 vdu_volumes = get_volumes_from_instantiation_params(
1281 vdu_instantiation_params, vdud
1282 )
1283 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001284 vdur["additionalParams"]["OSM"][
1285 "vim_flavor_id"
1286 ] = vdu_instantiation_params.get("vim-flavor-id")
tierno2357f4e2020-10-19 16:38:59 +00001287 vdur_list.append(vdur)
1288 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001289 target["vnf"].append(target_vnf)
1290
garciadeblas07f4e4c2022-06-09 09:42:58 +02001291 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001292 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001293 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001294 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001295 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001296 nsr_id,
1297 action_id,
1298 nslcmop_id,
1299 start_deploy,
1300 timeout_ns_deploy,
1301 stage,
1302 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001303 )
tierno69f0d382020-05-07 13:08:09 +00001304
1305 # Updating NSR
1306 db_nsr_update = {
1307 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001308 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001309 }
1310 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1311 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1312 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001313 self.logger.debug(
1314 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1315 )
tierno69f0d382020-05-07 13:08:09 +00001316 return
1317
garciadeblas5697b8b2021-03-24 09:17:02 +01001318 async def _wait_ng_ro(
1319 self,
1320 nsr_id,
1321 action_id,
1322 nslcmop_id=None,
1323 start_time=None,
1324 timeout=600,
1325 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001326 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001327 ):
tierno69f0d382020-05-07 13:08:09 +00001328 detailed_status_old = None
1329 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001330 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001331 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001332 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001333 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001334 if desc_status["status"] == "FAILED":
1335 raise NgRoException(desc_status["details"])
1336 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001337 if stage:
1338 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001339 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001340 if stage:
1341 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001342 break
1343 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001344 assert False, "ROclient.check_ns_status returns unknown {}".format(
1345 desc_status["status"]
1346 )
tierno2357f4e2020-10-19 16:38:59 +00001347 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001348 detailed_status_old = stage[2]
1349 db_nsr_update["detailed-status"] = " ".join(stage)
1350 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1351 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001352 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001353 else: # timeout_ns_deploy
1354 raise NgRoException("Timeout waiting ns to deploy")
1355
garciadeblas5697b8b2021-03-24 09:17:02 +01001356 async def _terminate_ng_ro(
1357 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1358 ):
tierno69f0d382020-05-07 13:08:09 +00001359 db_nsr_update = {}
1360 failed_detail = []
1361 action_id = None
1362 start_deploy = time()
1363 try:
1364 target = {
1365 "ns": {"vld": []},
1366 "vnf": [],
1367 "image": [],
1368 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001369 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001370 }
1371 desc = await self.RO.deploy(nsr_id, target)
1372 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001373 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001374 self.logger.debug(
1375 logging_text
1376 + "ns terminate action at RO. action_id={}".format(action_id)
1377 )
tierno69f0d382020-05-07 13:08:09 +00001378
1379 # wait until done
1380 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001381 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001382 nsr_id,
1383 action_id,
1384 nslcmop_id,
1385 start_deploy,
1386 delete_timeout,
1387 stage,
1388 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001389 )
tierno69f0d382020-05-07 13:08:09 +00001390 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1391 # delete all nsr
1392 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001393 except NgRoException as e:
1394 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001395 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1396 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001397 self.logger.debug(
1398 logging_text + "RO_action_id={} already deleted".format(action_id)
1399 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001400 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001401 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001402 self.logger.debug(
1403 logging_text
1404 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1405 )
tierno69f0d382020-05-07 13:08:09 +00001406 else:
1407 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001408 self.logger.error(
1409 logging_text
1410 + "RO_action_id={} delete error: {}".format(action_id, e)
1411 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001412 except Exception as e:
1413 failed_detail.append("delete error: {}".format(e))
1414 self.logger.error(
1415 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1416 )
tierno69f0d382020-05-07 13:08:09 +00001417
1418 if failed_detail:
1419 stage[2] = "Error deleting from VIM"
1420 else:
1421 stage[2] = "Deleted from VIM"
1422 db_nsr_update["detailed-status"] = " ".join(stage)
1423 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1424 self._write_op_status(nslcmop_id, stage)
1425
1426 if failed_detail:
1427 raise LcmException("; ".join(failed_detail))
1428 return
1429
garciadeblas5697b8b2021-03-24 09:17:02 +01001430 async def instantiate_RO(
1431 self,
1432 logging_text,
1433 nsr_id,
1434 nsd,
1435 db_nsr,
1436 db_nslcmop,
1437 db_vnfrs,
1438 db_vnfds,
1439 n2vc_key_list,
1440 stage,
1441 ):
tiernoe95ed362020-04-23 08:24:57 +00001442 """
1443 Instantiate at RO
1444 :param logging_text: preffix text to use at logging
1445 :param nsr_id: nsr identity
1446 :param nsd: database content of ns descriptor
1447 :param db_nsr: database content of ns record
1448 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1449 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001450 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001451 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1452 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1453 :return: None or exception
1454 """
tiernoe876f672020-02-13 14:34:48 +00001455 try:
tiernoe876f672020-02-13 14:34:48 +00001456 start_deploy = time()
1457 ns_params = db_nslcmop.get("operationParams")
1458 if ns_params and ns_params.get("timeout_ns_deploy"):
1459 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1460 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001461 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001462
tiernoe876f672020-02-13 14:34:48 +00001463 # Check for and optionally request placement optimization. Database will be updated if placement activated
1464 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001465 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1466 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1467 for vnfr in db_vnfrs.values():
1468 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1469 break
1470 else:
1471 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001472
garciadeblas5697b8b2021-03-24 09:17:02 +01001473 return await self._instantiate_ng_ro(
1474 logging_text,
1475 nsr_id,
1476 nsd,
1477 db_nsr,
1478 db_nslcmop,
1479 db_vnfrs,
1480 db_vnfds,
1481 n2vc_key_list,
1482 stage,
1483 start_deploy,
1484 timeout_ns_deploy,
1485 )
tierno2357f4e2020-10-19 16:38:59 +00001486 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001487 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001488 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001489 self.logger.error(
1490 "Error deploying at VIM {}".format(e),
1491 exc_info=not isinstance(
1492 e,
1493 (
1494 ROclient.ROClientException,
1495 LcmException,
1496 DbException,
1497 NgRoException,
1498 ),
1499 ),
1500 )
tiernoe876f672020-02-13 14:34:48 +00001501 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001502
tierno7ecbc342020-09-21 14:05:39 +00001503 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1504 """
1505 Wait for kdu to be up, get ip address
1506 :param logging_text: prefix use for logging
1507 :param nsr_id:
1508 :param vnfr_id:
1509 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001510 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001511 """
1512
1513 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1514 nb_tries = 0
1515
1516 while nb_tries < 360:
1517 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001518 kdur = next(
1519 (
1520 x
1521 for x in get_iterable(db_vnfr, "kdur")
1522 if x.get("kdu-name") == kdu_name
1523 ),
1524 None,
1525 )
tierno7ecbc342020-09-21 14:05:39 +00001526 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001527 raise LcmException(
1528 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1529 )
tierno7ecbc342020-09-21 14:05:39 +00001530 if kdur.get("status"):
1531 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001532 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001533 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001534 raise LcmException(
1535 "target KDU={} is in error state".format(kdu_name)
1536 )
tierno7ecbc342020-09-21 14:05:39 +00001537
Gabriel Cubae7898982023-05-11 01:57:21 -05001538 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001539 nb_tries += 1
1540 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1541
garciadeblas5697b8b2021-03-24 09:17:02 +01001542 async def wait_vm_up_insert_key_ro(
1543 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1544 ):
tiernoa5088192019-11-26 16:12:53 +00001545 """
1546 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1547 :param logging_text: prefix use for logging
1548 :param nsr_id:
1549 :param vnfr_id:
1550 :param vdu_id:
1551 :param vdu_index:
1552 :param pub_key: public ssh key to inject, None to skip
1553 :param user: user to apply the public ssh key
1554 :return: IP address
1555 """
quilesj7e13aeb2019-10-08 13:34:55 +02001556
tierno2357f4e2020-10-19 16:38:59 +00001557 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001558 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001559 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001560 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001561
tiernod8323042019-08-09 11:32:23 +00001562 while True:
quilesj3149f262019-12-03 10:58:10 +00001563 ro_retries += 1
1564 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001565 raise LcmException(
1566 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1567 )
quilesj3149f262019-12-03 10:58:10 +00001568
Gabriel Cubae7898982023-05-11 01:57:21 -05001569 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001570
1571 # get ip address
tiernod8323042019-08-09 11:32:23 +00001572 if not target_vdu_id:
1573 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001574
1575 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001576 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001577 raise LcmException(
1578 "Cannot inject ssh-key because target VNF is in error state"
1579 )
tiernod8323042019-08-09 11:32:23 +00001580 ip_address = db_vnfr.get("ip-address")
1581 if not ip_address:
1582 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001583 vdur = next(
1584 (
1585 x
1586 for x in get_iterable(db_vnfr, "vdur")
1587 if x.get("ip-address") == ip_address
1588 ),
1589 None,
1590 )
quilesj3149f262019-12-03 10:58:10 +00001591 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001592 vdur = next(
1593 (
1594 x
1595 for x in get_iterable(db_vnfr, "vdur")
1596 if x.get("vdu-id-ref") == vdu_id
1597 and x.get("count-index") == vdu_index
1598 ),
1599 None,
1600 )
quilesj3149f262019-12-03 10:58:10 +00001601
garciadeblas5697b8b2021-03-24 09:17:02 +01001602 if (
1603 not vdur and len(db_vnfr.get("vdur", ())) == 1
1604 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001605 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001606 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001607 raise LcmException(
1608 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1609 vnfr_id, vdu_id, vdu_index
1610 )
1611 )
tierno2357f4e2020-10-19 16:38:59 +00001612 # New generation RO stores information at "vim_info"
1613 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001614 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001615 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001616 target_vim = next(
1617 t for t in vdur["vim_info"]
1618 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001619 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001620 if (
1621 vdur.get("pdu-type")
1622 or vdur.get("status") == "ACTIVE"
1623 or ng_ro_status == "ACTIVE"
1624 ):
quilesj3149f262019-12-03 10:58:10 +00001625 ip_address = vdur.get("ip-address")
1626 if not ip_address:
1627 continue
1628 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001629 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001630 raise LcmException(
1631 "Cannot inject ssh-key because target VM is in error state"
1632 )
quilesj3149f262019-12-03 10:58:10 +00001633
tiernod8323042019-08-09 11:32:23 +00001634 if not target_vdu_id:
1635 continue
tiernod8323042019-08-09 11:32:23 +00001636
quilesj7e13aeb2019-10-08 13:34:55 +02001637 # inject public key into machine
1638 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001639 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001640 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001641 if vdur.get("pdu-type"):
1642 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1643 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001644 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001645 target = {
1646 "action": {
1647 "action": "inject_ssh_key",
1648 "key": pub_key,
1649 "user": user,
1650 },
1651 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1652 }
1653 desc = await self.RO.deploy(nsr_id, target)
1654 action_id = desc["action_id"]
1655 await self._wait_ng_ro(
1656 nsr_id, action_id, timeout=600, operation="instantiation"
1657 )
1658 break
tierno69f0d382020-05-07 13:08:09 +00001659 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001660 raise LcmException(
1661 "Reaching max tries injecting key. Error: {}".format(e)
1662 )
quilesj7e13aeb2019-10-08 13:34:55 +02001663 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001664 break
1665
1666 return ip_address
1667
tierno5ee02052019-12-05 19:55:02 +00001668 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1669 """
1670 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1671 """
1672 my_vca = vca_deployed_list[vca_index]
1673 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001674 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001675 return
1676 timeout = 300
1677 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001678 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1679 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1680 configuration_status_list = db_nsr["configurationStatus"]
1681 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001682 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001683 # myself
tierno5ee02052019-12-05 19:55:02 +00001684 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001685 if not my_vca.get("member-vnf-index") or (
1686 vca_deployed.get("member-vnf-index")
1687 == my_vca.get("member-vnf-index")
1688 ):
quilesj3655ae02019-12-12 16:08:35 +00001689 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001690 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001691 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001692 elif internal_status == "BROKEN":
1693 raise LcmException(
1694 "Configuration aborted because dependent charm/s has failed"
1695 )
quilesj3655ae02019-12-12 16:08:35 +00001696 else:
1697 break
tierno5ee02052019-12-05 19:55:02 +00001698 else:
quilesj3655ae02019-12-12 16:08:35 +00001699 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001700 return
1701 await asyncio.sleep(10)
1702 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001703
1704 raise LcmException("Configuration aborted because dependent charm/s timeout")
1705
David Garciac1fe90a2021-03-31 19:12:02 +02001706 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001707 vca_id = None
1708 if db_vnfr:
1709 vca_id = deep_get(db_vnfr, ("vca-id",))
1710 elif db_nsr:
1711 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1712 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1713 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001714
garciadeblas5697b8b2021-03-24 09:17:02 +01001715 async def instantiate_N2VC(
1716 self,
1717 logging_text,
1718 vca_index,
1719 nsi_id,
1720 db_nsr,
1721 db_vnfr,
1722 vdu_id,
1723 kdu_name,
1724 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001725 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001726 config_descriptor,
1727 deploy_params,
1728 base_folder,
1729 nslcmop_id,
1730 stage,
1731 vca_type,
1732 vca_name,
1733 ee_config_descriptor,
1734 ):
tiernod8323042019-08-09 11:32:23 +00001735 nsr_id = db_nsr["_id"]
1736 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001737 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001738 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001739 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001740 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001741 "collection": "nsrs",
1742 "filter": {"_id": nsr_id},
1743 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001744 }
tiernod8323042019-08-09 11:32:23 +00001745 step = ""
1746 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001747 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001748 element_under_configuration = nsr_id
1749
tiernod8323042019-08-09 11:32:23 +00001750 vnfr_id = None
1751 if db_vnfr:
1752 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001753 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001754
garciadeblas5697b8b2021-03-24 09:17:02 +01001755 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001756
aktas98488ed2021-07-29 17:42:49 +03001757 if vca_type == "native_charm":
1758 index_number = 0
1759 else:
1760 index_number = vdu_index or 0
1761
tiernod8323042019-08-09 11:32:23 +00001762 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001763 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001764 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001765 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001766 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001767 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001768 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001769 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001770 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001771 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001772 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001773 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001774 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001775 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001776
1777 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001778 if base_folder["pkg-dir"]:
1779 artifact_path = "{}/{}/{}/{}".format(
1780 base_folder["folder"],
1781 base_folder["pkg-dir"],
1782 "charms"
aticig15db6142022-01-24 12:51:26 +03001783 if vca_type
1784 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001785 else "helm-charts",
1786 vca_name,
1787 )
1788 else:
1789 artifact_path = "{}/Scripts/{}/{}/".format(
1790 base_folder["folder"],
1791 "charms"
aticig15db6142022-01-24 12:51:26 +03001792 if vca_type
1793 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001794 else "helm-charts",
1795 vca_name,
1796 )
bravof922c4172020-11-24 21:21:43 -03001797
1798 self.logger.debug("Artifact path > {}".format(artifact_path))
1799
tiernoa278b842020-07-08 15:33:55 +00001800 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001801 initial_config_primitive_list = config_descriptor.get(
1802 "initial-config-primitive"
1803 )
tiernoa278b842020-07-08 15:33:55 +00001804
garciadeblas5697b8b2021-03-24 09:17:02 +01001805 self.logger.debug(
1806 "Initial config primitive list > {}".format(
1807 initial_config_primitive_list
1808 )
1809 )
bravof922c4172020-11-24 21:21:43 -03001810
tiernoa278b842020-07-08 15:33:55 +00001811 # add config if not present for NS charm
1812 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001813 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001814 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1815 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1816 )
tiernod8323042019-08-09 11:32:23 +00001817
garciadeblas5697b8b2021-03-24 09:17:02 +01001818 self.logger.debug(
1819 "Initial config primitive list #2 > {}".format(
1820 initial_config_primitive_list
1821 )
1822 )
tierno588547c2020-07-01 15:30:20 +00001823 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001824 # find old ee_id if exists
1825 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001826
David Garciac1fe90a2021-03-31 19:12:02 +02001827 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001828 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001829 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001830 self._write_configuration_status(
1831 nsr_id=nsr_id,
1832 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001833 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001834 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001835 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001836 )
tiernod8323042019-08-09 11:32:23 +00001837
tierno588547c2020-07-01 15:30:20 +00001838 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001839 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001840
1841 ee_id = None
1842 credentials = None
1843 if vca_type == "k8s_proxy_charm":
1844 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001845 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001846 namespace=namespace,
1847 artifact_path=artifact_path,
1848 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001849 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001850 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001851 elif vca_type == "helm" or vca_type == "helm-v3":
1852 ee_id, credentials = await self.vca_map[
1853 vca_type
1854 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001855 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001856 reuse_ee_id=ee_id,
1857 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001858 config=osm_config,
1859 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001860 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001861 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001862 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001863 else:
1864 ee_id, credentials = await self.vca_map[
1865 vca_type
1866 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001867 namespace=namespace,
1868 reuse_ee_id=ee_id,
1869 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001870 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001871 )
quilesj3655ae02019-12-12 16:08:35 +00001872
tierno588547c2020-07-01 15:30:20 +00001873 elif vca_type == "native_charm":
1874 step = "Waiting to VM being up and getting IP address"
1875 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001876 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1877 logging_text,
1878 nsr_id,
1879 vnfr_id,
1880 vdu_id,
1881 vdu_index,
1882 user=None,
1883 pub_key=None,
1884 )
tierno588547c2020-07-01 15:30:20 +00001885 credentials = {"hostname": rw_mgmt_ip}
1886 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001887 username = deep_get(
1888 config_descriptor, ("config-access", "ssh-access", "default-user")
1889 )
tierno588547c2020-07-01 15:30:20 +00001890 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1891 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001892 if not username and initial_config_primitive_list:
1893 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001894 for param in config_primitive.get("parameter", ()):
1895 if param["name"] == "ssh-username":
1896 username = param["value"]
1897 break
1898 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001899 raise LcmException(
1900 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1901 "'config-access.ssh-access.default-user'"
1902 )
tierno588547c2020-07-01 15:30:20 +00001903 credentials["username"] = username
1904 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001905
tierno588547c2020-07-01 15:30:20 +00001906 self._write_configuration_status(
1907 nsr_id=nsr_id,
1908 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001909 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001910 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001911 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001912 )
quilesj3655ae02019-12-12 16:08:35 +00001913
tierno588547c2020-07-01 15:30:20 +00001914 step = "register execution environment {}".format(credentials)
1915 self.logger.debug(logging_text + step)
1916 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001917 credentials=credentials,
1918 namespace=namespace,
1919 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001920 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001921 )
tierno3bedc9b2019-11-27 15:46:57 +00001922
tierno588547c2020-07-01 15:30:20 +00001923 # for compatibility with MON/POL modules, the need model and application name at database
1924 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001925 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001926 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1927 if len(ee_id_parts) >= 2:
1928 model_name = ee_id_parts[0]
1929 application_name = ee_id_parts[1]
1930 db_nsr_update[db_update_entry + "model"] = model_name
1931 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001932
1933 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001934 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001935
tiernoc231a872020-01-21 08:49:05 +00001936 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001937 nsr_id=nsr_id,
1938 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001939 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001940 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001941 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001942 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001943 )
1944
tierno3bedc9b2019-11-27 15:46:57 +00001945 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001946 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001947 config = None
tierno588547c2020-07-01 15:30:20 +00001948 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001949 config_primitive = next(
1950 (p for p in initial_config_primitive_list if p["name"] == "config"),
1951 None,
1952 )
tiernoa278b842020-07-08 15:33:55 +00001953 if config_primitive:
1954 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001955 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001956 )
tierno588547c2020-07-01 15:30:20 +00001957 num_units = 1
1958 if vca_type == "lxc_proxy_charm":
1959 if element_type == "NS":
1960 num_units = db_nsr.get("config-units") or 1
1961 elif element_type == "VNF":
1962 num_units = db_vnfr.get("config-units") or 1
1963 elif element_type == "VDU":
1964 for v in db_vnfr["vdur"]:
1965 if vdu_id == v["vdu-id-ref"]:
1966 num_units = v.get("config-units") or 1
1967 break
David Garciaaae391f2020-11-09 11:12:54 +01001968 if vca_type != "k8s_proxy_charm":
1969 await self.vca_map[vca_type].install_configuration_sw(
1970 ee_id=ee_id,
1971 artifact_path=artifact_path,
1972 db_dict=db_dict,
1973 config=config,
1974 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001975 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001976 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001977 )
quilesj7e13aeb2019-10-08 13:34:55 +02001978
quilesj63f90042020-01-17 09:53:55 +00001979 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001980 self.update_db_2(
1981 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1982 )
quilesj63f90042020-01-17 09:53:55 +00001983
1984 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001985 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001986 logging_text=logging_text,
1987 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001988 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001989 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001990 )
quilesj63f90042020-01-17 09:53:55 +00001991
Patricia Reinosob4312c02023-01-06 22:28:44 +00001992 if not is_relation_added:
1993 raise LcmException("Relations could not be added to VCA.")
1994
quilesj7e13aeb2019-10-08 13:34:55 +02001995 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001996 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001997 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001998 pub_key = None
1999 user = None
tierno588547c2020-07-01 15:30:20 +00002000 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01002001 if deep_get(
2002 config_descriptor, ("config-access", "ssh-access", "required")
2003 ):
tierno588547c2020-07-01 15:30:20 +00002004 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00002005 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01002006 user = deep_get(
2007 config_descriptor,
2008 ("config-access", "ssh-access", "default-user"),
2009 )
tierno3bedc9b2019-11-27 15:46:57 +00002010 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02002011 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01002012 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02002013 )
quilesj7e13aeb2019-10-08 13:34:55 +02002014
garciadeblas5697b8b2021-03-24 09:17:02 +01002015 step = "Insert public key into VM user={} ssh_key={}".format(
2016 user, pub_key
2017 )
tierno3bedc9b2019-11-27 15:46:57 +00002018 else:
tierno588547c2020-07-01 15:30:20 +00002019 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00002020 step = "Waiting to VM being up and getting IP address"
2021 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02002022
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002023 # default rw_mgmt_ip to None, avoiding the non definition of the variable
2024 rw_mgmt_ip = None
2025
tierno3bedc9b2019-11-27 15:46:57 +00002026 # n2vc_redesign STEP 5.1
2027 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00002028 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00002029 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02002030 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01002031 logging_text, nsr_id, vnfr_id, kdu_name
2032 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002033 vnfd = self.db.get_one(
2034 "vnfds_revisions",
2035 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
2036 )
2037 kdu = get_kdu(vnfd, kdu_name)
2038 kdu_services = [
2039 service["name"] for service in get_kdu_services(kdu)
2040 ]
2041 exposed_services = []
2042 for service in services:
2043 if any(s in service["name"] for s in kdu_services):
2044 exposed_services.append(service)
2045 await self.vca_map[vca_type].exec_primitive(
2046 ee_id=ee_id,
2047 primitive_name="config",
2048 params_dict={
2049 "osm-config": json.dumps(
2050 OsmConfigBuilder(
2051 k8s={"services": exposed_services}
2052 ).build()
2053 )
2054 },
2055 vca_id=vca_id,
2056 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002057
2058 # This verification is needed in order to avoid trying to add a public key
2059 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
2060 # for a KNF and not for its KDUs, the previous verification gives False, and the code
2061 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
2062 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00002063 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002064 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2065 logging_text,
2066 nsr_id,
2067 vnfr_id,
2068 vdu_id,
2069 vdu_index,
2070 user=user,
2071 pub_key=pub_key,
2072 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002073
garciadeblas5697b8b2021-03-24 09:17:02 +01002074 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02002075
tiernoa5088192019-11-26 16:12:53 +00002076 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02002077 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00002078
2079 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01002080 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00002081
2082 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00002083 if initial_config_primitive_list:
2084 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00002085
2086 # stage, in function of element type: vdu, kdu, vnf or ns
2087 my_vca = vca_deployed_list[vca_index]
2088 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
2089 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01002090 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00002091 elif my_vca.get("member-vnf-index"):
2092 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01002093 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00002094 else:
2095 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01002096 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00002097
tiernoc231a872020-01-21 08:49:05 +00002098 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002099 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002100 )
2101
garciadeblas5697b8b2021-03-24 09:17:02 +01002102 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002103
tiernoe876f672020-02-13 14:34:48 +00002104 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002105 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002106 # adding information on the vca_deployed if it is a NS execution environment
2107 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002108 deploy_params["ns_config_info"] = json.dumps(
2109 self._get_ns_config_info(nsr_id)
2110 )
tiernod8323042019-08-09 11:32:23 +00002111 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002112 primitive_params_ = self._map_primitive_params(
2113 initial_config_primitive, {}, deploy_params
2114 )
tierno3bedc9b2019-11-27 15:46:57 +00002115
garciadeblas5697b8b2021-03-24 09:17:02 +01002116 step = "execute primitive '{}' params '{}'".format(
2117 initial_config_primitive["name"], primitive_params_
2118 )
tiernod8323042019-08-09 11:32:23 +00002119 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002120 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002121 ee_id=ee_id,
2122 primitive_name=initial_config_primitive["name"],
2123 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002124 db_dict=db_dict,
2125 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002126 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002127 )
tiernoe876f672020-02-13 14:34:48 +00002128 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2129 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002130 if config_descriptor.get("terminate-config-primitive"):
2131 self.update_db_2(
2132 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2133 )
tiernoe876f672020-02-13 14:34:48 +00002134 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002135
tiernod8323042019-08-09 11:32:23 +00002136 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002137
tiernob996d942020-07-03 14:52:28 +00002138 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002139 if vca_type == "helm" or vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02002140 # TODO: review for those cases where the helm chart is a reference and
2141 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002142 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002143 ee_id=ee_id,
2144 artifact_path=artifact_path,
2145 ee_config_descriptor=ee_config_descriptor,
2146 vnfr_id=vnfr_id,
2147 nsr_id=nsr_id,
2148 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002149 element_type=element_type,
2150 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2151 vdu_id=vdu_id,
2152 vdu_index=vdu_index,
2153 kdu_name=kdu_name,
2154 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002155 )
2156 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002157 self.update_db_2(
2158 "nsrs",
2159 nsr_id,
2160 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2161 )
tiernob996d942020-07-03 14:52:28 +00002162
bravof73bac502021-05-11 07:38:47 -04002163 for job in prometheus_jobs:
2164 self.db.set_one(
2165 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002166 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002167 job,
2168 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002169 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002170 )
2171
quilesj7e13aeb2019-10-08 13:34:55 +02002172 step = "instantiated at VCA"
2173 self.logger.debug(logging_text + step)
2174
tiernoc231a872020-01-21 08:49:05 +00002175 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002176 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002177 )
2178
tiernod8323042019-08-09 11:32:23 +00002179 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002180 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002181 if not isinstance(
2182 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2183 ):
2184 self.logger.error(
2185 "Exception while {} : {}".format(step, e), exc_info=True
2186 )
tiernoc231a872020-01-21 08:49:05 +00002187 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002188 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002189 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002190 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002191
garciadeblas5697b8b2021-03-24 09:17:02 +01002192 def _write_ns_status(
2193 self,
2194 nsr_id: str,
2195 ns_state: str,
2196 current_operation: str,
2197 current_operation_id: str,
2198 error_description: str = None,
2199 error_detail: str = None,
2200 other_update: dict = None,
2201 ):
tiernoe876f672020-02-13 14:34:48 +00002202 """
2203 Update db_nsr fields.
2204 :param nsr_id:
2205 :param ns_state:
2206 :param current_operation:
2207 :param current_operation_id:
2208 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002209 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002210 :param other_update: Other required changes at database if provided, will be cleared
2211 :return:
2212 """
quilesj4cda56b2019-12-05 10:02:20 +00002213 try:
tiernoe876f672020-02-13 14:34:48 +00002214 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002215 db_dict[
2216 "_admin.nslcmop"
2217 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002218 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002219 db_dict["_admin.operation-type"] = (
2220 current_operation if current_operation != "IDLE" else None
2221 )
quilesj4cda56b2019-12-05 10:02:20 +00002222 db_dict["currentOperation"] = current_operation
2223 db_dict["currentOperationID"] = current_operation_id
2224 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002225 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002226
2227 if ns_state:
2228 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002229 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002230 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002231 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002232
garciadeblas5697b8b2021-03-24 09:17:02 +01002233 def _write_op_status(
2234 self,
2235 op_id: str,
2236 stage: list = None,
2237 error_message: str = None,
2238 queuePosition: int = 0,
2239 operation_state: str = None,
2240 other_update: dict = None,
2241 ):
quilesj3655ae02019-12-12 16:08:35 +00002242 try:
tiernoe876f672020-02-13 14:34:48 +00002243 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002244 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002245 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002246 db_dict["stage"] = stage[0]
2247 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002248 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002249 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002250
2251 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002252 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002253 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002254 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002255 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002256 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002257 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002258 self.logger.warn(
2259 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2260 )
quilesj3655ae02019-12-12 16:08:35 +00002261
tierno51183952020-04-03 15:48:18 +00002262 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002263 try:
tierno51183952020-04-03 15:48:18 +00002264 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002265 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002266 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002267 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002268 db_nsr_update = {
2269 "configurationStatus.{}.status".format(index): status
2270 for index, v in enumerate(config_status)
2271 if v
2272 }
quilesj3655ae02019-12-12 16:08:35 +00002273 # update status
tierno51183952020-04-03 15:48:18 +00002274 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002275
tiernoe876f672020-02-13 14:34:48 +00002276 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002277 self.logger.warn(
2278 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2279 )
quilesj3655ae02019-12-12 16:08:35 +00002280
garciadeblas5697b8b2021-03-24 09:17:02 +01002281 def _write_configuration_status(
2282 self,
2283 nsr_id: str,
2284 vca_index: int,
2285 status: str = None,
2286 element_under_configuration: str = None,
2287 element_type: str = None,
2288 other_update: dict = None,
2289 ):
quilesj3655ae02019-12-12 16:08:35 +00002290 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2291 # .format(vca_index, status))
2292
2293 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002294 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002295 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002296 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002297 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002298 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002299 db_dict[
2300 db_path + "elementUnderConfiguration"
2301 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002302 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002303 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002304 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002305 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002306 self.logger.warn(
2307 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2308 status, nsr_id, vca_index, e
2309 )
2310 )
quilesj4cda56b2019-12-05 10:02:20 +00002311
tierno38089af2020-04-16 07:56:58 +00002312 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2313 """
2314 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2315 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2316 Database is used because the result can be obtained from a different LCM worker in case of HA.
2317 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2318 :param db_nslcmop: database content of nslcmop
2319 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002320 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2321 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002322 """
tierno8790a3d2020-04-23 22:49:52 +00002323 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002324 nslcmop_id = db_nslcmop["_id"]
2325 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002326 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002327 self.logger.debug(
2328 logging_text + "Invoke and wait for placement optimization"
2329 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002330 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002331 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002332 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002333 pla_result = None
2334 while not pla_result and wait >= 0:
2335 await asyncio.sleep(db_poll_interval)
2336 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002337 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002338 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002339
2340 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002341 raise LcmException(
2342 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2343 )
magnussonle9198bb2020-01-21 13:00:51 +01002344
garciadeblas5697b8b2021-03-24 09:17:02 +01002345 for pla_vnf in pla_result["vnf"]:
2346 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2347 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002348 continue
tierno8790a3d2020-04-23 22:49:52 +00002349 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002350 self.db.set_one(
2351 "vnfrs",
2352 {"_id": vnfr["_id"]},
2353 {"vim-account-id": pla_vnf["vimAccountId"]},
2354 )
tierno38089af2020-04-16 07:56:58 +00002355 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002356 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002357 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002358
aguilard1ae3c562023-02-16 17:24:35 +00002359 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2360 alerts = []
2361 nsr_id = vnfr["nsr-id-ref"]
2362 df = vnfd.get("df", [{}])[0]
2363 # Checking for auto-healing configuration
2364 if "healing-aspect" in df:
2365 healing_aspects = df["healing-aspect"]
2366 for healing in healing_aspects:
2367 for healing_policy in healing.get("healing-policy", ()):
2368 vdu_id = healing_policy["vdu-id"]
2369 vdur = next(
2370 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2371 {},
2372 )
2373 if not vdur:
2374 continue
2375 metric_name = "vm_status"
2376 vdu_name = vdur.get("name")
2377 vnf_member_index = vnfr["member-vnf-index-ref"]
2378 uuid = str(uuid4())
2379 name = f"healing_{uuid}"
2380 action = healing_policy
2381 # action_on_recovery = healing.get("action-on-recovery")
2382 # cooldown_time = healing.get("cooldown-time")
2383 # day1 = healing.get("day1")
2384 alert = {
2385 "uuid": uuid,
2386 "name": name,
2387 "metric": metric_name,
2388 "tags": {
2389 "ns_id": nsr_id,
2390 "vnf_member_index": vnf_member_index,
2391 "vdu_name": vdu_name,
2392 },
2393 "alarm_status": "ok",
2394 "action_type": "healing",
2395 "action": action,
2396 }
2397 alerts.append(alert)
2398 return alerts
2399
2400 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2401 alerts = []
2402 nsr_id = vnfr["nsr-id-ref"]
2403 df = vnfd.get("df", [{}])[0]
2404 # Checking for auto-scaling configuration
2405 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002406 scaling_aspects = df["scaling-aspect"]
2407 all_vnfd_monitoring_params = {}
2408 for ivld in vnfd.get("int-virtual-link-desc", ()):
2409 for mp in ivld.get("monitoring-parameters", ()):
2410 all_vnfd_monitoring_params[mp.get("id")] = mp
2411 for vdu in vnfd.get("vdu", ()):
2412 for mp in vdu.get("monitoring-parameter", ()):
2413 all_vnfd_monitoring_params[mp.get("id")] = mp
2414 for df in vnfd.get("df", ()):
2415 for mp in df.get("monitoring-parameter", ()):
2416 all_vnfd_monitoring_params[mp.get("id")] = mp
2417 for scaling_aspect in scaling_aspects:
2418 scaling_group_name = scaling_aspect.get("name", "")
2419 # Get monitored VDUs
2420 all_monitored_vdus = set()
2421 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2422 "deltas", ()
2423 ):
2424 for vdu_delta in delta.get("vdu-delta", ()):
2425 all_monitored_vdus.add(vdu_delta.get("id"))
2426 monitored_vdurs = list(
2427 filter(
2428 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2429 vnfr["vdur"],
2430 )
2431 )
2432 if not monitored_vdurs:
2433 self.logger.error(
2434 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2435 )
2436 continue
2437 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2438 if scaling_policy["scaling-type"] != "automatic":
2439 continue
2440 threshold_time = scaling_policy.get("threshold-time", "1")
2441 cooldown_time = scaling_policy.get("cooldown-time", "0")
2442 for scaling_criteria in scaling_policy["scaling-criteria"]:
2443 monitoring_param_ref = scaling_criteria.get(
2444 "vnf-monitoring-param-ref"
2445 )
2446 vnf_monitoring_param = all_vnfd_monitoring_params[
2447 monitoring_param_ref
2448 ]
2449 for vdur in monitored_vdurs:
2450 vdu_id = vdur["vdu-id-ref"]
2451 metric_name = vnf_monitoring_param.get("performance-metric")
aguilarde416ea02023-05-08 15:09:37 +00002452 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002453 vnf_member_index = vnfr["member-vnf-index-ref"]
2454 scalein_threshold = scaling_criteria.get(
2455 "scale-in-threshold"
2456 )
2457 scaleout_threshold = scaling_criteria.get(
2458 "scale-out-threshold"
2459 )
2460 # Looking for min/max-number-of-instances
2461 instances_min_number = 1
2462 instances_max_number = 1
2463 vdu_profile = df["vdu-profile"]
2464 if vdu_profile:
2465 profile = next(
2466 item for item in vdu_profile if item["id"] == vdu_id
2467 )
2468 instances_min_number = profile.get(
2469 "min-number-of-instances", 1
2470 )
2471 instances_max_number = profile.get(
2472 "max-number-of-instances", 1
2473 )
2474
2475 if scalein_threshold:
2476 uuid = str(uuid4())
2477 name = f"scalein_{uuid}"
2478 operation = scaling_criteria[
2479 "scale-in-relational-operation"
2480 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002481 rel_operator = self.rel_operation_types.get(
2482 operation, "<="
2483 )
aguilard1ae3c562023-02-16 17:24:35 +00002484 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2485 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
2486 labels = {
2487 "ns_id": nsr_id,
2488 "vnf_member_index": vnf_member_index,
2489 "vdu_id": vdu_id,
2490 }
2491 prom_cfg = {
2492 "alert": name,
2493 "expr": expression,
2494 "for": str(threshold_time) + "m",
2495 "labels": labels,
2496 }
2497 action = scaling_policy
2498 action = {
2499 "scaling-group": scaling_group_name,
2500 "cooldown-time": cooldown_time,
2501 }
2502 alert = {
2503 "uuid": uuid,
2504 "name": name,
2505 "metric": metric_name,
2506 "tags": {
2507 "ns_id": nsr_id,
2508 "vnf_member_index": vnf_member_index,
2509 "vdu_id": vdu_id,
2510 },
2511 "alarm_status": "ok",
2512 "action_type": "scale_in",
2513 "action": action,
2514 "prometheus_config": prom_cfg,
2515 }
2516 alerts.append(alert)
2517
2518 if scaleout_threshold:
2519 uuid = str(uuid4())
2520 name = f"scaleout_{uuid}"
2521 operation = scaling_criteria[
2522 "scale-out-relational-operation"
2523 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002524 rel_operator = self.rel_operation_types.get(
2525 operation, "<="
2526 )
aguilard1ae3c562023-02-16 17:24:35 +00002527 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2528 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
2529 labels = {
2530 "ns_id": nsr_id,
2531 "vnf_member_index": vnf_member_index,
2532 "vdu_id": vdu_id,
2533 }
2534 prom_cfg = {
2535 "alert": name,
2536 "expr": expression,
2537 "for": str(threshold_time) + "m",
2538 "labels": labels,
2539 }
2540 action = scaling_policy
2541 action = {
2542 "scaling-group": scaling_group_name,
2543 "cooldown-time": cooldown_time,
2544 }
2545 alert = {
2546 "uuid": uuid,
2547 "name": name,
2548 "metric": metric_name,
2549 "tags": {
2550 "ns_id": nsr_id,
2551 "vnf_member_index": vnf_member_index,
2552 "vdu_id": vdu_id,
2553 },
2554 "alarm_status": "ok",
2555 "action_type": "scale_out",
2556 "action": action,
2557 "prometheus_config": prom_cfg,
2558 }
2559 alerts.append(alert)
2560 return alerts
2561
garciadeblas9148fa82023-05-30 12:51:14 +02002562 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2563 alerts = []
2564 nsr_id = vnfr["nsr-id-ref"]
2565 vnf_member_index = vnfr["member-vnf-index-ref"]
2566
2567 # Checking for VNF alarm configuration
2568 for vdur in vnfr["vdur"]:
2569 vdu_id = vdur["vdu-id-ref"]
2570 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2571 if "alarm" in vdu:
2572 # Get VDU monitoring params, since alerts are based on them
2573 vdu_monitoring_params = {}
2574 for mp in vdu.get("monitoring-parameter", []):
2575 vdu_monitoring_params[mp.get("id")] = mp
2576 if not vdu_monitoring_params:
2577 self.logger.error(
2578 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2579 )
2580 continue
2581 # Get alarms in the VDU
2582 alarm_descriptors = vdu["alarm"]
2583 # Create VDU alarms for each alarm in the VDU
2584 for alarm_descriptor in alarm_descriptors:
2585 # Check that the VDU alarm refers to a proper monitoring param
2586 alarm_monitoring_param = alarm_descriptor.get(
2587 "vnf-monitoring-param-ref", ""
2588 )
2589 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2590 alarm_monitoring_param, {}
2591 )
2592 if not vdu_specific_monitoring_param:
2593 self.logger.error(
2594 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2595 )
2596 continue
2597 metric_name = vdu_specific_monitoring_param.get(
2598 "performance-metric"
2599 )
2600 if not metric_name:
2601 self.logger.error(
2602 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2603 )
2604 continue
2605 # Set params of the alarm to be created in Prometheus
2606 metric_name = f"osm_{metric_name}"
2607 metric_threshold = alarm_descriptor.get("value")
2608 uuid = str(uuid4())
2609 alert_name = f"vdu_alarm_{uuid}"
2610 operation = alarm_descriptor["operation"]
2611 rel_operator = self.rel_operation_types.get(operation, "<=")
2612 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 +00002613 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002614 labels = {
2615 "ns_id": nsr_id,
2616 "vnf_member_index": vnf_member_index,
2617 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002618 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002619 }
2620 prom_cfg = {
2621 "alert": alert_name,
2622 "expr": expression,
2623 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2624 "labels": labels,
2625 }
2626 alarm_action = dict()
2627 for action_type in ["ok", "insufficient-data", "alarm"]:
2628 if (
2629 "actions" in alarm_descriptor
2630 and action_type in alarm_descriptor["actions"]
2631 ):
aguilardeb076722023-05-31 09:45:00 +00002632 alarm_action[action_type] = alarm_descriptor["actions"][
2633 action_type
2634 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002635 alert = {
2636 "uuid": uuid,
2637 "name": alert_name,
2638 "metric": metric_name,
2639 "tags": {
2640 "ns_id": nsr_id,
2641 "vnf_member_index": vnf_member_index,
2642 "vdu_id": vdu_id,
2643 },
2644 "alarm_status": "ok",
2645 "action_type": "vdu_alarm",
2646 "action": alarm_action,
2647 "prometheus_config": prom_cfg,
2648 }
2649 alerts.append(alert)
2650 return alerts
2651
magnussonle9198bb2020-01-21 13:00:51 +01002652 def update_nsrs_with_pla_result(self, params):
2653 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002654 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2655 self.update_db_2(
2656 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2657 )
magnussonle9198bb2020-01-21 13:00:51 +01002658 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002659 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002660
tierno59d22d22018-09-25 18:10:19 +02002661 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002662 """
2663
2664 :param nsr_id: ns instance to deploy
2665 :param nslcmop_id: operation to run
2666 :return:
2667 """
kuused124bfe2019-06-18 12:09:24 +02002668
2669 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002670 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002671 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002672 self.logger.debug(
2673 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2674 )
kuused124bfe2019-06-18 12:09:24 +02002675 return
2676
tierno59d22d22018-09-25 18:10:19 +02002677 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2678 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002679
tierno59d22d22018-09-25 18:10:19 +02002680 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002681
2682 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002683 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002684
2685 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002686 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002687
2688 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002689 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002690 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002691 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002692
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002693 timeout_ns_deploy = self.timeout.ns_deploy
2694
tierno59d22d22018-09-25 18:10:19 +02002695 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002696 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002697 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002698 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002699 exc = None
tiernoe876f672020-02-13 14:34:48 +00002700 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002701 stage = [
2702 "Stage 1/5: preparation of the environment.",
2703 "Waiting for previous operations to terminate.",
2704 "",
2705 ]
tiernoe876f672020-02-13 14:34:48 +00002706 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002707 try:
kuused124bfe2019-06-18 12:09:24 +02002708 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002709 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002710
quilesj7e13aeb2019-10-08 13:34:55 +02002711 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002712 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002713 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002714 db_nsr_update["detailed-status"] = "creating"
2715 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002716 self._write_ns_status(
2717 nsr_id=nsr_id,
2718 ns_state="BUILDING",
2719 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002720 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002721 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002722 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002723 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002724
quilesj7e13aeb2019-10-08 13:34:55 +02002725 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002726 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002727 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002728 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2729 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2730 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2731 )
tierno744303e2020-01-13 16:46:31 +00002732 ns_params = db_nslcmop.get("operationParams")
2733 if ns_params and ns_params.get("timeout_ns_deploy"):
2734 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002735
2736 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002737 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002738 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002739 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002740 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002741 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002742 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002743 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002744 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002745 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002746
quilesj7e13aeb2019-10-08 13:34:55 +02002747 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002748 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002749 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002750 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002751
quilesj7e13aeb2019-10-08 13:34:55 +02002752 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002753 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002754
2755 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002756 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002757 if vnfr.get("kdur"):
2758 kdur_list = []
2759 for kdur in vnfr["kdur"]:
2760 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002761 kdur["additionalParams"] = json.loads(
2762 kdur["additionalParams"]
2763 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002764 kdur_list.append(kdur)
2765 vnfr["kdur"] = kdur_list
2766
bravof922c4172020-11-24 21:21:43 -03002767 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2768 vnfd_id = vnfr["vnfd-id"]
2769 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002770 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002771
quilesj7e13aeb2019-10-08 13:34:55 +02002772 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002773 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002774 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002775 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2776 vnfd_id, vnfd_ref
2777 )
tiernoe876f672020-02-13 14:34:48 +00002778 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002779 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002780
quilesj7e13aeb2019-10-08 13:34:55 +02002781 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002782 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002783
2784 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002785 vca_deployed_list = None
2786 if db_nsr["_admin"].get("deployed"):
2787 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2788 if vca_deployed_list is None:
2789 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002790 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002791 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002792 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002793 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002794 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002795 elif isinstance(vca_deployed_list, dict):
2796 # maintain backward compatibility. Change a dict to list at database
2797 vca_deployed_list = list(vca_deployed_list.values())
2798 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002799 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002800
garciadeblas5697b8b2021-03-24 09:17:02 +01002801 if not isinstance(
2802 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2803 ):
tiernoa009e552019-01-30 16:45:44 +00002804 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2805 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002806
tiernobaa51102018-12-14 13:16:18 +00002807 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2808 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2809 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002810 self.db.set_list(
2811 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2812 )
quilesj3655ae02019-12-12 16:08:35 +00002813
2814 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002815 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2816 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002817
tiernob5203912020-08-11 11:20:13 +00002818 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002819 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002820 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002821 await self.deploy_kdus(
2822 logging_text=logging_text,
2823 nsr_id=nsr_id,
2824 nslcmop_id=nslcmop_id,
2825 db_vnfrs=db_vnfrs,
2826 db_vnfds=db_vnfds,
2827 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002828 )
tiernoe876f672020-02-13 14:34:48 +00002829
2830 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002831 # n2vc_redesign STEP 1 Get VCA public ssh-key
2832 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002833 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002834 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002835 if self.vca_config.public_key:
2836 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002837
tiernoe876f672020-02-13 14:34:48 +00002838 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002839 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002840 self.instantiate_RO(
2841 logging_text=logging_text,
2842 nsr_id=nsr_id,
2843 nsd=nsd,
2844 db_nsr=db_nsr,
2845 db_nslcmop=db_nslcmop,
2846 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002847 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002848 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002849 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002850 )
tiernod8323042019-08-09 11:32:23 +00002851 )
2852 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002853 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002854
tiernod8323042019-08-09 11:32:23 +00002855 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002856 stage[1] = "Deploying Execution Environments."
2857 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002858
Gabriel Cuba1411a002022-10-07 11:38:23 -05002859 # create namespace and certificate if any helm based EE is present in the NS
2860 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002861 await self.vca_map["helm-v3"].setup_ns_namespace(
2862 name=nsr_id,
2863 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002864 # create TLS certificates
2865 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002866 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002867 dns_prefix="*",
2868 nsr_id=nsr_id,
2869 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002870 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002871 )
2872
tiernod8323042019-08-09 11:32:23 +00002873 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002874 for vnf_profile in get_vnf_profiles(nsd):
2875 vnfd_id = vnf_profile["vnfd-id"]
2876 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2877 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002878 db_vnfr = db_vnfrs[member_vnf_index]
2879 base_folder = vnfd["_admin"]["storage"]
2880 vdu_id = None
2881 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002882 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002883 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002884 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002885
tierno8a518872018-12-21 13:42:14 +00002886 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002887 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002888 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002889 deploy_params.update(
2890 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2891 )
tierno8a518872018-12-21 13:42:14 +00002892
bravofe5a31bc2021-02-17 19:09:12 -03002893 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002894 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002895 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002896 logging_text=logging_text
2897 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002898 db_nsr=db_nsr,
2899 db_vnfr=db_vnfr,
2900 nslcmop_id=nslcmop_id,
2901 nsr_id=nsr_id,
2902 nsi_id=nsi_id,
2903 vnfd_id=vnfd_id,
2904 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002905 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002906 member_vnf_index=member_vnf_index,
2907 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002908 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002909 vdu_name=vdu_name,
2910 deploy_params=deploy_params,
2911 descriptor_config=descriptor_config,
2912 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002913 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002914 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002915 )
tierno59d22d22018-09-25 18:10:19 +02002916
2917 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002918 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002919 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002920 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002921 vdur = find_in_list(
2922 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2923 )
bravof922c4172020-11-24 21:21:43 -03002924
tierno626e0152019-11-29 14:16:16 +00002925 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002926 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002927 else:
2928 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002929 deploy_params_vdu["OSM"] = get_osm_params(
2930 db_vnfr, vdu_id, vdu_count_index=0
2931 )
endika76ba9232021-06-21 18:55:07 +02002932 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002933
2934 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002935 self.logger.debug(
2936 "Descriptor config > {}".format(descriptor_config)
2937 )
tierno588547c2020-07-01 15:30:20 +00002938 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002939 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002940 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002941 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002942 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002943 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002944 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002945 logging_text=logging_text
2946 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2947 member_vnf_index, vdu_id, vdu_index
2948 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002949 db_nsr=db_nsr,
2950 db_vnfr=db_vnfr,
2951 nslcmop_id=nslcmop_id,
2952 nsr_id=nsr_id,
2953 nsi_id=nsi_id,
2954 vnfd_id=vnfd_id,
2955 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002956 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002957 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002958 member_vnf_index=member_vnf_index,
2959 vdu_index=vdu_index,
2960 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002961 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002962 descriptor_config=descriptor_config,
2963 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002964 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002965 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002966 )
bravof922c4172020-11-24 21:21:43 -03002967 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002968 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002969 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002970 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002971 vdu_id = None
2972 vdu_index = 0
2973 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002974 kdu_index, kdur = next(
2975 x
2976 for x in enumerate(db_vnfr["kdur"])
2977 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002978 )
bravof922c4172020-11-24 21:21:43 -03002979 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002980 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002981 deploy_params_kdu.update(
2982 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002983 )
tierno59d22d22018-09-25 18:10:19 +02002984
calvinosanch9f9c6f22019-11-04 13:37:39 +01002985 self._deploy_n2vc(
2986 logging_text=logging_text,
2987 db_nsr=db_nsr,
2988 db_vnfr=db_vnfr,
2989 nslcmop_id=nslcmop_id,
2990 nsr_id=nsr_id,
2991 nsi_id=nsi_id,
2992 vnfd_id=vnfd_id,
2993 vdu_id=vdu_id,
2994 kdu_name=kdu_name,
2995 member_vnf_index=member_vnf_index,
2996 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002997 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002998 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002999 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01003000 descriptor_config=descriptor_config,
3001 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00003002 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01003003 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01003004 )
tierno59d22d22018-09-25 18:10:19 +02003005
k4.rahul74944982023-04-19 17:00:52 +05303006 # Check if each vnf has exporter for metric collection if so update prometheus job records
3007 if "exporters-endpoints" in vnfd.get("df")[0]:
3008 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
3009 self.logger.debug("exporter config :{}".format(exporter_config))
3010 artifact_path = "{}/{}/{}".format(
3011 base_folder["folder"],
3012 base_folder["pkg-dir"],
3013 "exporter-endpoint",
3014 )
3015 ee_id = None
3016 ee_config_descriptor = exporter_config
3017 vnfr_id = db_vnfr["id"]
3018 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
3019 logging_text,
3020 nsr_id,
3021 vnfr_id,
3022 vdu_id=None,
3023 vdu_index=None,
3024 user=None,
3025 pub_key=None,
3026 )
3027 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
3028 self.logger.debug("Artifact_path:{}".format(artifact_path))
3029 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
3030 vdu_id_for_prom = None
3031 vdu_index_for_prom = None
3032 for x in get_iterable(db_vnfr, "vdur"):
3033 vdu_id_for_prom = x.get("vdu-id-ref")
3034 vdu_index_for_prom = x.get("count-index")
3035 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
3036 ee_id=ee_id,
3037 artifact_path=artifact_path,
3038 ee_config_descriptor=ee_config_descriptor,
3039 vnfr_id=vnfr_id,
3040 nsr_id=nsr_id,
3041 target_ip=rw_mgmt_ip,
3042 element_type="VDU",
3043 vdu_id=vdu_id_for_prom,
3044 vdu_index=vdu_index_for_prom,
3045 )
3046
3047 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
3048 if prometheus_jobs:
3049 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
3050 self.update_db_2(
3051 "nsrs",
3052 nsr_id,
3053 db_nsr_update,
3054 )
3055
3056 for job in prometheus_jobs:
3057 self.db.set_one(
3058 "prometheus_jobs",
3059 {"job_name": job["job_name"]},
3060 job,
3061 upsert=True,
3062 fail_on_empty=False,
3063 )
3064
tierno1b633412019-02-25 16:48:23 +00003065 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00003066 descriptor_config = nsd.get("ns-configuration")
3067 if descriptor_config and descriptor_config.get("juju"):
3068 vnfd_id = None
3069 db_vnfr = None
3070 member_vnf_index = None
3071 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01003072 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01003073 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00003074 vdu_index = 0
3075 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00003076
tiernod8323042019-08-09 11:32:23 +00003077 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01003078 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00003079 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003080 deploy_params.update(
3081 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
3082 )
tiernod8323042019-08-09 11:32:23 +00003083 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02003084 self._deploy_n2vc(
3085 logging_text=logging_text,
3086 db_nsr=db_nsr,
3087 db_vnfr=db_vnfr,
3088 nslcmop_id=nslcmop_id,
3089 nsr_id=nsr_id,
3090 nsi_id=nsi_id,
3091 vnfd_id=vnfd_id,
3092 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01003093 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02003094 member_vnf_index=member_vnf_index,
3095 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003096 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02003097 vdu_name=vdu_name,
3098 deploy_params=deploy_params,
3099 descriptor_config=descriptor_config,
3100 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00003101 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01003102 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02003103 )
tierno1b633412019-02-25 16:48:23 +00003104
tiernoe876f672020-02-13 14:34:48 +00003105 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00003106
garciadeblas5697b8b2021-03-24 09:17:02 +01003107 except (
3108 ROclient.ROClientException,
3109 DbException,
3110 LcmException,
3111 N2VCException,
3112 ) as e:
3113 self.logger.error(
3114 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3115 )
tierno59d22d22018-09-25 18:10:19 +02003116 exc = e
3117 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003118 self.logger.error(
3119 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3120 )
tierno59d22d22018-09-25 18:10:19 +02003121 exc = "Operation was cancelled"
3122 except Exception as e:
3123 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003124 self.logger.critical(
3125 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3126 exc_info=True,
3127 )
tierno59d22d22018-09-25 18:10:19 +02003128 finally:
3129 if exc:
tiernoe876f672020-02-13 14:34:48 +00003130 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003131 try:
tiernoe876f672020-02-13 14:34:48 +00003132 # wait for pending tasks
3133 if tasks_dict_info:
3134 stage[1] = "Waiting for instantiate pending tasks."
3135 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003136 error_list += await self._wait_for_tasks(
3137 logging_text,
3138 tasks_dict_info,
3139 timeout_ns_deploy,
3140 stage,
3141 nslcmop_id,
3142 nsr_id=nsr_id,
3143 )
tiernoe876f672020-02-13 14:34:48 +00003144 stage[1] = stage[2] = ""
3145 except asyncio.CancelledError:
3146 error_list.append("Cancelled")
3147 # TODO cancel all tasks
3148 except Exception as exc:
3149 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003150
tiernoe876f672020-02-13 14:34:48 +00003151 # update operation-status
3152 db_nsr_update["operational-status"] = "running"
3153 # let's begin with VCA 'configured' status (later we can change it)
3154 db_nsr_update["config-status"] = "configured"
3155 for task, task_name in tasks_dict_info.items():
3156 if not task.done() or task.cancelled() or task.exception():
3157 if task_name.startswith(self.task_name_deploy_vca):
3158 # A N2VC task is pending
3159 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003160 else:
tiernoe876f672020-02-13 14:34:48 +00003161 # RO or KDU task is pending
3162 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003163
tiernoe876f672020-02-13 14:34:48 +00003164 # update status at database
3165 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003166 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003167 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003168 error_description_nslcmop = "{} Detail: {}".format(
3169 stage[0], error_detail
3170 )
3171 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3172 nslcmop_id, stage[0]
3173 )
quilesj3655ae02019-12-12 16:08:35 +00003174
garciadeblas5697b8b2021-03-24 09:17:02 +01003175 db_nsr_update["detailed-status"] = (
3176 error_description_nsr + " Detail: " + error_detail
3177 )
tiernoe876f672020-02-13 14:34:48 +00003178 db_nslcmop_update["detailed-status"] = error_detail
3179 nslcmop_operation_state = "FAILED"
3180 ns_state = "BROKEN"
3181 else:
tiernoa2143262020-03-27 16:20:40 +00003182 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003183 error_description_nsr = error_description_nslcmop = None
3184 ns_state = "READY"
3185 db_nsr_update["detailed-status"] = "Done"
3186 db_nslcmop_update["detailed-status"] = "Done"
3187 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003188 # Gather auto-healing and auto-scaling alerts for each vnfr
3189 healing_alerts = []
3190 scaling_alerts = []
3191 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3192 vnfd = next(
3193 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3194 )
3195 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3196 for alert in healing_alerts:
3197 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3198 self.db.create("alerts", alert)
3199
3200 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3201 for alert in scaling_alerts:
3202 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3203 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003204
garciadeblas9148fa82023-05-30 12:51:14 +02003205 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3206 for alert in alarm_alerts:
3207 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3208 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003209 if db_nsr:
3210 self._write_ns_status(
3211 nsr_id=nsr_id,
3212 ns_state=ns_state,
3213 current_operation="IDLE",
3214 current_operation_id=None,
3215 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003216 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003217 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003218 )
tiernoa17d4f42020-04-28 09:59:23 +00003219 self._write_op_status(
3220 op_id=nslcmop_id,
3221 stage="",
3222 error_message=error_description_nslcmop,
3223 operation_state=nslcmop_operation_state,
3224 other_update=db_nslcmop_update,
3225 )
quilesj3655ae02019-12-12 16:08:35 +00003226
tierno59d22d22018-09-25 18:10:19 +02003227 if nslcmop_operation_state:
3228 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003229 await self.msg.aiowrite(
3230 "ns",
3231 "instantiated",
3232 {
3233 "nsr_id": nsr_id,
3234 "nslcmop_id": nslcmop_id,
3235 "operationState": nslcmop_operation_state,
3236 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003237 )
tierno59d22d22018-09-25 18:10:19 +02003238 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003239 self.logger.error(
3240 logging_text + "kafka_write notification Exception {}".format(e)
3241 )
tierno59d22d22018-09-25 18:10:19 +02003242
3243 self.logger.debug(logging_text + "Exit")
3244 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3245
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003246 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003247 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003248 cached_vnfds[vnfd_id] = self.db.get_one(
3249 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3250 )
David Garciab4ebcd02021-10-28 02:00:43 +02003251 return cached_vnfds[vnfd_id]
3252
3253 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3254 if vnf_profile_id not in cached_vnfrs:
3255 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3256 "vnfrs",
3257 {
3258 "member-vnf-index-ref": vnf_profile_id,
3259 "nsr-id-ref": nsr_id,
3260 },
3261 )
3262 return cached_vnfrs[vnf_profile_id]
3263
3264 def _is_deployed_vca_in_relation(
3265 self, vca: DeployedVCA, relation: Relation
3266 ) -> bool:
3267 found = False
3268 for endpoint in (relation.provider, relation.requirer):
3269 if endpoint["kdu-resource-profile-id"]:
3270 continue
3271 found = (
3272 vca.vnf_profile_id == endpoint.vnf_profile_id
3273 and vca.vdu_profile_id == endpoint.vdu_profile_id
3274 and vca.execution_environment_ref == endpoint.execution_environment_ref
3275 )
3276 if found:
3277 break
3278 return found
3279
3280 def _update_ee_relation_data_with_implicit_data(
3281 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3282 ):
3283 ee_relation_data = safe_get_ee_relation(
3284 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3285 )
3286 ee_relation_level = EELevel.get_level(ee_relation_data)
3287 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3288 "execution-environment-ref"
3289 ]:
3290 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3291 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003292 project = nsd["_admin"]["projects_read"][0]
3293 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003294 entity_id = (
3295 vnfd_id
3296 if ee_relation_level == EELevel.VNF
3297 else ee_relation_data["vdu-profile-id"]
3298 )
3299 ee = get_juju_ee_ref(db_vnfd, entity_id)
3300 if not ee:
3301 raise Exception(
3302 f"not execution environments found for ee_relation {ee_relation_data}"
3303 )
3304 ee_relation_data["execution-environment-ref"] = ee["id"]
3305 return ee_relation_data
3306
3307 def _get_ns_relations(
3308 self,
3309 nsr_id: str,
3310 nsd: Dict[str, Any],
3311 vca: DeployedVCA,
3312 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003313 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003314 relations = []
3315 db_ns_relations = get_ns_configuration_relation_list(nsd)
3316 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003317 provider_dict = None
3318 requirer_dict = None
3319 if all(key in r for key in ("provider", "requirer")):
3320 provider_dict = r["provider"]
3321 requirer_dict = r["requirer"]
3322 elif "entities" in r:
3323 provider_id = r["entities"][0]["id"]
3324 provider_dict = {
3325 "nsr-id": nsr_id,
3326 "endpoint": r["entities"][0]["endpoint"],
3327 }
3328 if provider_id != nsd["id"]:
3329 provider_dict["vnf-profile-id"] = provider_id
3330 requirer_id = r["entities"][1]["id"]
3331 requirer_dict = {
3332 "nsr-id": nsr_id,
3333 "endpoint": r["entities"][1]["endpoint"],
3334 }
3335 if requirer_id != nsd["id"]:
3336 requirer_dict["vnf-profile-id"] = requirer_id
3337 else:
aticig15db6142022-01-24 12:51:26 +03003338 raise Exception(
3339 "provider/requirer or entities must be included in the relation."
3340 )
David Garciab4ebcd02021-10-28 02:00:43 +02003341 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003342 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003343 )
3344 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003345 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003346 )
3347 provider = EERelation(relation_provider)
3348 requirer = EERelation(relation_requirer)
3349 relation = Relation(r["name"], provider, requirer)
3350 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3351 if vca_in_relation:
3352 relations.append(relation)
3353 return relations
3354
3355 def _get_vnf_relations(
3356 self,
3357 nsr_id: str,
3358 nsd: Dict[str, Any],
3359 vca: DeployedVCA,
3360 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003361 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003362 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003363 if vca.target_element == "ns":
3364 self.logger.debug("VCA is a NS charm, not a VNF.")
3365 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003366 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3367 vnf_profile_id = vnf_profile["id"]
3368 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003369 project = nsd["_admin"]["projects_read"][0]
3370 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003371 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3372 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003373 provider_dict = None
3374 requirer_dict = None
3375 if all(key in r for key in ("provider", "requirer")):
3376 provider_dict = r["provider"]
3377 requirer_dict = r["requirer"]
3378 elif "entities" in r:
3379 provider_id = r["entities"][0]["id"]
3380 provider_dict = {
3381 "nsr-id": nsr_id,
3382 "vnf-profile-id": vnf_profile_id,
3383 "endpoint": r["entities"][0]["endpoint"],
3384 }
3385 if provider_id != vnfd_id:
3386 provider_dict["vdu-profile-id"] = provider_id
3387 requirer_id = r["entities"][1]["id"]
3388 requirer_dict = {
3389 "nsr-id": nsr_id,
3390 "vnf-profile-id": vnf_profile_id,
3391 "endpoint": r["entities"][1]["endpoint"],
3392 }
3393 if requirer_id != vnfd_id:
3394 requirer_dict["vdu-profile-id"] = requirer_id
3395 else:
aticig15db6142022-01-24 12:51:26 +03003396 raise Exception(
3397 "provider/requirer or entities must be included in the relation."
3398 )
David Garciab4ebcd02021-10-28 02:00:43 +02003399 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003400 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003401 )
3402 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003403 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003404 )
3405 provider = EERelation(relation_provider)
3406 requirer = EERelation(relation_requirer)
3407 relation = Relation(r["name"], provider, requirer)
3408 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3409 if vca_in_relation:
3410 relations.append(relation)
3411 return relations
3412
3413 def _get_kdu_resource_data(
3414 self,
3415 ee_relation: EERelation,
3416 db_nsr: Dict[str, Any],
3417 cached_vnfds: Dict[str, Any],
3418 ) -> DeployedK8sResource:
3419 nsd = get_nsd(db_nsr)
3420 vnf_profiles = get_vnf_profiles(nsd)
3421 vnfd_id = find_in_list(
3422 vnf_profiles,
3423 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3424 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003425 project = nsd["_admin"]["projects_read"][0]
3426 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003427 kdu_resource_profile = get_kdu_resource_profile(
3428 db_vnfd, ee_relation.kdu_resource_profile_id
3429 )
3430 kdu_name = kdu_resource_profile["kdu-name"]
3431 deployed_kdu, _ = get_deployed_kdu(
3432 db_nsr.get("_admin", ()).get("deployed", ()),
3433 kdu_name,
3434 ee_relation.vnf_profile_id,
3435 )
3436 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3437 return deployed_kdu
3438
3439 def _get_deployed_component(
3440 self,
3441 ee_relation: EERelation,
3442 db_nsr: Dict[str, Any],
3443 cached_vnfds: Dict[str, Any],
3444 ) -> DeployedComponent:
3445 nsr_id = db_nsr["_id"]
3446 deployed_component = None
3447 ee_level = EELevel.get_level(ee_relation)
3448 if ee_level == EELevel.NS:
3449 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3450 if vca:
3451 deployed_component = DeployedVCA(nsr_id, vca)
3452 elif ee_level == EELevel.VNF:
3453 vca = get_deployed_vca(
3454 db_nsr,
3455 {
3456 "vdu_id": None,
3457 "member-vnf-index": ee_relation.vnf_profile_id,
3458 "ee_descriptor_id": ee_relation.execution_environment_ref,
3459 },
3460 )
3461 if vca:
3462 deployed_component = DeployedVCA(nsr_id, vca)
3463 elif ee_level == EELevel.VDU:
3464 vca = get_deployed_vca(
3465 db_nsr,
3466 {
3467 "vdu_id": ee_relation.vdu_profile_id,
3468 "member-vnf-index": ee_relation.vnf_profile_id,
3469 "ee_descriptor_id": ee_relation.execution_environment_ref,
3470 },
3471 )
3472 if vca:
3473 deployed_component = DeployedVCA(nsr_id, vca)
3474 elif ee_level == EELevel.KDU:
3475 kdu_resource_data = self._get_kdu_resource_data(
3476 ee_relation, db_nsr, cached_vnfds
3477 )
3478 if kdu_resource_data:
3479 deployed_component = DeployedK8sResource(kdu_resource_data)
3480 return deployed_component
3481
3482 async def _add_relation(
3483 self,
3484 relation: Relation,
3485 vca_type: str,
3486 db_nsr: Dict[str, Any],
3487 cached_vnfds: Dict[str, Any],
3488 cached_vnfrs: Dict[str, Any],
3489 ) -> bool:
3490 deployed_provider = self._get_deployed_component(
3491 relation.provider, db_nsr, cached_vnfds
3492 )
3493 deployed_requirer = self._get_deployed_component(
3494 relation.requirer, db_nsr, cached_vnfds
3495 )
3496 if (
3497 deployed_provider
3498 and deployed_requirer
3499 and deployed_provider.config_sw_installed
3500 and deployed_requirer.config_sw_installed
3501 ):
3502 provider_db_vnfr = (
3503 self._get_vnfr(
3504 relation.provider.nsr_id,
3505 relation.provider.vnf_profile_id,
3506 cached_vnfrs,
3507 )
3508 if relation.provider.vnf_profile_id
3509 else None
3510 )
3511 requirer_db_vnfr = (
3512 self._get_vnfr(
3513 relation.requirer.nsr_id,
3514 relation.requirer.vnf_profile_id,
3515 cached_vnfrs,
3516 )
3517 if relation.requirer.vnf_profile_id
3518 else None
3519 )
3520 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3521 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3522 provider_relation_endpoint = RelationEndpoint(
3523 deployed_provider.ee_id,
3524 provider_vca_id,
3525 relation.provider.endpoint,
3526 )
3527 requirer_relation_endpoint = RelationEndpoint(
3528 deployed_requirer.ee_id,
3529 requirer_vca_id,
3530 relation.requirer.endpoint,
3531 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003532 try:
3533 await self.vca_map[vca_type].add_relation(
3534 provider=provider_relation_endpoint,
3535 requirer=requirer_relation_endpoint,
3536 )
3537 except N2VCException as exception:
3538 self.logger.error(exception)
3539 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003540 return True
3541 return False
3542
David Garciac1fe90a2021-03-31 19:12:02 +02003543 async def _add_vca_relations(
3544 self,
3545 logging_text,
3546 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003547 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003548 vca_index: int,
3549 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003550 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003551 # steps:
3552 # 1. find all relations for this VCA
3553 # 2. wait for other peers related
3554 # 3. add relations
3555
3556 try:
quilesj63f90042020-01-17 09:53:55 +00003557 # STEP 1: find all relations for this VCA
3558
3559 # read nsr record
3560 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003561 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003562
3563 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003564 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3565 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003566
David Garciab4ebcd02021-10-28 02:00:43 +02003567 cached_vnfds = {}
3568 cached_vnfrs = {}
3569 relations = []
3570 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3571 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003572
3573 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003574 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003575 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003576 return True
3577
David Garciab4ebcd02021-10-28 02:00:43 +02003578 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003579
3580 # add all relations
3581 start = time()
3582 while True:
3583 # check timeout
3584 now = time()
3585 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003586 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003587 return False
3588
David Garciab4ebcd02021-10-28 02:00:43 +02003589 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003590 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3591
David Garciab4ebcd02021-10-28 02:00:43 +02003592 # for each relation, find the VCA's related
3593 for relation in relations.copy():
3594 added = await self._add_relation(
3595 relation,
3596 vca_type,
3597 db_nsr,
3598 cached_vnfds,
3599 cached_vnfrs,
3600 )
3601 if added:
3602 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003603
David Garciab4ebcd02021-10-28 02:00:43 +02003604 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003605 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003606 break
David Garciab4ebcd02021-10-28 02:00:43 +02003607 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003608
3609 return True
3610
3611 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003612 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003613 return False
3614
garciadeblas5697b8b2021-03-24 09:17:02 +01003615 async def _install_kdu(
3616 self,
3617 nsr_id: str,
3618 nsr_db_path: str,
3619 vnfr_data: dict,
3620 kdu_index: int,
3621 kdud: dict,
3622 vnfd: dict,
3623 k8s_instance_info: dict,
3624 k8params: dict = None,
3625 timeout: int = 600,
3626 vca_id: str = None,
3627 ):
tiernob9018152020-04-16 14:18:24 +00003628 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003629 k8sclustertype = k8s_instance_info["k8scluster-type"]
3630 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003631 db_dict_install = {
3632 "collection": "nsrs",
3633 "filter": {"_id": nsr_id},
3634 "path": nsr_db_path,
3635 }
lloretgalleg7c121132020-07-08 07:53:22 +00003636
romeromonser4554a702021-05-28 12:00:08 +02003637 if k8s_instance_info.get("kdu-deployment-name"):
3638 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3639 else:
3640 kdu_instance = self.k8scluster_map[
3641 k8sclustertype
3642 ].generate_kdu_instance_name(
3643 db_dict=db_dict_install,
3644 kdu_model=k8s_instance_info["kdu-model"],
3645 kdu_name=k8s_instance_info["kdu-name"],
3646 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003647
3648 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003649 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003650 item="nsrs",
3651 _id=nsr_id,
3652 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003653 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003654
3655 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3656 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3657 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3658 # namespace, this first verification could be removed, and the next step would be done for any kind
3659 # of KNF.
3660 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3661 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3662 if k8sclustertype in ("juju", "juju-bundle"):
3663 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3664 # that the user passed a namespace which he wants its KDU to be deployed in)
3665 if (
3666 self.db.count(
3667 table="nsrs",
3668 q_filter={
3669 "_id": nsr_id,
3670 "_admin.projects_write": k8s_instance_info["namespace"],
3671 "_admin.projects_read": k8s_instance_info["namespace"],
3672 },
3673 )
3674 > 0
3675 ):
3676 self.logger.debug(
3677 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3678 )
3679 self.update_db_2(
3680 item="nsrs",
3681 _id=nsr_id,
3682 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3683 )
3684 k8s_instance_info["namespace"] = kdu_instance
3685
David Garciad64e2742021-02-25 20:19:18 +01003686 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003687 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3688 kdu_model=k8s_instance_info["kdu-model"],
3689 atomic=True,
3690 params=k8params,
3691 db_dict=db_dict_install,
3692 timeout=timeout,
3693 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003694 namespace=k8s_instance_info["namespace"],
3695 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003696 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003697 )
lloretgalleg7c121132020-07-08 07:53:22 +00003698
3699 # Obtain services to obtain management service ip
3700 services = await self.k8scluster_map[k8sclustertype].get_services(
3701 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3702 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003703 namespace=k8s_instance_info["namespace"],
3704 )
lloretgalleg7c121132020-07-08 07:53:22 +00003705
3706 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003707 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003708 kdu_config = get_configuration(vnfd, kdud["name"])
3709 if kdu_config:
3710 target_ee_list = kdu_config.get("execution-environment-list", [])
3711 else:
3712 target_ee_list = []
3713
lloretgalleg7c121132020-07-08 07:53:22 +00003714 if services:
tierno7ecbc342020-09-21 14:05:39 +00003715 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003716 mgmt_services = [
3717 service
3718 for service in kdud.get("service", [])
3719 if service.get("mgmt-service")
3720 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003721 for mgmt_service in mgmt_services:
3722 for service in services:
3723 if service["name"].startswith(mgmt_service["name"]):
3724 # Mgmt service found, Obtain service ip
3725 ip = service.get("external_ip", service.get("cluster_ip"))
3726 if isinstance(ip, list) and len(ip) == 1:
3727 ip = ip[0]
3728
garciadeblas5697b8b2021-03-24 09:17:02 +01003729 vnfr_update_dict[
3730 "kdur.{}.ip-address".format(kdu_index)
3731 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003732
3733 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003734 service_external_cp = mgmt_service.get(
3735 "external-connection-point-ref"
3736 )
lloretgalleg7c121132020-07-08 07:53:22 +00003737 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003738 if (
3739 deep_get(vnfd, ("mgmt-interface", "cp"))
3740 == service_external_cp
3741 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003742 vnfr_update_dict["ip-address"] = ip
3743
bravof6ec62b72021-02-25 17:20:35 -03003744 if find_in_list(
3745 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003746 lambda ee: ee.get(
3747 "external-connection-point-ref", ""
3748 )
3749 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003750 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003751 vnfr_update_dict[
3752 "kdur.{}.ip-address".format(kdu_index)
3753 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003754 break
3755 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003756 self.logger.warn(
3757 "Mgmt service name: {} not found".format(
3758 mgmt_service["name"]
3759 )
3760 )
lloretgalleg7c121132020-07-08 07:53:22 +00003761
tierno7ecbc342020-09-21 14:05:39 +00003762 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3763 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003764
bravof9a256db2021-02-22 18:02:07 -03003765 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003766 if (
3767 kdu_config
3768 and kdu_config.get("initial-config-primitive")
3769 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3770 ):
3771 initial_config_primitive_list = kdu_config.get(
3772 "initial-config-primitive"
3773 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003774 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3775
3776 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003777 primitive_params_ = self._map_primitive_params(
3778 initial_config_primitive, {}, {}
3779 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003780
3781 await asyncio.wait_for(
3782 self.k8scluster_map[k8sclustertype].exec_primitive(
3783 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3784 kdu_instance=kdu_instance,
3785 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003786 params=primitive_params_,
3787 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003788 vca_id=vca_id,
3789 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003790 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003791 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003792
tiernob9018152020-04-16 14:18:24 +00003793 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003794 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003795 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003796 self.update_db_2(
3797 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3798 )
3799 self.update_db_2(
3800 "vnfrs",
3801 vnfr_data.get("_id"),
3802 {"kdur.{}.status".format(kdu_index): "ERROR"},
3803 )
tiernob9018152020-04-16 14:18:24 +00003804 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00003805 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00003806 pass
lloretgalleg7c121132020-07-08 07:53:22 +00003807 # reraise original error
3808 raise
3809
3810 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003811
garciadeblas5697b8b2021-03-24 09:17:02 +01003812 async def deploy_kdus(
3813 self,
3814 logging_text,
3815 nsr_id,
3816 nslcmop_id,
3817 db_vnfrs,
3818 db_vnfds,
3819 task_instantiation_info,
3820 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003821 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003822
garciadeblas5697b8b2021-03-24 09:17:02 +01003823 k8scluster_id_2_uuic = {
3824 "helm-chart-v3": {},
3825 "helm-chart": {},
3826 "juju-bundle": {},
3827 }
tierno626e0152019-11-29 14:16:16 +00003828
tierno16f4a4e2020-07-20 09:05:51 +00003829 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003830 nonlocal k8scluster_id_2_uuic
3831 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3832 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3833
tierno16f4a4e2020-07-20 09:05:51 +00003834 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003835 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3836 "k8scluster", cluster_id
3837 )
tierno16f4a4e2020-07-20 09:05:51 +00003838 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003839 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3840 task_name, cluster_id
3841 )
tierno16f4a4e2020-07-20 09:05:51 +00003842 self.logger.debug(logging_text + text)
3843 await asyncio.wait(task_dependency, timeout=3600)
3844
garciadeblas5697b8b2021-03-24 09:17:02 +01003845 db_k8scluster = self.db.get_one(
3846 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3847 )
tierno626e0152019-11-29 14:16:16 +00003848 if not db_k8scluster:
3849 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003850
tierno626e0152019-11-29 14:16:16 +00003851 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3852 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003853 if cluster_type == "helm-chart-v3":
3854 try:
3855 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003856 k8s_credentials = yaml.safe_dump(
3857 db_k8scluster.get("credentials")
3858 )
3859 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3860 k8s_credentials, reuse_cluster_uuid=cluster_id
3861 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003862 db_k8scluster_update = {}
3863 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3864 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003865 db_k8scluster_update[
3866 "_admin.helm-chart-v3.created"
3867 ] = uninstall_sw
3868 db_k8scluster_update[
3869 "_admin.helm-chart-v3.operationalState"
3870 ] = "ENABLED"
3871 self.update_db_2(
3872 "k8sclusters", cluster_id, db_k8scluster_update
3873 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003874 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003875 self.logger.error(
3876 logging_text
3877 + "error initializing helm-v3 cluster: {}".format(str(e))
3878 )
3879 raise LcmException(
3880 "K8s cluster '{}' has not been initialized for '{}'".format(
3881 cluster_id, cluster_type
3882 )
3883 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003884 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003885 raise LcmException(
3886 "K8s cluster '{}' has not been initialized for '{}'".format(
3887 cluster_id, cluster_type
3888 )
3889 )
tierno626e0152019-11-29 14:16:16 +00003890 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3891 return k8s_id
3892
3893 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003894 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003895 try:
tierno626e0152019-11-29 14:16:16 +00003896 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003897 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003898
tierno626e0152019-11-29 14:16:16 +00003899 index = 0
tiernoe876f672020-02-13 14:34:48 +00003900 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003901 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003902
tierno626e0152019-11-29 14:16:16 +00003903 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003904 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003905 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3906 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003907 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003908 vnfd_id = vnfr_data.get("vnfd-id")
3909 vnfd_with_id = find_in_list(
3910 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3911 )
3912 kdud = next(
3913 kdud
3914 for kdud in vnfd_with_id["kdu"]
3915 if kdud["name"] == kdur["kdu-name"]
3916 )
tiernode1584f2020-04-07 09:07:33 +00003917 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003918 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003919 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003920 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003921 # Default version: helm3, if helm-version is v2 assign v2
3922 k8sclustertype = "helm-chart-v3"
3923 self.logger.debug("kdur: {}".format(kdur))
garciadeblas5697b8b2021-03-24 09:17:02 +01003924 if (
3925 kdur.get("helm-version")
3926 and kdur.get("helm-version") == "v2"
3927 ):
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003928 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00003929 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003930 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003931 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003932 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003933 raise LcmException(
3934 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3935 "juju-bundle. Maybe an old NBI version is running".format(
3936 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3937 )
3938 )
quilesjacde94f2020-01-23 10:07:08 +00003939 # check if kdumodel is a file and exists
3940 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003941 vnfd_with_id = find_in_list(
3942 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3943 )
3944 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003945 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003946 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003947 if storage["pkg-dir"]:
3948 filename = "{}/{}/{}s/{}".format(
3949 storage["folder"],
3950 storage["pkg-dir"],
3951 k8sclustertype,
3952 kdumodel,
3953 )
3954 else:
3955 filename = "{}/Scripts/{}s/{}".format(
3956 storage["folder"],
3957 k8sclustertype,
3958 kdumodel,
3959 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003960 if self.fs.file_exists(
3961 filename, mode="file"
3962 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003963 kdumodel = self.fs.path + filename
3964 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003965 raise
garciadeblas5697b8b2021-03-24 09:17:02 +01003966 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00003967 pass
lloretgallegedc5f332020-02-20 11:50:50 +01003968
tiernoe876f672020-02-13 14:34:48 +00003969 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003970 step = "Synchronize repos for k8s cluster '{}'".format(
3971 k8s_cluster_id
3972 )
tierno16f4a4e2020-07-20 09:05:51 +00003973 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003974
lloretgalleg7c121132020-07-08 07:53:22 +00003975 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003976 if (
3977 k8sclustertype == "helm-chart"
3978 and cluster_uuid not in updated_cluster_list
3979 ) or (
3980 k8sclustertype == "helm-chart-v3"
3981 and cluster_uuid not in updated_v3_cluster_list
3982 ):
tiernoe876f672020-02-13 14:34:48 +00003983 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003984 self.k8scluster_map[k8sclustertype].synchronize_repos(
3985 cluster_uuid=cluster_uuid
3986 )
3987 )
tiernoe876f672020-02-13 14:34:48 +00003988 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003989 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003990 unset = {
3991 "_admin.helm_charts_added." + item: None
3992 for item in del_repo_list
3993 }
3994 updated = {
3995 "_admin.helm_charts_added." + item: name
3996 for item, name in added_repo_dict.items()
3997 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003998 updated_cluster_list.append(cluster_uuid)
3999 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01004000 unset = {
4001 "_admin.helm_charts_v3_added." + item: None
4002 for item in del_repo_list
4003 }
4004 updated = {
4005 "_admin.helm_charts_v3_added." + item: name
4006 for item, name in added_repo_dict.items()
4007 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00004008 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01004009 self.logger.debug(
4010 logging_text + "repos synchronized on k8s cluster "
4011 "'{}' to_delete: {}, to_add: {}".format(
4012 k8s_cluster_id, del_repo_list, added_repo_dict
4013 )
4014 )
4015 self.db.set_one(
4016 "k8sclusters",
4017 {"_id": k8s_cluster_id},
4018 updated,
4019 unset=unset,
4020 )
lloretgallegedc5f332020-02-20 11:50:50 +01004021
lloretgalleg7c121132020-07-08 07:53:22 +00004022 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01004023 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
4024 vnfr_data["member-vnf-index-ref"],
4025 kdur["kdu-name"],
4026 k8s_cluster_id,
4027 )
4028 k8s_instance_info = {
4029 "kdu-instance": None,
4030 "k8scluster-uuid": cluster_uuid,
4031 "k8scluster-type": k8sclustertype,
4032 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
4033 "kdu-name": kdur["kdu-name"],
4034 "kdu-model": kdumodel,
4035 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02004036 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004037 }
tiernob9018152020-04-16 14:18:24 +00004038 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00004039 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00004040 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01004041 vnfd_with_id = find_in_list(
4042 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
4043 )
tiernoa2143262020-03-27 16:20:40 +00004044 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004045 self._install_kdu(
4046 nsr_id,
4047 db_path,
4048 vnfr_data,
4049 kdu_index,
4050 kdud,
4051 vnfd_with_id,
4052 k8s_instance_info,
4053 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02004054 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01004055 vca_id=vca_id,
4056 )
4057 )
4058 self.lcm_tasks.register(
4059 "ns",
4060 nsr_id,
4061 nslcmop_id,
4062 "instantiate_KDU-{}".format(index),
4063 task,
4064 )
4065 task_instantiation_info[task] = "Deploying KDU {}".format(
4066 kdur["kdu-name"]
4067 )
tiernoe876f672020-02-13 14:34:48 +00004068
tierno626e0152019-11-29 14:16:16 +00004069 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00004070
tiernoe876f672020-02-13 14:34:48 +00004071 except (LcmException, asyncio.CancelledError):
4072 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01004073 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00004074 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
4075 if isinstance(e, (N2VCException, DbException)):
4076 self.logger.error(logging_text + msg)
4077 else:
4078 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00004079 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01004080 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01004081 if db_nsr_update:
4082 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00004083
garciadeblas5697b8b2021-03-24 09:17:02 +01004084 def _deploy_n2vc(
4085 self,
4086 logging_text,
4087 db_nsr,
4088 db_vnfr,
4089 nslcmop_id,
4090 nsr_id,
4091 nsi_id,
4092 vnfd_id,
4093 vdu_id,
4094 kdu_name,
4095 member_vnf_index,
4096 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004097 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004098 vdu_name,
4099 deploy_params,
4100 descriptor_config,
4101 base_folder,
4102 task_instantiation_info,
4103 stage,
4104 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004105 # launch instantiate_N2VC in a asyncio task and register task object
4106 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4107 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004108 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004109
garciadeblas5697b8b2021-03-24 09:17:02 +01004110 self.logger.debug(
4111 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4112 )
aticig9bc63ac2022-07-27 09:32:06 +03004113
4114 charm_name = ""
4115 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004116 if "execution-environment-list" in descriptor_config:
4117 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004118 elif "juju" in descriptor_config:
4119 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004120 if "execution-environment-list" not in descriptor_config:
4121 # charm name is only required for ns charms
4122 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004123 else: # other types as script are not supported
4124 ee_list = []
4125
4126 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004127 self.logger.debug(
4128 logging_text
4129 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4130 ee_item.get("juju"), ee_item.get("helm-chart")
4131 )
4132 )
tiernoa278b842020-07-08 15:33:55 +00004133 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00004134 if ee_item.get("juju"):
garciadeblas5697b8b2021-03-24 09:17:02 +01004135 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03004136 if get_charm_name:
4137 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas5697b8b2021-03-24 09:17:02 +01004138 vca_type = (
4139 "lxc_proxy_charm"
4140 if ee_item["juju"].get("charm") is not None
4141 else "native_charm"
4142 )
4143 if ee_item["juju"].get("cloud") == "k8s":
tierno588547c2020-07-01 15:30:20 +00004144 vca_type = "k8s_proxy_charm"
garciadeblas5697b8b2021-03-24 09:17:02 +01004145 elif ee_item["juju"].get("proxy") is False:
tierno588547c2020-07-01 15:30:20 +00004146 vca_type = "native_charm"
4147 elif ee_item.get("helm-chart"):
garciadeblas5697b8b2021-03-24 09:17:02 +01004148 vca_name = ee_item["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00004149 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
4150 vca_type = "helm"
4151 else:
4152 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00004153 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004154 self.logger.debug(
4155 logging_text + "skipping non juju neither charm configuration"
4156 )
quilesj7e13aeb2019-10-08 13:34:55 +02004157 continue
quilesj3655ae02019-12-12 16:08:35 +00004158
tierno588547c2020-07-01 15:30:20 +00004159 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004160 for vca_index, vca_deployed in enumerate(
4161 db_nsr["_admin"]["deployed"]["VCA"]
4162 ):
tierno588547c2020-07-01 15:30:20 +00004163 if not vca_deployed:
4164 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004165 if (
4166 vca_deployed.get("member-vnf-index") == member_vnf_index
4167 and vca_deployed.get("vdu_id") == vdu_id
4168 and vca_deployed.get("kdu_name") == kdu_name
4169 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4170 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4171 ):
tierno588547c2020-07-01 15:30:20 +00004172 break
4173 else:
4174 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004175 target = (
4176 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4177 )
tiernoa278b842020-07-08 15:33:55 +00004178 if vdu_id:
4179 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4180 elif kdu_name:
4181 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004182 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004183 "target_element": target,
4184 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004185 "member-vnf-index": member_vnf_index,
4186 "vdu_id": vdu_id,
4187 "kdu_name": kdu_name,
4188 "vdu_count_index": vdu_index,
4189 "operational-status": "init", # TODO revise
4190 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004191 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004192 "vnfd_id": vnfd_id,
4193 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004194 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004195 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004196 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004197 }
4198 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004199
tierno588547c2020-07-01 15:30:20 +00004200 # create VCA and configurationStatus in db
4201 db_dict = {
4202 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004203 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004204 }
4205 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004206
tierno588547c2020-07-01 15:30:20 +00004207 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4208
bravof922c4172020-11-24 21:21:43 -03004209 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4210 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4211 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4212
tierno588547c2020-07-01 15:30:20 +00004213 # Launch task
4214 task_n2vc = asyncio.ensure_future(
4215 self.instantiate_N2VC(
4216 logging_text=logging_text,
4217 vca_index=vca_index,
4218 nsi_id=nsi_id,
4219 db_nsr=db_nsr,
4220 db_vnfr=db_vnfr,
4221 vdu_id=vdu_id,
4222 kdu_name=kdu_name,
4223 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004224 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004225 deploy_params=deploy_params,
4226 config_descriptor=descriptor_config,
4227 base_folder=base_folder,
4228 nslcmop_id=nslcmop_id,
4229 stage=stage,
4230 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004231 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004232 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004233 )
quilesj7e13aeb2019-10-08 13:34:55 +02004234 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004235 self.lcm_tasks.register(
4236 "ns",
4237 nsr_id,
4238 nslcmop_id,
4239 "instantiate_N2VC-{}".format(vca_index),
4240 task_n2vc,
4241 )
4242 task_instantiation_info[
4243 task_n2vc
4244 ] = self.task_name_deploy_vca + " {}.{}".format(
4245 member_vnf_index or "", vdu_id or ""
4246 )
tiernobaa51102018-12-14 13:16:18 +00004247
tiernoc9556972019-07-05 15:25:25 +00004248 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02004249 def _create_nslcmop(nsr_id, operation, params):
4250 """
4251 Creates a ns-lcm-opp content to be stored at database.
4252 :param nsr_id: internal id of the instance
4253 :param operation: instantiate, terminate, scale, action, ...
4254 :param params: user parameters for the operation
4255 :return: dictionary following SOL005 format
4256 """
4257 # Raise exception if invalid arguments
4258 if not (nsr_id and operation and params):
4259 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004260 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided"
4261 )
kuuse0ca67472019-05-13 15:59:27 +02004262 now = time()
4263 _id = str(uuid4())
4264 nslcmop = {
4265 "id": _id,
4266 "_id": _id,
4267 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
4268 "operationState": "PROCESSING",
4269 "statusEnteredTime": now,
4270 "nsInstanceId": nsr_id,
4271 "lcmOperationType": operation,
4272 "startTime": now,
4273 "isAutomaticInvocation": False,
4274 "operationParams": params,
4275 "isCancelPending": False,
4276 "links": {
4277 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
4278 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004279 },
kuuse0ca67472019-05-13 15:59:27 +02004280 }
4281 return nslcmop
4282
calvinosanch9f9c6f22019-11-04 13:37:39 +01004283 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004284 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004285 for key, value in params.items():
4286 if str(value).startswith("!!yaml "):
4287 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004288 return params
4289
kuuse8b998e42019-07-30 15:22:16 +02004290 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004291 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004292 primitive_params = {}
4293 params = {
4294 "member_vnf_index": vnf_index,
4295 "primitive": primitive,
4296 "primitive_params": primitive_params,
4297 }
4298 desc_params = {}
4299 return self._map_primitive_params(seq, params, desc_params)
4300
kuuseac3a8882019-10-03 10:48:06 +02004301 # sub-operations
4302
tierno51183952020-04-03 15:48:18 +00004303 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004304 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4305 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004306 # b. Skip sub-operation
4307 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4308 return self.SUBOPERATION_STATUS_SKIP
4309 else:
tierno7c4e24c2020-05-13 08:41:35 +00004310 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004311 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004312 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004313 operationState = "PROCESSING"
4314 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004315 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004316 db_nslcmop, op_index, operationState, detailed_status
4317 )
kuuseac3a8882019-10-03 10:48:06 +02004318 # Return the sub-operation index
4319 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4320 # with arguments extracted from the sub-operation
4321 return op_index
4322
4323 # Find a sub-operation where all keys in a matching dictionary must match
4324 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4325 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004326 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004327 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004328 for i, op in enumerate(op_list):
4329 if all(op.get(k) == match[k] for k in match):
4330 return i
4331 return self.SUBOPERATION_STATUS_NOT_FOUND
4332
4333 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004334 def _update_suboperation_status(
4335 self, db_nslcmop, op_index, operationState, detailed_status
4336 ):
kuuseac3a8882019-10-03 10:48:06 +02004337 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004338 q_filter = {"_id": db_nslcmop["_id"]}
4339 update_dict = {
4340 "_admin.operations.{}.operationState".format(op_index): operationState,
4341 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4342 }
4343 self.db.set_one(
4344 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4345 )
kuuseac3a8882019-10-03 10:48:06 +02004346
4347 # Add sub-operation, return the index of the added sub-operation
4348 # Optionally, set operationState, detailed-status, and operationType
4349 # Status and type are currently set for 'scale' sub-operations:
4350 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4351 # 'detailed-status' : status message
4352 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4353 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004354 def _add_suboperation(
4355 self,
4356 db_nslcmop,
4357 vnf_index,
4358 vdu_id,
4359 vdu_count_index,
4360 vdu_name,
4361 primitive,
4362 mapped_primitive_params,
4363 operationState=None,
4364 detailed_status=None,
4365 operationType=None,
4366 RO_nsr_id=None,
4367 RO_scaling_info=None,
4368 ):
tiernoe876f672020-02-13 14:34:48 +00004369 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004370 return self.SUBOPERATION_STATUS_NOT_FOUND
4371 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004372 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4373 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004374 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004375 new_op = {
4376 "member_vnf_index": vnf_index,
4377 "vdu_id": vdu_id,
4378 "vdu_count_index": vdu_count_index,
4379 "primitive": primitive,
4380 "primitive_params": mapped_primitive_params,
4381 }
kuuseac3a8882019-10-03 10:48:06 +02004382 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004383 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004384 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004385 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004386 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004387 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004388 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004389 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004390 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004391 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004392 if not op_list:
4393 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004394 db_nslcmop_admin.update({"operations": [new_op]})
4395 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004396 else:
4397 # Existing operations, append operation to list
4398 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004399
garciadeblas5697b8b2021-03-24 09:17:02 +01004400 db_nslcmop_update = {"_admin.operations": op_list}
4401 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004402 op_index = len(op_list) - 1
4403 return op_index
4404
4405 # Helper methods for scale() sub-operations
4406
4407 # pre-scale/post-scale:
4408 # Check for 3 different cases:
4409 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4410 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004411 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004412 def _check_or_add_scale_suboperation(
4413 self,
4414 db_nslcmop,
4415 vnf_index,
4416 vnf_config_primitive,
4417 primitive_params,
4418 operationType,
4419 RO_nsr_id=None,
4420 RO_scaling_info=None,
4421 ):
kuuseac3a8882019-10-03 10:48:06 +02004422 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004423 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004424 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004425 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004426 "member_vnf_index": vnf_index,
4427 "RO_nsr_id": RO_nsr_id,
4428 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004429 }
4430 else:
4431 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004432 "member_vnf_index": vnf_index,
4433 "primitive": vnf_config_primitive,
4434 "primitive_params": primitive_params,
4435 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004436 }
4437 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004438 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004439 # a. New sub-operation
4440 # The sub-operation does not exist, add it.
4441 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4442 # The following parameters are set to None for all kind of scaling:
4443 vdu_id = None
4444 vdu_count_index = None
4445 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004446 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004447 vnf_config_primitive = None
4448 primitive_params = None
4449 else:
4450 RO_nsr_id = None
4451 RO_scaling_info = None
4452 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004453 operationState = "PROCESSING"
4454 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004455 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004456 self._add_suboperation(
4457 db_nslcmop,
4458 vnf_index,
4459 vdu_id,
4460 vdu_count_index,
4461 vdu_name,
4462 vnf_config_primitive,
4463 primitive_params,
4464 operationState,
4465 detailed_status,
4466 operationType,
4467 RO_nsr_id,
4468 RO_scaling_info,
4469 )
kuuseac3a8882019-10-03 10:48:06 +02004470 return self.SUBOPERATION_STATUS_NEW
4471 else:
4472 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4473 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004474 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004475
preethika.pdf7d8e02019-12-10 13:10:48 +00004476 # Function to return execution_environment id
4477
4478 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00004479 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00004480 for vca in vca_deployed_list:
4481 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
k4.rahul74944982023-04-19 17:00:52 +05304482 return vca.get("ee_id")
preethika.pdf7d8e02019-12-10 13:10:48 +00004483
David Garciac1fe90a2021-03-31 19:12:02 +02004484 async def destroy_N2VC(
4485 self,
4486 logging_text,
4487 db_nslcmop,
4488 vca_deployed,
4489 config_descriptor,
4490 vca_index,
4491 destroy_ee=True,
4492 exec_primitives=True,
4493 scaling_in=False,
4494 vca_id: str = None,
4495 ):
tiernoe876f672020-02-13 14:34:48 +00004496 """
4497 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4498 :param logging_text:
4499 :param db_nslcmop:
4500 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4501 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4502 :param vca_index: index in the database _admin.deployed.VCA
4503 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004504 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4505 not executed properly
aktas13251562021-02-12 22:19:10 +03004506 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004507 :return: None or exception
4508 """
tiernoe876f672020-02-13 14:34:48 +00004509
tierno588547c2020-07-01 15:30:20 +00004510 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004511 logging_text
4512 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004513 vca_index, vca_deployed, config_descriptor, destroy_ee
4514 )
4515 )
4516
4517 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4518
4519 # execute terminate_primitives
4520 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004521 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004522 config_descriptor.get("terminate-config-primitive"),
4523 vca_deployed.get("ee_descriptor_id"),
4524 )
tierno588547c2020-07-01 15:30:20 +00004525 vdu_id = vca_deployed.get("vdu_id")
4526 vdu_count_index = vca_deployed.get("vdu_count_index")
4527 vdu_name = vca_deployed.get("vdu_name")
4528 vnf_index = vca_deployed.get("member-vnf-index")
4529 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004530 for seq in terminate_primitives:
4531 # For each sequence in list, get primitive and call _ns_execute_primitive()
4532 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004533 vnf_index, seq.get("name")
4534 )
tierno588547c2020-07-01 15:30:20 +00004535 self.logger.debug(logging_text + step)
4536 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004537 primitive = seq.get("name")
4538 mapped_primitive_params = self._get_terminate_primitive_params(
4539 seq, vnf_index
4540 )
tierno588547c2020-07-01 15:30:20 +00004541
4542 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004543 self._add_suboperation(
4544 db_nslcmop,
4545 vnf_index,
4546 vdu_id,
4547 vdu_count_index,
4548 vdu_name,
4549 primitive,
4550 mapped_primitive_params,
4551 )
tierno588547c2020-07-01 15:30:20 +00004552 # Sub-operations: Call _ns_execute_primitive() instead of action()
4553 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004554 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004555 vca_deployed["ee_id"],
4556 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004557 mapped_primitive_params,
4558 vca_type=vca_type,
4559 vca_id=vca_id,
4560 )
tierno588547c2020-07-01 15:30:20 +00004561 except LcmException:
4562 # this happens when VCA is not deployed. In this case it is not needed to terminate
4563 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004564 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004565 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004566 raise LcmException(
4567 "terminate_primitive {} for vnf_member_index={} fails with "
4568 "error {}".format(seq.get("name"), vnf_index, result_detail)
4569 )
tierno588547c2020-07-01 15:30:20 +00004570 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004571 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4572 vca_index
4573 )
4574 self.update_db_2(
4575 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4576 )
tiernoe876f672020-02-13 14:34:48 +00004577
bravof73bac502021-05-11 07:38:47 -04004578 # Delete Prometheus Jobs if any
4579 # This uses NSR_ID, so it will destroy any jobs under this index
4580 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004581
tiernoe876f672020-02-13 14:34:48 +00004582 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004583 await self.vca_map[vca_type].delete_execution_environment(
4584 vca_deployed["ee_id"],
4585 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004586 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004587 vca_id=vca_id,
4588 )
kuuse0ca67472019-05-13 15:59:27 +02004589
David Garciac1fe90a2021-03-31 19:12:02 +02004590 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004591 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004592 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004593 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004594 await self.n2vc.delete_namespace(
4595 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004596 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004597 vca_id=vca_id,
4598 )
tiernof59ad6c2020-04-08 12:50:52 +00004599 except N2VCNotFound: # already deleted. Skip
4600 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004601 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004602
tiernoe876f672020-02-13 14:34:48 +00004603 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004604 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004605 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004606 if not task_is_locked_by_me:
4607 return
4608
tierno59d22d22018-09-25 18:10:19 +02004609 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4610 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004611 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004612 db_nsr = None
4613 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004614 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004615 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004616 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004617 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004618 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004619 tasks_dict_info = {}
4620 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004621 stage = [
4622 "Stage 1/3: Preparing task.",
4623 "Waiting for previous operations to terminate.",
4624 "",
4625 ]
tiernoe876f672020-02-13 14:34:48 +00004626 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004627 try:
kuused124bfe2019-06-18 12:09:24 +02004628 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004629 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004630
tiernoe876f672020-02-13 14:34:48 +00004631 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4632 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4633 operation_params = db_nslcmop.get("operationParams") or {}
4634 if operation_params.get("timeout_ns_terminate"):
4635 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4636 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4637 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4638
4639 db_nsr_update["operational-status"] = "terminating"
4640 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004641 self._write_ns_status(
4642 nsr_id=nsr_id,
4643 ns_state="TERMINATING",
4644 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004645 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004646 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004647 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004648 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004649 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004650 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4651 return
tierno59d22d22018-09-25 18:10:19 +02004652
tiernoe876f672020-02-13 14:34:48 +00004653 stage[1] = "Getting vnf descriptors from db."
4654 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004655 db_vnfrs_dict = {
4656 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4657 }
tiernoe876f672020-02-13 14:34:48 +00004658 db_vnfds_from_id = {}
4659 db_vnfds_from_member_index = {}
4660 # Loop over VNFRs
4661 for vnfr in db_vnfrs_list:
4662 vnfd_id = vnfr["vnfd-id"]
4663 if vnfd_id not in db_vnfds_from_id:
4664 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4665 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004666 db_vnfds_from_member_index[
4667 vnfr["member-vnf-index-ref"]
4668 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004669
tiernoe876f672020-02-13 14:34:48 +00004670 # Destroy individual execution environments when there are terminating primitives.
4671 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004672 # TODO - check before calling _destroy_N2VC
4673 # if not operation_params.get("skip_terminate_primitives"):#
4674 # or not vca.get("needed_terminate"):
4675 stage[0] = "Stage 2/3 execute terminating primitives."
4676 self.logger.debug(logging_text + stage[0])
4677 stage[1] = "Looking execution environment that needs terminate."
4678 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004679
tierno588547c2020-07-01 15:30:20 +00004680 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004681 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004682 vca_member_vnf_index = vca.get("member-vnf-index")
4683 vca_id = self.get_vca_id(
4684 db_vnfrs_dict.get(vca_member_vnf_index)
4685 if vca_member_vnf_index
4686 else None,
4687 db_nsr,
4688 )
tierno588547c2020-07-01 15:30:20 +00004689 if not vca or not vca.get("ee_id"):
4690 continue
4691 if not vca.get("member-vnf-index"):
4692 # ns
4693 config_descriptor = db_nsr.get("ns-configuration")
4694 elif vca.get("vdu_id"):
4695 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004696 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004697 elif vca.get("kdu_name"):
4698 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004699 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004700 else:
bravofe5a31bc2021-02-17 19:09:12 -03004701 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004702 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004703 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004704 exec_terminate_primitives = not operation_params.get(
4705 "skip_terminate_primitives"
4706 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004707 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4708 # pending native charms
garciadeblas5697b8b2021-03-24 09:17:02 +01004709 destroy_ee = (
4710 True if vca_type in ("helm", "helm-v3", "native_charm") else False
4711 )
tierno86e33612020-09-16 14:13:06 +00004712 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4713 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004714 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004715 self.destroy_N2VC(
4716 logging_text,
4717 db_nslcmop,
4718 vca,
4719 config_descriptor,
4720 vca_index,
4721 destroy_ee,
4722 exec_terminate_primitives,
4723 vca_id=vca_id,
4724 )
4725 )
tierno588547c2020-07-01 15:30:20 +00004726 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004727
tierno588547c2020-07-01 15:30:20 +00004728 # wait for pending tasks of terminate primitives
4729 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004730 self.logger.debug(
4731 logging_text
4732 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4733 )
4734 error_list = await self._wait_for_tasks(
4735 logging_text,
4736 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004737 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004738 stage,
4739 nslcmop_id,
4740 )
tierno86e33612020-09-16 14:13:06 +00004741 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004742 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004743 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004744
tiernoe876f672020-02-13 14:34:48 +00004745 # remove All execution environments at once
4746 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004747
tierno49676be2020-04-07 16:34:35 +00004748 if nsr_deployed.get("VCA"):
4749 stage[1] = "Deleting all execution environments."
4750 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02004751 vca_id = self.get_vca_id({}, db_nsr)
4752 task_delete_ee = asyncio.ensure_future(
4753 asyncio.wait_for(
4754 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
Luis Vegaa27dc532022-11-11 20:10:49 +00004755 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004756 )
4757 )
tierno49676be2020-04-07 16:34:35 +00004758 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
4759 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02004760
Gabriel Cuba1411a002022-10-07 11:38:23 -05004761 # Delete Namespace and Certificates if necessary
4762 if check_helm_ee_in_ns(list(db_vnfds_from_member_index.values())):
4763 await self.vca_map["helm-v3"].delete_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05004764 namespace=db_nslcmop["nsInstanceId"],
4765 certificate_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05004766 )
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05004767 await self.vca_map["helm-v3"].delete_namespace(
4768 namespace=db_nslcmop["nsInstanceId"],
4769 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05004770
tiernoe876f672020-02-13 14:34:48 +00004771 # Delete from k8scluster
4772 stage[1] = "Deleting KDUs."
4773 self.logger.debug(logging_text + stage[1])
4774 # print(nsr_deployed)
4775 for kdu in get_iterable(nsr_deployed, "K8s"):
4776 if not kdu or not kdu.get("kdu-instance"):
4777 continue
4778 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004779 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004780 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4781 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004782 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004783 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4784 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004785 kdu_instance=kdu_instance,
4786 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004787 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004788 )
4789 )
tiernoe876f672020-02-13 14:34:48 +00004790 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004791 self.logger.error(
4792 logging_text
4793 + "Unknown k8s deployment type {}".format(
4794 kdu.get("k8scluster-type")
4795 )
4796 )
tiernoe876f672020-02-13 14:34:48 +00004797 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004798 tasks_dict_info[
4799 task_delete_kdu_instance
4800 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004801
4802 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004803 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004804 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004805 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004806 self._terminate_ng_ro(
4807 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4808 )
4809 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004810 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004811
tiernoe876f672020-02-13 14:34:48 +00004812 # rest of staff will be done at finally
4813
garciadeblas5697b8b2021-03-24 09:17:02 +01004814 except (
4815 ROclient.ROClientException,
4816 DbException,
4817 LcmException,
4818 N2VCException,
4819 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004820 self.logger.error(logging_text + "Exit Exception {}".format(e))
4821 exc = e
4822 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004823 self.logger.error(
4824 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4825 )
tiernoe876f672020-02-13 14:34:48 +00004826 exc = "Operation was cancelled"
4827 except Exception as e:
4828 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004829 self.logger.critical(
4830 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4831 exc_info=True,
4832 )
tiernoe876f672020-02-13 14:34:48 +00004833 finally:
4834 if exc:
4835 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004836 try:
tiernoe876f672020-02-13 14:34:48 +00004837 # wait for pending tasks
4838 if tasks_dict_info:
4839 stage[1] = "Waiting for terminate pending tasks."
4840 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004841 error_list += await self._wait_for_tasks(
4842 logging_text,
4843 tasks_dict_info,
4844 timeout_ns_terminate,
4845 stage,
4846 nslcmop_id,
4847 )
tiernoe876f672020-02-13 14:34:48 +00004848 stage[1] = stage[2] = ""
4849 except asyncio.CancelledError:
4850 error_list.append("Cancelled")
4851 # TODO cancell all tasks
4852 except Exception as exc:
4853 error_list.append(str(exc))
4854 # update status at database
4855 if error_list:
4856 error_detail = "; ".join(error_list)
4857 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004858 error_description_nslcmop = "{} Detail: {}".format(
4859 stage[0], error_detail
4860 )
4861 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4862 nslcmop_id, stage[0]
4863 )
tierno59d22d22018-09-25 18:10:19 +02004864
tierno59d22d22018-09-25 18:10:19 +02004865 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004866 db_nsr_update["detailed-status"] = (
4867 error_description_nsr + " Detail: " + error_detail
4868 )
tiernoe876f672020-02-13 14:34:48 +00004869 db_nslcmop_update["detailed-status"] = error_detail
4870 nslcmop_operation_state = "FAILED"
4871 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004872 else:
tiernoa2143262020-03-27 16:20:40 +00004873 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004874 error_description_nsr = error_description_nslcmop = None
4875 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004876 db_nsr_update["operational-status"] = "terminated"
4877 db_nsr_update["detailed-status"] = "Done"
4878 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4879 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004880 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004881
tiernoe876f672020-02-13 14:34:48 +00004882 if db_nsr:
4883 self._write_ns_status(
4884 nsr_id=nsr_id,
4885 ns_state=ns_state,
4886 current_operation="IDLE",
4887 current_operation_id=None,
4888 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004889 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004890 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004891 )
tiernoa17d4f42020-04-28 09:59:23 +00004892 self._write_op_status(
4893 op_id=nslcmop_id,
4894 stage="",
4895 error_message=error_description_nslcmop,
4896 operation_state=nslcmop_operation_state,
4897 other_update=db_nslcmop_update,
4898 )
lloretgalleg6d488782020-07-22 10:13:46 +00004899 if ns_state == "NOT_INSTANTIATED":
4900 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004901 self.db.set_list(
4902 "vnfrs",
4903 {"nsr-id-ref": nsr_id},
4904 {"_admin.nsState": "NOT_INSTANTIATED"},
4905 )
lloretgalleg6d488782020-07-22 10:13:46 +00004906 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004907 self.logger.warn(
4908 logging_text
4909 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4910 nsr_id, e
4911 )
4912 )
tiernoa17d4f42020-04-28 09:59:23 +00004913 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004914 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004915 if nslcmop_operation_state:
4916 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004917 await self.msg.aiowrite(
4918 "ns",
4919 "terminated",
4920 {
4921 "nsr_id": nsr_id,
4922 "nslcmop_id": nslcmop_id,
4923 "operationState": nslcmop_operation_state,
4924 "autoremove": autoremove,
4925 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004926 )
tierno59d22d22018-09-25 18:10:19 +02004927 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004928 self.logger.error(
4929 logging_text + "kafka_write notification Exception {}".format(e)
4930 )
aguilard1ae3c562023-02-16 17:24:35 +00004931 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4932 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004933
tierno59d22d22018-09-25 18:10:19 +02004934 self.logger.debug(logging_text + "Exit")
4935 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4936
garciadeblas5697b8b2021-03-24 09:17:02 +01004937 async def _wait_for_tasks(
4938 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4939 ):
tiernoe876f672020-02-13 14:34:48 +00004940 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004941 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004942 error_list = []
4943 pending_tasks = list(created_tasks_info.keys())
4944 num_tasks = len(pending_tasks)
4945 num_done = 0
4946 stage[1] = "{}/{}.".format(num_done, num_tasks)
4947 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004948 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004949 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004950 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004951 done, pending_tasks = await asyncio.wait(
4952 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4953 )
tiernoe876f672020-02-13 14:34:48 +00004954 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004955 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004956 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004957 new_error = created_tasks_info[task] + ": Timeout"
4958 error_detail_list.append(new_error)
4959 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004960 break
4961 for task in done:
4962 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004963 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004964 else:
4965 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004966 if exc:
4967 if isinstance(exc, asyncio.TimeoutError):
4968 exc = "Timeout"
4969 new_error = created_tasks_info[task] + ": {}".format(exc)
4970 error_list.append(created_tasks_info[task])
4971 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004972 if isinstance(
4973 exc,
4974 (
4975 str,
4976 DbException,
4977 N2VCException,
4978 ROclient.ROClientException,
4979 LcmException,
4980 K8sException,
4981 NgRoException,
4982 ),
4983 ):
tierno067e04a2020-03-31 12:53:13 +00004984 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004985 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004986 exc_traceback = "".join(
4987 traceback.format_exception(None, exc, exc.__traceback__)
4988 )
4989 self.logger.error(
4990 logging_text
4991 + created_tasks_info[task]
4992 + " "
4993 + exc_traceback
4994 )
tierno067e04a2020-03-31 12:53:13 +00004995 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004996 self.logger.debug(
4997 logging_text + created_tasks_info[task] + ": Done"
4998 )
tiernoe876f672020-02-13 14:34:48 +00004999 stage[1] = "{}/{}.".format(num_done, num_tasks)
5000 if new_error:
tiernoa2143262020-03-27 16:20:40 +00005001 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00005002 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01005003 self.update_db_2(
5004 "nsrs",
5005 nsr_id,
5006 {
5007 "errorDescription": "Error at: " + ", ".join(error_list),
5008 "errorDetail": ". ".join(error_detail_list),
5009 },
5010 )
tiernoe876f672020-02-13 14:34:48 +00005011 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00005012 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00005013
tiernoda1ff8c2020-10-22 14:12:46 +00005014 @staticmethod
5015 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00005016 """
5017 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
5018 The default-value is used. If it is between < > it look for a value at instantiation_params
5019 :param primitive_desc: portion of VNFD/NSD that describes primitive
5020 :param params: Params provided by user
5021 :param instantiation_params: Instantiation params provided by user
5022 :return: a dictionary with the calculated params
5023 """
5024 calculated_params = {}
5025 for parameter in primitive_desc.get("parameter", ()):
5026 param_name = parameter["name"]
5027 if param_name in params:
5028 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00005029 elif "default-value" in parameter or "value" in parameter:
5030 if "value" in parameter:
5031 calculated_params[param_name] = parameter["value"]
5032 else:
5033 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005034 if (
5035 isinstance(calculated_params[param_name], str)
5036 and calculated_params[param_name].startswith("<")
5037 and calculated_params[param_name].endswith(">")
5038 ):
tierno98ad6ea2019-05-30 17:16:28 +00005039 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01005040 calculated_params[param_name] = instantiation_params[
5041 calculated_params[param_name][1:-1]
5042 ]
tiernoda964822019-01-14 15:53:47 +00005043 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005044 raise LcmException(
5045 "Parameter {} needed to execute primitive {} not provided".format(
5046 calculated_params[param_name], primitive_desc["name"]
5047 )
5048 )
tiernoda964822019-01-14 15:53:47 +00005049 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005050 raise LcmException(
5051 "Parameter {} needed to execute primitive {} not provided".format(
5052 param_name, primitive_desc["name"]
5053 )
5054 )
tierno59d22d22018-09-25 18:10:19 +02005055
tiernoda964822019-01-14 15:53:47 +00005056 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01005057 calculated_params[param_name] = yaml.safe_dump(
5058 calculated_params[param_name], default_flow_style=True, width=256
5059 )
5060 elif isinstance(calculated_params[param_name], str) and calculated_params[
5061 param_name
5062 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00005063 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00005064 if parameter.get("data-type") == "INTEGER":
5065 try:
5066 calculated_params[param_name] = int(calculated_params[param_name])
5067 except ValueError: # error converting string to int
5068 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01005069 "Parameter {} of primitive {} must be integer".format(
5070 param_name, primitive_desc["name"]
5071 )
5072 )
tiernofa40e692020-10-14 14:59:36 +00005073 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01005074 calculated_params[param_name] = not (
5075 (str(calculated_params[param_name])).lower() == "false"
5076 )
tiernoc3f2a822019-11-05 13:45:04 +00005077
5078 # add always ns_config_info if primitive name is config
5079 if primitive_desc["name"] == "config":
5080 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01005081 calculated_params["ns_config_info"] = instantiation_params[
5082 "ns_config_info"
5083 ]
tiernoda964822019-01-14 15:53:47 +00005084 return calculated_params
5085
garciadeblas5697b8b2021-03-24 09:17:02 +01005086 def _look_for_deployed_vca(
5087 self,
5088 deployed_vca,
5089 member_vnf_index,
5090 vdu_id,
5091 vdu_count_index,
5092 kdu_name=None,
5093 ee_descriptor_id=None,
5094 ):
tiernoe876f672020-02-13 14:34:48 +00005095 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
5096 for vca in deployed_vca:
5097 if not vca:
5098 continue
5099 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
5100 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01005101 if (
5102 vdu_count_index is not None
5103 and vdu_count_index != vca["vdu_count_index"]
5104 ):
tiernoe876f672020-02-13 14:34:48 +00005105 continue
5106 if kdu_name and kdu_name != vca["kdu_name"]:
5107 continue
tiernoa278b842020-07-08 15:33:55 +00005108 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
5109 continue
tiernoe876f672020-02-13 14:34:48 +00005110 break
5111 else:
5112 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01005113 raise LcmException(
5114 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
5115 " is not deployed".format(
5116 member_vnf_index,
5117 vdu_id,
5118 vdu_count_index,
5119 kdu_name,
5120 ee_descriptor_id,
5121 )
5122 )
tiernoe876f672020-02-13 14:34:48 +00005123 # get ee_id
5124 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01005125 vca_type = vca.get(
5126 "type", "lxc_proxy_charm"
5127 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00005128 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005129 raise LcmException(
5130 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
5131 "execution environment".format(
5132 member_vnf_index, vdu_id, kdu_name, vdu_count_index
5133 )
5134 )
tierno588547c2020-07-01 15:30:20 +00005135 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00005136
David Garciac1fe90a2021-03-31 19:12:02 +02005137 async def _ns_execute_primitive(
5138 self,
5139 ee_id,
5140 primitive,
5141 primitive_params,
5142 retries=0,
5143 retries_interval=30,
5144 timeout=None,
5145 vca_type=None,
5146 db_dict=None,
5147 vca_id: str = None,
5148 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005149 try:
tierno98ad6ea2019-05-30 17:16:28 +00005150 if primitive == "config":
5151 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005152
tierno588547c2020-07-01 15:30:20 +00005153 vca_type = vca_type or "lxc_proxy_charm"
5154
quilesj7e13aeb2019-10-08 13:34:55 +02005155 while retries >= 0:
5156 try:
tierno067e04a2020-03-31 12:53:13 +00005157 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005158 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005159 ee_id=ee_id,
5160 primitive_name=primitive,
5161 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005162 progress_timeout=self.timeout.progress_primitive,
5163 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005164 db_dict=db_dict,
5165 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005166 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005167 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005168 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005169 )
quilesj7e13aeb2019-10-08 13:34:55 +02005170 # execution was OK
5171 break
tierno067e04a2020-03-31 12:53:13 +00005172 except asyncio.CancelledError:
5173 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005174 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005175 retries -= 1
5176 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005177 self.logger.debug(
5178 "Error executing action {} on {} -> {}".format(
5179 primitive, ee_id, e
5180 )
5181 )
quilesj7e13aeb2019-10-08 13:34:55 +02005182 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005183 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005184 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005185 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005186 e = N2VCException(
5187 message="Timed out waiting for action to complete"
5188 )
5189 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005190
garciadeblas5697b8b2021-03-24 09:17:02 +01005191 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005192
tierno067e04a2020-03-31 12:53:13 +00005193 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005194 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005195 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005196 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005197
ksaikiranr3fde2c72021-03-15 10:39:06 +05305198 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5199 """
5200 Updating the vca_status with latest juju information in nsrs record
5201 :param: nsr_id: Id of the nsr
5202 :param: nslcmop_id: Id of the nslcmop
5203 :return: None
5204 """
5205
5206 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5207 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005208 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005209 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005210 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5211 cluster_uuid, kdu_instance, cluster_type = (
5212 k8s["k8scluster-uuid"],
5213 k8s["kdu-instance"],
5214 k8s["k8scluster-type"],
5215 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005216 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005217 cluster_uuid=cluster_uuid,
5218 kdu_instance=kdu_instance,
5219 filter={"_id": nsr_id},
5220 vca_id=vca_id,
5221 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005222 )
ksaikiranr656b6dd2021-02-19 10:25:18 +05305223 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005224 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305225 table, filter = "nsrs", {"_id": nsr_id}
5226 path = "_admin.deployed.VCA.{}.".format(vca_index)
5227 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305228
5229 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5230 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5231
tierno59d22d22018-09-25 18:10:19 +02005232 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005233 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005234 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005235 if not task_is_locked_by_me:
5236 return
5237
tierno59d22d22018-09-25 18:10:19 +02005238 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5239 self.logger.debug(logging_text + "Enter")
5240 # get all needed from database
5241 db_nsr = None
5242 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005243 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005244 db_nslcmop_update = {}
5245 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005246 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005247 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005248 step = ""
tierno59d22d22018-09-25 18:10:19 +02005249 try:
kuused124bfe2019-06-18 12:09:24 +02005250 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005251 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005252 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005253
quilesj4cda56b2019-12-05 10:02:20 +00005254 self._write_ns_status(
5255 nsr_id=nsr_id,
5256 ns_state=None,
5257 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005258 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005259 )
5260
tierno59d22d22018-09-25 18:10:19 +02005261 step = "Getting information from database"
5262 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5263 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005264 if db_nslcmop["operationParams"].get("primitive_params"):
5265 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5266 db_nslcmop["operationParams"]["primitive_params"]
5267 )
tiernoda964822019-01-14 15:53:47 +00005268
tiernoe4f7e6c2018-11-27 14:55:30 +00005269 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005270 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005271 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005272 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005273 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005274 primitive = db_nslcmop["operationParams"]["primitive"]
5275 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005276 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005277 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005278 )
tierno59d22d22018-09-25 18:10:19 +02005279
tierno1b633412019-02-25 16:48:23 +00005280 if vnf_index:
5281 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005282 db_vnfr = self.db.get_one(
5283 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5284 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005285 if db_vnfr.get("kdur"):
5286 kdur_list = []
5287 for kdur in db_vnfr["kdur"]:
5288 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005289 kdur["additionalParams"] = json.loads(
5290 kdur["additionalParams"]
5291 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005292 kdur_list.append(kdur)
5293 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005294 step = "Getting vnfd from database"
5295 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005296
5297 # Sync filesystem before running a primitive
5298 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005299 else:
tierno067e04a2020-03-31 12:53:13 +00005300 step = "Getting nsd from database"
5301 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005302
David Garciac1fe90a2021-03-31 19:12:02 +02005303 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005304 # for backward compatibility
5305 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5306 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5307 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5308 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5309
tiernoda964822019-01-14 15:53:47 +00005310 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005311 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005312 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005313 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005314 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005315 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005316 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005317 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005318 else:
tiernoa278b842020-07-08 15:33:55 +00005319 descriptor_configuration = db_nsd.get("ns-configuration")
5320
garciadeblas5697b8b2021-03-24 09:17:02 +01005321 if descriptor_configuration and descriptor_configuration.get(
5322 "config-primitive"
5323 ):
tiernoa278b842020-07-08 15:33:55 +00005324 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005325 if config_primitive["name"] == primitive:
5326 config_primitive_desc = config_primitive
5327 break
tiernoda964822019-01-14 15:53:47 +00005328
garciadeblas6bed6b32020-07-20 11:05:42 +00005329 if not config_primitive_desc:
5330 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005331 raise LcmException(
5332 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5333 primitive
5334 )
5335 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005336 primitive_name = primitive
5337 ee_descriptor_id = None
5338 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005339 primitive_name = config_primitive_desc.get(
5340 "execution-environment-primitive", primitive
5341 )
5342 ee_descriptor_id = config_primitive_desc.get(
5343 "execution-environment-ref"
5344 )
tierno1b633412019-02-25 16:48:23 +00005345
tierno1b633412019-02-25 16:48:23 +00005346 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005347 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005348 vdur = next(
5349 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5350 )
bravof922c4172020-11-24 21:21:43 -03005351 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005352 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005353 kdur = next(
5354 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5355 )
bravof922c4172020-11-24 21:21:43 -03005356 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005357 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005358 desc_params = parse_yaml_strings(
5359 db_vnfr.get("additionalParamsForVnf")
5360 )
tierno1b633412019-02-25 16:48:23 +00005361 else:
bravof922c4172020-11-24 21:21:43 -03005362 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005363 if kdu_name and get_configuration(db_vnfd, kdu_name):
5364 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005365 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005366 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005367 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005368 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005369 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005370 kdu = find_in_list(
5371 nsr_deployed["K8s"],
5372 lambda kdu: kdu_name == kdu["kdu-name"]
5373 and kdu["member-vnf-index"] == vnf_index,
5374 )
5375 kdu_action = (
5376 True
5377 if primitive_name in actions
5378 and kdu["k8scluster-type"] not in ("helm-chart", "helm-chart-v3")
5379 else False
5380 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005381
tiernoda964822019-01-14 15:53:47 +00005382 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005383 if kdu_name and (
5384 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5385 ):
tierno067e04a2020-03-31 12:53:13 +00005386 # TODO Check if we will need something at vnf level
5387 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005388 if (
5389 kdu_name == kdu["kdu-name"]
5390 and kdu["member-vnf-index"] == vnf_index
5391 ):
tierno067e04a2020-03-31 12:53:13 +00005392 break
5393 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005394 raise LcmException(
5395 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5396 )
quilesj7e13aeb2019-10-08 13:34:55 +02005397
tierno067e04a2020-03-31 12:53:13 +00005398 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005399 msg = "unknown k8scluster-type '{}'".format(
5400 kdu.get("k8scluster-type")
5401 )
tierno067e04a2020-03-31 12:53:13 +00005402 raise LcmException(msg)
5403
garciadeblas5697b8b2021-03-24 09:17:02 +01005404 db_dict = {
5405 "collection": "nsrs",
5406 "filter": {"_id": nsr_id},
5407 "path": "_admin.deployed.K8s.{}".format(index),
5408 }
5409 self.logger.debug(
5410 logging_text
5411 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5412 )
tiernoa278b842020-07-08 15:33:55 +00005413 step = "Executing kdu {}".format(primitive_name)
garciadeblas61412702024-07-19 12:08:07 +02005414 if primitive_name == "upgrade" and primitive_params:
5415 if primitive_params.get("kdu_model"):
5416 kdu_model = primitive_params.pop("kdu_model")
tierno067e04a2020-03-31 12:53:13 +00005417 else:
5418 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005419 if kdu_model.count("/") < 2: # helm chart is not embedded
5420 parts = kdu_model.split(sep=":")
5421 if len(parts) == 2:
5422 kdu_model = parts[0]
garciadeblas61412702024-07-19 12:08:07 +02005423 if primitive_params.get("kdu_atomic_upgrade"):
5424 atomic_upgrade = primitive_params.get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01005425 "kdu_atomic_upgrade"
5426 ).lower() in ("yes", "true", "1")
garciadeblas61412702024-07-19 12:08:07 +02005427 del primitive_params["kdu_atomic_upgrade"]
limondd8b0a62022-10-28 10:39:16 +02005428 else:
5429 atomic_upgrade = True
garciadeblasdceaef82024-02-08 14:11:51 +01005430 # Type of upgrade: reset, reuse, reset_then_reuse
5431 reset_values = False
5432 reuse_values = False
5433 reset_then_reuse_values = False
5434 # If no option is specified, default behaviour is reuse_values
5435 # Otherwise, options will be parsed and used
5436 if (
garciadeblas61412702024-07-19 12:08:07 +02005437 ("kdu_reset_values" not in primitive_params)
5438 and ("kdu_reuse_values" not in primitive_params)
5439 and ("kdu_reset_then_reuse_values" not in primitive_params)
garciadeblasdceaef82024-02-08 14:11:51 +01005440 ):
5441 reuse_values = True
5442 else:
garciadeblas61412702024-07-19 12:08:07 +02005443 if primitive_params.get("kdu_reset_values"):
5444 reset_values = primitive_params.pop(
garciadeblasdceaef82024-02-08 14:11:51 +01005445 "kdu_reset_values"
5446 ).lower() in ("yes", "true", "1")
garciadeblas61412702024-07-19 12:08:07 +02005447 if primitive_params.get("kdu_reuse_values"):
5448 reuse_values = primitive_params.pop(
garciadeblasdceaef82024-02-08 14:11:51 +01005449 "kdu_reuse_values"
5450 ).lower() in ("yes", "true", "1")
garciadeblas61412702024-07-19 12:08:07 +02005451 if primitive_params.get("kdu_reset_then_reuse_values"):
5452 reset_then_reuse_values = primitive_params.get(
garciadeblasdceaef82024-02-08 14:11:51 +01005453 "kdu_reset_then_reuse_values"
5454 ).lower() in ("yes", "true", "1")
5455 # Two true options are not possible
5456 if (
5457 sum([reset_values, reuse_values, reset_then_reuse_values])
5458 >= 2
5459 ):
5460 raise LcmException(
5461 "Cannot upgrade the KDU simultaneously with two true options to handle values"
5462 )
garciadeblas61412702024-07-19 12:08:07 +02005463 # kdur and desc_params already set from before
5464 if reset_values:
5465 desc_params = primitive_params
5466 else:
5467 desc_params.update(primitive_params)
tierno067e04a2020-03-31 12:53:13 +00005468 detailed_status = await asyncio.wait_for(
5469 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5470 cluster_uuid=kdu.get("k8scluster-uuid"),
5471 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005472 atomic=atomic_upgrade,
garciadeblasdceaef82024-02-08 14:11:51 +01005473 reset_values=reset_values,
5474 reuse_values=reuse_values,
5475 reset_then_reuse_values=reset_then_reuse_values,
garciadeblas5697b8b2021-03-24 09:17:02 +01005476 kdu_model=kdu_model,
5477 params=desc_params,
5478 db_dict=db_dict,
5479 timeout=timeout_ns_action,
5480 ),
5481 timeout=timeout_ns_action + 10,
5482 )
5483 self.logger.debug(
5484 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5485 )
tiernoa278b842020-07-08 15:33:55 +00005486 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005487 detailed_status = await asyncio.wait_for(
5488 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5489 cluster_uuid=kdu.get("k8scluster-uuid"),
5490 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005491 db_dict=db_dict,
5492 ),
5493 timeout=timeout_ns_action,
5494 )
tiernoa278b842020-07-08 15:33:55 +00005495 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005496 detailed_status = await asyncio.wait_for(
5497 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5498 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005499 kdu_instance=kdu.get("kdu-instance"),
5500 vca_id=vca_id,
5501 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005502 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005503 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005504 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005505 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5506 kdu["kdu-name"], nsr_id
5507 )
5508 params = self._map_primitive_params(
5509 config_primitive_desc, primitive_params, desc_params
5510 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005511
5512 detailed_status = await asyncio.wait_for(
5513 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5514 cluster_uuid=kdu.get("k8scluster-uuid"),
5515 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005516 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005517 params=params,
5518 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005519 timeout=timeout_ns_action,
5520 vca_id=vca_id,
5521 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005522 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005523 )
tierno067e04a2020-03-31 12:53:13 +00005524
5525 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005526 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005527 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005528 detailed_status = ""
5529 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005530 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005531 ee_id, vca_type = self._look_for_deployed_vca(
5532 nsr_deployed["VCA"],
5533 member_vnf_index=vnf_index,
5534 vdu_id=vdu_id,
5535 vdu_count_index=vdu_count_index,
5536 ee_descriptor_id=ee_descriptor_id,
5537 )
5538 for vca_index, vca_deployed in enumerate(
5539 db_nsr["_admin"]["deployed"]["VCA"]
5540 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305541 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005542 db_dict = {
5543 "collection": "nsrs",
5544 "filter": {"_id": nsr_id},
5545 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5546 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305547 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005548 (
5549 nslcmop_operation_state,
5550 detailed_status,
5551 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005552 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005553 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005554 primitive_params=self._map_primitive_params(
5555 config_primitive_desc, primitive_params, desc_params
5556 ),
tierno588547c2020-07-01 15:30:20 +00005557 timeout=timeout_ns_action,
5558 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005559 db_dict=db_dict,
5560 vca_id=vca_id,
5561 )
tierno067e04a2020-03-31 12:53:13 +00005562
5563 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005564 error_description_nslcmop = (
5565 detailed_status if nslcmop_operation_state == "FAILED" else ""
5566 )
5567 self.logger.debug(
5568 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005569 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005570 nslcmop_operation_state, detailed_status
5571 )
5572 )
tierno59d22d22018-09-25 18:10:19 +02005573 return # database update is called inside finally
5574
tiernof59ad6c2020-04-08 12:50:52 +00005575 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005576 self.logger.error(logging_text + "Exit Exception {}".format(e))
5577 exc = e
5578 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005579 self.logger.error(
5580 logging_text + "Cancelled Exception while '{}'".format(step)
5581 )
tierno59d22d22018-09-25 18:10:19 +02005582 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005583 except asyncio.TimeoutError:
5584 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5585 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005586 except Exception as e:
5587 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005588 self.logger.critical(
5589 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5590 exc_info=True,
5591 )
tierno59d22d22018-09-25 18:10:19 +02005592 finally:
tierno067e04a2020-03-31 12:53:13 +00005593 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005594 db_nslcmop_update[
5595 "detailed-status"
5596 ] = (
5597 detailed_status
5598 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005599 nslcmop_operation_state = "FAILED"
5600 if db_nsr:
5601 self._write_ns_status(
5602 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005603 ns_state=db_nsr[
5604 "nsState"
5605 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005606 current_operation="IDLE",
5607 current_operation_id=None,
5608 # error_description=error_description_nsr,
5609 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005610 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005611 )
5612
garciadeblas5697b8b2021-03-24 09:17:02 +01005613 self._write_op_status(
5614 op_id=nslcmop_id,
5615 stage="",
5616 error_message=error_description_nslcmop,
5617 operation_state=nslcmop_operation_state,
5618 other_update=db_nslcmop_update,
5619 )
tierno067e04a2020-03-31 12:53:13 +00005620
tierno59d22d22018-09-25 18:10:19 +02005621 if nslcmop_operation_state:
5622 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005623 await self.msg.aiowrite(
5624 "ns",
5625 "actioned",
5626 {
5627 "nsr_id": nsr_id,
5628 "nslcmop_id": nslcmop_id,
5629 "operationState": nslcmop_operation_state,
5630 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005631 )
tierno59d22d22018-09-25 18:10:19 +02005632 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005633 self.logger.error(
5634 logging_text + "kafka_write notification Exception {}".format(e)
5635 )
tierno59d22d22018-09-25 18:10:19 +02005636 self.logger.debug(logging_text + "Exit")
5637 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005638 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005639
elumalaica7ece02022-04-12 12:47:32 +05305640 async def terminate_vdus(
5641 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5642 ):
5643 """This method terminates VDUs
5644
5645 Args:
5646 db_vnfr: VNF instance record
5647 member_vnf_index: VNF index to identify the VDUs to be removed
5648 db_nsr: NS instance record
5649 update_db_nslcmops: Nslcmop update record
5650 """
5651 vca_scaling_info = []
5652 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5653 scaling_info["scaling_direction"] = "IN"
5654 scaling_info["vdu-delete"] = {}
5655 scaling_info["kdu-delete"] = {}
5656 db_vdur = db_vnfr.get("vdur")
5657 vdur_list = copy(db_vdur)
5658 count_index = 0
5659 for index, vdu in enumerate(vdur_list):
5660 vca_scaling_info.append(
5661 {
5662 "osm_vdu_id": vdu["vdu-id-ref"],
5663 "member-vnf-index": member_vnf_index,
5664 "type": "delete",
5665 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005666 }
5667 )
elumalaica7ece02022-04-12 12:47:32 +05305668 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5669 scaling_info["vdu"].append(
5670 {
5671 "name": vdu.get("name") or vdu.get("vdu-name"),
5672 "vdu_id": vdu["vdu-id-ref"],
5673 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005674 }
5675 )
elumalaica7ece02022-04-12 12:47:32 +05305676 for interface in vdu["interfaces"]:
5677 scaling_info["vdu"][index]["interface"].append(
5678 {
5679 "name": interface["name"],
5680 "ip_address": interface["ip-address"],
5681 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005682 }
5683 )
elumalaica7ece02022-04-12 12:47:32 +05305684 self.logger.info("NS update scaling info{}".format(scaling_info))
5685 stage[2] = "Terminating VDUs"
5686 if scaling_info.get("vdu-delete"):
5687 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005688 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305689 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005690 logging_text,
5691 db_nsr,
5692 update_db_nslcmops,
5693 db_vnfr,
5694 scaling_info,
5695 stage,
elumalaica7ece02022-04-12 12:47:32 +05305696 )
5697
preethika.p28b0bf82022-09-23 07:36:28 +00005698 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305699 """This method is to Remove VNF instances from NS.
5700
5701 Args:
5702 nsr_id: NS instance id
5703 nslcmop_id: nslcmop id of update
5704 vnf_instance_id: id of the VNF instance to be removed
5705
5706 Returns:
5707 result: (str, str) COMPLETED/FAILED, details
5708 """
5709 try:
5710 db_nsr_update = {}
5711 logging_text = "Task ns={} update ".format(nsr_id)
5712 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5713 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5714 if check_vnfr_count > 1:
5715 stage = ["", "", ""]
5716 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005717 self.logger.debug(
5718 step + " after having waited for previous tasks to be completed"
5719 )
elumalaica7ece02022-04-12 12:47:32 +05305720 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5721 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5722 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5723 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5724 """ db_vnfr = self.db.get_one(
5725 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5726
5727 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005728 await self.terminate_vdus(
5729 db_vnfr,
5730 member_vnf_index,
5731 db_nsr,
5732 update_db_nslcmops,
5733 stage,
5734 logging_text,
5735 )
elumalaica7ece02022-04-12 12:47:32 +05305736
5737 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5738 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005739 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5740 "constituent-vnfr-ref"
5741 )
elumalaica7ece02022-04-12 12:47:32 +05305742 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5743 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5744 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5745 return "COMPLETED", "Done"
5746 else:
5747 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005748 raise LcmException(
5749 "{} Cannot terminate the last VNF in this NS.".format(
5750 vnf_instance_id
5751 )
5752 )
elumalaica7ece02022-04-12 12:47:32 +05305753 except (LcmException, asyncio.CancelledError):
5754 raise
5755 except Exception as e:
5756 self.logger.debug("Error removing VNF {}".format(e))
5757 return "FAILED", "Error removing VNF {}".format(e)
5758
elumalaib9e357c2022-04-27 09:58:38 +05305759 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005760 self,
5761 nsr_id,
5762 nslcmop_id,
5763 db_vnfd,
5764 db_vnfr,
5765 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305766 ):
5767 """This method updates and redeploys VNF instances
5768
5769 Args:
5770 nsr_id: NS instance id
5771 nslcmop_id: nslcmop id
5772 db_vnfd: VNF descriptor
5773 db_vnfr: VNF instance record
5774 db_nsr: NS instance record
5775
5776 Returns:
5777 result: (str, str) COMPLETED/FAILED, details
5778 """
5779 try:
5780 count_index = 0
5781 stage = ["", "", ""]
5782 logging_text = "Task ns={} update ".format(nsr_id)
5783 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5784 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5785
5786 # Terminate old VNF resources
5787 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005788 await self.terminate_vdus(
5789 db_vnfr,
5790 member_vnf_index,
5791 db_nsr,
5792 update_db_nslcmops,
5793 stage,
5794 logging_text,
5795 )
elumalaib9e357c2022-04-27 09:58:38 +05305796
5797 # old_vnfd_id = db_vnfr["vnfd-id"]
5798 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5799 new_db_vnfd = db_vnfd
5800 # new_vnfd_ref = new_db_vnfd["id"]
5801 # new_vnfd_id = vnfd_id
5802
5803 # Create VDUR
5804 new_vnfr_cp = []
5805 for cp in new_db_vnfd.get("ext-cpd", ()):
5806 vnf_cp = {
5807 "name": cp.get("id"),
5808 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5809 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5810 "id": cp.get("id"),
5811 }
5812 new_vnfr_cp.append(vnf_cp)
5813 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5814 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5815 # 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 +00005816 new_vnfr_update = {
5817 "revision": latest_vnfd_revision,
5818 "connection-point": new_vnfr_cp,
5819 "vdur": new_vdur,
5820 "ip-address": "",
5821 }
elumalaib9e357c2022-04-27 09:58:38 +05305822 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5823 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005824 "vnfrs",
5825 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305826 )
5827
5828 # Instantiate new VNF resources
5829 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5830 vca_scaling_info = []
5831 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5832 scaling_info["scaling_direction"] = "OUT"
5833 scaling_info["vdu-create"] = {}
5834 scaling_info["kdu-create"] = {}
5835 vdud_instantiate_list = db_vnfd["vdu"]
5836 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005837 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305838 if cloud_init_text:
5839 additional_params = (
5840 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5841 or {}
5842 )
5843 cloud_init_list = []
5844 if cloud_init_text:
5845 # TODO Information of its own ip is not available because db_vnfr is not updated.
5846 additional_params["OSM"] = get_osm_params(
5847 updated_db_vnfr, vdud["id"], 1
5848 )
5849 cloud_init_list.append(
5850 self._parse_cloud_init(
5851 cloud_init_text,
5852 additional_params,
5853 db_vnfd["id"],
5854 vdud["id"],
5855 )
5856 )
5857 vca_scaling_info.append(
5858 {
5859 "osm_vdu_id": vdud["id"],
5860 "member-vnf-index": member_vnf_index,
5861 "type": "create",
5862 "vdu_index": count_index,
5863 }
5864 )
5865 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005866 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305867 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005868 "New Resources to be deployed: {}".format(scaling_info)
5869 )
elumalaib9e357c2022-04-27 09:58:38 +05305870 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005871 logging_text,
5872 db_nsr,
5873 update_db_nslcmops,
5874 updated_db_vnfr,
5875 scaling_info,
5876 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305877 )
5878 return "COMPLETED", "Done"
5879 except (LcmException, asyncio.CancelledError):
5880 raise
5881 except Exception as e:
5882 self.logger.debug("Error updating VNF {}".format(e))
5883 return "FAILED", "Error updating VNF {}".format(e)
5884
aticigdffa6212022-04-12 15:27:53 +03005885 async def _ns_charm_upgrade(
5886 self,
5887 ee_id,
5888 charm_id,
5889 charm_type,
5890 path,
5891 timeout: float = None,
5892 ) -> (str, str):
5893 """This method upgrade charms in VNF instances
5894
5895 Args:
5896 ee_id: Execution environment id
5897 path: Local path to the charm
5898 charm_id: charm-id
5899 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5900 timeout: (Float) Timeout for the ns update operation
5901
5902 Returns:
5903 result: (str, str) COMPLETED/FAILED, details
5904 """
5905 try:
5906 charm_type = charm_type or "lxc_proxy_charm"
5907 output = await self.vca_map[charm_type].upgrade_charm(
5908 ee_id=ee_id,
5909 path=path,
5910 charm_id=charm_id,
5911 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005912 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005913 )
5914
5915 if output:
5916 return "COMPLETED", output
5917
5918 except (LcmException, asyncio.CancelledError):
5919 raise
5920
5921 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005922 self.logger.debug("Error upgrading charm {}".format(path))
5923
5924 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5925
5926 async def update(self, nsr_id, nslcmop_id):
5927 """Update NS according to different update types
5928
5929 This method performs upgrade of VNF instances then updates the revision
5930 number in VNF record
5931
5932 Args:
5933 nsr_id: Network service will be updated
5934 nslcmop_id: ns lcm operation id
5935
5936 Returns:
5937 It may raise DbException, LcmException, N2VCException, K8sException
5938
5939 """
5940 # Try to lock HA task here
5941 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5942 if not task_is_locked_by_me:
5943 return
5944
5945 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5946 self.logger.debug(logging_text + "Enter")
5947
5948 # Set the required variables to be filled up later
5949 db_nsr = None
5950 db_nslcmop_update = {}
5951 vnfr_update = {}
5952 nslcmop_operation_state = None
5953 db_nsr_update = {}
5954 error_description_nslcmop = ""
5955 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305956 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005957 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005958 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005959
5960 try:
5961 # wait for any previous tasks in process
5962 step = "Waiting for previous operations to terminate"
5963 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5964 self._write_ns_status(
5965 nsr_id=nsr_id,
5966 ns_state=None,
5967 current_operation="UPDATING",
5968 current_operation_id=nslcmop_id,
5969 )
5970
5971 step = "Getting nslcmop from database"
5972 db_nslcmop = self.db.get_one(
5973 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5974 )
5975 update_type = db_nslcmop["operationParams"]["updateType"]
5976
5977 step = "Getting nsr from database"
5978 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5979 old_operational_status = db_nsr["operational-status"]
5980 db_nsr_update["operational-status"] = "updating"
5981 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5982 nsr_deployed = db_nsr["_admin"].get("deployed")
5983
5984 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005985 # Get the input parameters given through update request
5986 vnf_instance_id = db_nslcmop["operationParams"][
5987 "changeVnfPackageData"
5988 ].get("vnfInstanceId")
5989
5990 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5991 "vnfdId"
5992 )
5993 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5994
5995 step = "Getting vnfr from database"
5996 db_vnfr = self.db.get_one(
5997 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5998 )
5999
6000 step = "Getting vnfds from database"
6001 # Latest VNFD
6002 latest_vnfd = self.db.get_one(
6003 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
6004 )
6005 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
6006
6007 # Current VNFD
6008 current_vnf_revision = db_vnfr.get("revision", 1)
6009 current_vnfd = self.db.get_one(
6010 "vnfds_revisions",
6011 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
6012 fail_on_empty=False,
6013 )
6014 # Charm artifact paths will be filled up later
6015 (
6016 current_charm_artifact_path,
6017 target_charm_artifact_path,
6018 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01006019 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006020 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03006021
6022 step = "Checking if revision has changed in VNFD"
6023 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05306024 change_type = "policy_updated"
6025
aticigdffa6212022-04-12 15:27:53 +03006026 # There is new revision of VNFD, update operation is required
6027 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03006028 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03006029
6030 step = "Removing the VNFD packages if they exist in the local path"
6031 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
6032 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
6033
6034 step = "Get the VNFD packages from FSMongo"
6035 self.fs.sync(from_path=latest_vnfd_path)
6036 self.fs.sync(from_path=current_vnfd_path)
6037
6038 step = (
6039 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
6040 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006041 current_base_folder = current_vnfd["_admin"]["storage"]
6042 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03006043
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006044 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03006045 get_iterable(nsr_deployed, "VCA")
6046 ):
6047 vnf_index = db_vnfr.get("member-vnf-index-ref")
6048
6049 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006050 if vca_deployed.get("member-vnf-index") == vnf_index:
6051 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6052 vca_type = vca_deployed.get("type")
6053 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03006054
6055 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006056 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03006057
6058 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03006059 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03006060 search_key = "kdu_name"
6061 else:
6062 search_key = "vnfd_id"
6063
6064 entity_id = vca_deployed.get(search_key)
6065
aticigdffa6212022-04-12 15:27:53 +03006066 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03006067 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03006068 )
6069
6070 if "execution-environment-list" in descriptor_config:
6071 ee_list = descriptor_config.get(
6072 "execution-environment-list", []
6073 )
6074 else:
6075 ee_list = []
6076
6077 # There could be several charm used in the same VNF
6078 for ee_item in ee_list:
6079 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03006080 step = "Getting charm name"
6081 charm_name = ee_item["juju"].get("charm")
6082
6083 step = "Setting Charm artifact paths"
6084 current_charm_artifact_path.append(
6085 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006086 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03006087 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006088 vca_type,
aticigdffa6212022-04-12 15:27:53 +03006089 current_vnf_revision,
6090 )
6091 )
6092 target_charm_artifact_path.append(
6093 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006094 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03006095 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006096 vca_type,
aticigd7083542022-05-30 20:45:55 +03006097 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03006098 )
6099 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006100 elif ee_item.get("helm-chart"):
6101 # add chart to list and all parameters
6102 step = "Getting helm chart name"
6103 chart_name = ee_item.get("helm-chart")
garciadeblasfb1e25f2022-11-18 14:36:22 +01006104 if (
6105 ee_item.get("helm-version")
6106 and ee_item.get("helm-version") == "v2"
6107 ):
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006108 vca_type = "helm"
6109 else:
6110 vca_type = "helm-v3"
6111 step = "Setting Helm chart artifact paths"
6112
garciadeblasfb1e25f2022-11-18 14:36:22 +01006113 helm_artifacts.append(
6114 {
6115 "current_artifact_path": get_charm_artifact_path(
6116 current_base_folder,
6117 chart_name,
6118 vca_type,
6119 current_vnf_revision,
6120 ),
6121 "target_artifact_path": get_charm_artifact_path(
6122 latest_base_folder,
6123 chart_name,
6124 vca_type,
6125 latest_vnfd_revision,
6126 ),
6127 "ee_id": ee_id,
6128 "vca_index": vca_index,
6129 "vdu_index": vdu_count_index,
6130 }
6131 )
aticigdffa6212022-04-12 15:27:53 +03006132
6133 charm_artifact_paths = zip(
6134 current_charm_artifact_path, target_charm_artifact_path
6135 )
6136
6137 step = "Checking if software version has changed in VNFD"
6138 if find_software_version(current_vnfd) != find_software_version(
6139 latest_vnfd
6140 ):
aticigdffa6212022-04-12 15:27:53 +03006141 step = "Checking if existing VNF has charm"
6142 for current_charm_path, target_charm_path in list(
6143 charm_artifact_paths
6144 ):
6145 if current_charm_path:
6146 raise LcmException(
6147 "Software version change is not supported as VNF instance {} has charm.".format(
6148 vnf_instance_id
6149 )
6150 )
6151
6152 # There is no change in the charm package, then redeploy the VNF
6153 # based on new descriptor
6154 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306155 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006156 (result, detailed_status) = await self._ns_redeploy_vnf(
6157 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306158 )
6159 if result == "FAILED":
6160 nslcmop_operation_state = result
6161 error_description_nslcmop = detailed_status
elumalai34481e82023-11-16 14:36:05 +05306162 old_operational_status = "failed"
elumalaib9e357c2022-04-27 09:58:38 +05306163 db_nslcmop_update["detailed-status"] = detailed_status
elumalai34481e82023-11-16 14:36:05 +05306164 db_nsr_update["detailed-status"] = detailed_status
6165 scaling_aspect = get_scaling_aspect(latest_vnfd)
6166 scaling_group_desc = db_nsr.get("_admin").get(
6167 "scaling-group", None
6168 )
6169 if scaling_group_desc:
6170 for aspect in scaling_aspect:
6171 scaling_group_id = aspect.get("id")
6172 for scale_index, scaling_group in enumerate(
6173 scaling_group_desc
6174 ):
6175 if scaling_group.get("name") == scaling_group_id:
6176 db_nsr_update[
6177 "_admin.scaling-group.{}.nb-scale-op".format(
6178 scale_index
6179 )
6180 ] = 0
elumalaib9e357c2022-04-27 09:58:38 +05306181 self.logger.debug(
6182 logging_text
6183 + " step {} Done with result {} {}".format(
6184 step, nslcmop_operation_state, detailed_status
6185 )
6186 )
aticigdffa6212022-04-12 15:27:53 +03006187
6188 else:
6189 step = "Checking if any charm package has changed or not"
6190 for current_charm_path, target_charm_path in list(
6191 charm_artifact_paths
6192 ):
6193 if (
6194 current_charm_path
6195 and target_charm_path
6196 and self.check_charm_hash_changed(
6197 current_charm_path, target_charm_path
6198 )
6199 ):
aticigdffa6212022-04-12 15:27:53 +03006200 step = "Checking whether VNF uses juju bundle"
6201 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006202 raise LcmException(
6203 "Charm upgrade is not supported for the instance which"
6204 " uses juju-bundle: {}".format(
6205 check_juju_bundle_existence(current_vnfd)
6206 )
6207 )
6208
6209 step = "Upgrading Charm"
6210 (
6211 result,
6212 detailed_status,
6213 ) = await self._ns_charm_upgrade(
6214 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006215 charm_id=vca_id,
6216 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006217 path=self.fs.path + target_charm_path,
6218 timeout=timeout_seconds,
6219 )
6220
6221 if result == "FAILED":
6222 nslcmop_operation_state = result
6223 error_description_nslcmop = detailed_status
6224
6225 db_nslcmop_update["detailed-status"] = detailed_status
6226 self.logger.debug(
6227 logging_text
6228 + " step {} Done with result {} {}".format(
6229 step, nslcmop_operation_state, detailed_status
6230 )
6231 )
6232
6233 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306234 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6235 result = "COMPLETED"
6236 detailed_status = "Done"
6237 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006238
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006239 # helm base EE
6240 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006241 if not (
6242 item["current_artifact_path"]
6243 and item["target_artifact_path"]
6244 and self.check_charm_hash_changed(
6245 item["current_artifact_path"],
6246 item["target_artifact_path"],
6247 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006248 ):
6249 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006250 db_update_entry = "_admin.deployed.VCA.{}.".format(
6251 item["vca_index"]
6252 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006253 vnfr_id = db_vnfr["_id"]
6254 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6255 db_dict = {
6256 "collection": "nsrs",
6257 "filter": {"_id": nsr_id},
6258 "path": db_update_entry,
6259 }
6260 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006261 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006262 namespace=namespace,
6263 helm_id=helm_id,
6264 db_dict=db_dict,
6265 config=osm_config,
6266 artifact_path=item["target_artifact_path"],
6267 vca_type=vca_type,
6268 )
6269 vnf_id = db_vnfr.get("vnfd-ref")
6270 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6271 self.logger.debug("get ssh key block")
6272 rw_mgmt_ip = None
6273 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006274 config_descriptor,
6275 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006276 ):
6277 # Needed to inject a ssh key
6278 user = deep_get(
6279 config_descriptor,
6280 ("config-access", "ssh-access", "default-user"),
6281 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006282 step = (
6283 "Install configuration Software, getting public ssh key"
6284 )
6285 pub_key = await self.vca_map[
6286 vca_type
6287 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006288 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6289 )
6290
garciadeblasfb1e25f2022-11-18 14:36:22 +01006291 step = (
6292 "Insert public key into VM user={} ssh_key={}".format(
6293 user, pub_key
6294 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006295 )
6296 self.logger.debug(logging_text + step)
6297
6298 # wait for RO (ip-address) Insert pub_key into VM
6299 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6300 logging_text,
6301 nsr_id,
6302 vnfr_id,
6303 None,
6304 item["vdu_index"],
6305 user=user,
6306 pub_key=pub_key,
6307 )
6308
6309 initial_config_primitive_list = config_descriptor.get(
6310 "initial-config-primitive"
6311 )
6312 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006313 (
6314 p
6315 for p in initial_config_primitive_list
6316 if p["name"] == "config"
6317 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006318 None,
6319 )
6320 if not config_primitive:
6321 continue
6322
6323 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6324 if rw_mgmt_ip:
6325 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6326 if db_vnfr.get("additionalParamsForVnf"):
6327 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006328 parse_yaml_strings(
6329 db_vnfr["additionalParamsForVnf"].copy()
6330 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006331 )
6332 primitive_params_ = self._map_primitive_params(
6333 config_primitive, {}, deploy_params
6334 )
6335
6336 step = "execute primitive '{}' params '{}'".format(
6337 config_primitive["name"], primitive_params_
6338 )
6339 self.logger.debug(logging_text + step)
6340 await self.vca_map[vca_type].exec_primitive(
6341 ee_id=ee_id,
6342 primitive_name=config_primitive["name"],
6343 params_dict=primitive_params_,
6344 db_dict=db_dict,
6345 vca_id=vca_id,
6346 vca_type=vca_type,
6347 )
6348
6349 step = "Updating policies"
6350 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6351 detailed_status = "Done"
6352 db_nslcmop_update["detailed-status"] = "Done"
6353
aticigdffa6212022-04-12 15:27:53 +03006354 # If nslcmop_operation_state is None, so any operation is not failed.
6355 if not nslcmop_operation_state:
6356 nslcmop_operation_state = "COMPLETED"
6357
6358 # If update CHANGE_VNFPKG nslcmop_operation is successful
6359 # vnf revision need to be updated
6360 vnfr_update["revision"] = latest_vnfd_revision
6361 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6362
6363 self.logger.debug(
6364 logging_text
6365 + " task Done with result {} {}".format(
6366 nslcmop_operation_state, detailed_status
6367 )
6368 )
6369 elif update_type == "REMOVE_VNF":
6370 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306371 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6372 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6373 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6374 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006375 (result, detailed_status) = await self.remove_vnf(
6376 nsr_id, nslcmop_id, vnf_instance_id
6377 )
elumalaica7ece02022-04-12 12:47:32 +05306378 if result == "FAILED":
6379 nslcmop_operation_state = result
6380 error_description_nslcmop = detailed_status
6381 db_nslcmop_update["detailed-status"] = detailed_status
6382 change_type = "vnf_terminated"
6383 if not nslcmop_operation_state:
6384 nslcmop_operation_state = "COMPLETED"
6385 self.logger.debug(
6386 logging_text
6387 + " task Done with result {} {}".format(
6388 nslcmop_operation_state, detailed_status
6389 )
6390 )
aticigdffa6212022-04-12 15:27:53 +03006391
k4.rahulb827de92022-05-02 16:35:02 +00006392 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006393 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6394 "vnfInstanceId"
6395 ]
6396 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6397 "changeStateTo"
6398 ]
6399 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6400 "additionalParam"
6401 ]
k4.rahulb827de92022-05-02 16:35:02 +00006402 (result, detailed_status) = await self.rebuild_start_stop(
6403 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006404 )
k4.rahulb827de92022-05-02 16:35:02 +00006405 if result == "FAILED":
6406 nslcmop_operation_state = result
6407 error_description_nslcmop = detailed_status
6408 db_nslcmop_update["detailed-status"] = detailed_status
6409 if not nslcmop_operation_state:
6410 nslcmop_operation_state = "COMPLETED"
6411 self.logger.debug(
6412 logging_text
6413 + " task Done with result {} {}".format(
6414 nslcmop_operation_state, detailed_status
6415 )
6416 )
6417
aticigdffa6212022-04-12 15:27:53 +03006418 # If nslcmop_operation_state is None, so any operation is not failed.
6419 # All operations are executed in overall.
6420 if not nslcmop_operation_state:
6421 nslcmop_operation_state = "COMPLETED"
6422 db_nsr_update["operational-status"] = old_operational_status
6423
6424 except (DbException, LcmException, N2VCException, K8sException) as e:
6425 self.logger.error(logging_text + "Exit Exception {}".format(e))
6426 exc = e
6427 except asyncio.CancelledError:
6428 self.logger.error(
6429 logging_text + "Cancelled Exception while '{}'".format(step)
6430 )
6431 exc = "Operation was cancelled"
6432 except asyncio.TimeoutError:
6433 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6434 exc = "Timeout"
6435 except Exception as e:
6436 exc = traceback.format_exc()
6437 self.logger.critical(
6438 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6439 exc_info=True,
6440 )
6441 finally:
6442 if exc:
6443 db_nslcmop_update[
6444 "detailed-status"
6445 ] = (
6446 detailed_status
6447 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6448 nslcmop_operation_state = "FAILED"
6449 db_nsr_update["operational-status"] = old_operational_status
6450 if db_nsr:
6451 self._write_ns_status(
6452 nsr_id=nsr_id,
6453 ns_state=db_nsr["nsState"],
6454 current_operation="IDLE",
6455 current_operation_id=None,
6456 other_update=db_nsr_update,
6457 )
6458
6459 self._write_op_status(
6460 op_id=nslcmop_id,
6461 stage="",
6462 error_message=error_description_nslcmop,
6463 operation_state=nslcmop_operation_state,
6464 other_update=db_nslcmop_update,
6465 )
6466
6467 if nslcmop_operation_state:
6468 try:
elumalaica7ece02022-04-12 12:47:32 +05306469 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306470 "nsr_id": nsr_id,
6471 "nslcmop_id": nslcmop_id,
6472 "operationState": nslcmop_operation_state,
6473 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006474 if (
6475 change_type in ("vnf_terminated", "policy_updated")
6476 and member_vnf_index
6477 ):
elumalaica7ece02022-04-12 12:47:32 +05306478 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006479 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006480 except Exception as e:
6481 self.logger.error(
6482 logging_text + "kafka_write notification Exception {}".format(e)
6483 )
6484 self.logger.debug(logging_text + "Exit")
6485 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6486 return nslcmop_operation_state, detailed_status
6487
tierno59d22d22018-09-25 18:10:19 +02006488 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006489 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006490 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006491 if not task_is_locked_by_me:
6492 return
6493
tierno59d22d22018-09-25 18:10:19 +02006494 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006495 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006496 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006497 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006498 self.logger.debug(logging_text + "Enter")
6499 # get all needed from database
6500 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006501 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006502 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006503 exc = None
tierno9ab95942018-10-10 16:44:22 +02006504 # in case of error, indicates what part of scale was failed to put nsr at error status
6505 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006506 old_operational_status = ""
6507 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006508 nsi_id = None
Rahul Kumar2864cff2023-11-09 08:34:27 +00006509 prom_job_name = ""
tierno59d22d22018-09-25 18:10:19 +02006510 try:
kuused124bfe2019-06-18 12:09:24 +02006511 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006512 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006513 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6514 self._write_ns_status(
6515 nsr_id=nsr_id,
6516 ns_state=None,
6517 current_operation="SCALING",
6518 current_operation_id=nslcmop_id,
6519 )
quilesj4cda56b2019-12-05 10:02:20 +00006520
ikalyvas02d9e7b2019-05-27 18:16:01 +03006521 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006522 self.logger.debug(
6523 step + " after having waited for previous tasks to be completed"
6524 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006525 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006526
ikalyvas02d9e7b2019-05-27 18:16:01 +03006527 step = "Getting nsr from database"
6528 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006529 old_operational_status = db_nsr["operational-status"]
6530 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006531
tierno59d22d22018-09-25 18:10:19 +02006532 step = "Parsing scaling parameters"
6533 db_nsr_update["operational-status"] = "scaling"
6534 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006535 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006536
garciadeblas5697b8b2021-03-24 09:17:02 +01006537 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6538 "scaleByStepData"
6539 ]["member-vnf-index"]
6540 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6541 "scaleByStepData"
6542 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006543 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006544 # for backward compatibility
6545 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6546 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6547 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6548 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6549
tierno59d22d22018-09-25 18:10:19 +02006550 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006551 db_vnfr = self.db.get_one(
6552 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6553 )
bravof922c4172020-11-24 21:21:43 -03006554
David Garciac1fe90a2021-03-31 19:12:02 +02006555 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6556
tierno59d22d22018-09-25 18:10:19 +02006557 step = "Getting vnfd from database"
6558 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006559
aktas13251562021-02-12 22:19:10 +03006560 base_folder = db_vnfd["_admin"]["storage"]
6561
tierno59d22d22018-09-25 18:10:19 +02006562 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006563 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006564 get_scaling_aspect(db_vnfd),
6565 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006566 )
6567 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006568 raise LcmException(
6569 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6570 "at vnfd:scaling-group-descriptor".format(scaling_group)
6571 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006572
tierno15b1cf12019-08-29 13:21:40 +00006573 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006574 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006575 nb_scale_op = 0
6576 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006577 self.update_db_2(
6578 "nsrs",
6579 nsr_id,
6580 {
6581 "_admin.scaling-group": [
6582 {"name": scaling_group, "nb-scale-op": 0}
6583 ]
6584 },
6585 )
tierno59d22d22018-09-25 18:10:19 +02006586 admin_scale_index = 0
6587 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006588 for admin_scale_index, admin_scale_info in enumerate(
6589 db_nsr["_admin"]["scaling-group"]
6590 ):
tierno59d22d22018-09-25 18:10:19 +02006591 if admin_scale_info["name"] == scaling_group:
6592 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6593 break
tierno9ab95942018-10-10 16:44:22 +02006594 else: # not found, set index one plus last element and add new entry with the name
6595 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006596 db_nsr_update[
6597 "_admin.scaling-group.{}.name".format(admin_scale_index)
6598 ] = scaling_group
aktas5f75f102021-03-15 11:26:10 +03006599
6600 vca_scaling_info = []
6601 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006602 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006603 if "aspect-delta-details" not in scaling_descriptor:
6604 raise LcmException(
6605 "Aspect delta details not fount in scaling descriptor {}".format(
6606 scaling_descriptor["name"]
6607 )
6608 )
tierno59d22d22018-09-25 18:10:19 +02006609 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006610 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006611
aktas5f75f102021-03-15 11:26:10 +03006612 scaling_info["scaling_direction"] = "OUT"
6613 scaling_info["vdu-create"] = {}
6614 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006615 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006616 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006617 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006618 # vdu_index also provides the number of instance of the targeted vdu
6619 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
Rahul Kumar2864cff2023-11-09 08:34:27 +00006620 if vdu_index <= len(db_vnfr["vdur"]):
6621 vdu_name_id = db_vnfr["vdur"][vdu_index - 1]["vdu-name"]
6622 prom_job_name = (
6623 db_vnfr["_id"] + vdu_name_id + str(vdu_index - 1)
6624 )
6625 prom_job_name = prom_job_name.replace("_", "")
6626 prom_job_name = prom_job_name.replace("-", "")
6627 else:
6628 prom_job_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01006629 cloud_init_text = self._get_vdu_cloud_init_content(
6630 vdud, db_vnfd
6631 )
tierno72ef84f2020-10-06 08:22:07 +00006632 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006633 additional_params = (
6634 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6635 or {}
6636 )
bravof832f8992020-12-07 12:57:31 -03006637 cloud_init_list = []
6638
6639 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6640 max_instance_count = 10
6641 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006642 max_instance_count = vdu_profile.get(
6643 "max-number-of-instances", 10
6644 )
6645
6646 default_instance_num = get_number_of_instances(
6647 db_vnfd, vdud["id"]
6648 )
aktas5f75f102021-03-15 11:26:10 +03006649 instances_number = vdu_delta.get("number-of-instances", 1)
6650 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006651
aktas5f75f102021-03-15 11:26:10 +03006652 new_instance_count = nb_scale_op + default_instance_num
6653 # Control if new count is over max and vdu count is less than max.
6654 # Then assign new instance count
6655 if new_instance_count > max_instance_count > vdu_count:
6656 instances_number = new_instance_count - max_instance_count
6657 else:
6658 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006659
aktas5f75f102021-03-15 11:26:10 +03006660 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006661 raise LcmException(
6662 "reached the limit of {} (max-instance-count) "
6663 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006664 "scaling-group-descriptor '{}'".format(
6665 nb_scale_op, scaling_group
6666 )
bravof922c4172020-11-24 21:21:43 -03006667 )
bravof832f8992020-12-07 12:57:31 -03006668 for x in range(vdu_delta.get("number-of-instances", 1)):
6669 if cloud_init_text:
6670 # TODO Information of its own ip is not available because db_vnfr is not updated.
6671 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006672 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006673 )
bravof832f8992020-12-07 12:57:31 -03006674 cloud_init_list.append(
6675 self._parse_cloud_init(
6676 cloud_init_text,
6677 additional_params,
6678 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006679 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006680 )
6681 )
aktas5f75f102021-03-15 11:26:10 +03006682 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006683 {
6684 "osm_vdu_id": vdu_delta["id"],
6685 "member-vnf-index": vnf_index,
6686 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006687 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006688 }
6689 )
aktas5f75f102021-03-15 11:26:10 +03006690 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6691 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006692 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006693 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006694 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006695
6696 # Might have different kdus in the same delta
6697 # Should have list for each kdu
6698 if not scaling_info["kdu-create"].get(kdu_name, None):
6699 scaling_info["kdu-create"][kdu_name] = []
6700
6701 kdur = get_kdur(db_vnfr, kdu_name)
6702 if kdur.get("helm-chart"):
6703 k8s_cluster_type = "helm-chart-v3"
6704 self.logger.debug("kdur: {}".format(kdur))
6705 if (
6706 kdur.get("helm-version")
6707 and kdur.get("helm-version") == "v2"
6708 ):
6709 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006710 elif kdur.get("juju-bundle"):
6711 k8s_cluster_type = "juju-bundle"
6712 else:
6713 raise LcmException(
6714 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6715 "juju-bundle. Maybe an old NBI version is running".format(
6716 db_vnfr["member-vnf-index-ref"], kdu_name
6717 )
6718 )
6719
6720 max_instance_count = 10
6721 if kdu_profile and "max-number-of-instances" in kdu_profile:
6722 max_instance_count = kdu_profile.get(
6723 "max-number-of-instances", 10
6724 )
6725
6726 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6727 deployed_kdu, _ = get_deployed_kdu(
6728 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006729 )
aktas5f75f102021-03-15 11:26:10 +03006730 if deployed_kdu is None:
6731 raise LcmException(
6732 "KDU '{}' for vnf '{}' not deployed".format(
6733 kdu_name, vnf_index
6734 )
6735 )
6736 kdu_instance = deployed_kdu.get("kdu-instance")
6737 instance_num = await self.k8scluster_map[
6738 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006739 ].get_scale_count(
6740 resource_name,
6741 kdu_instance,
6742 vca_id=vca_id,
6743 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6744 kdu_model=deployed_kdu.get("kdu-model"),
6745 )
aktas5f75f102021-03-15 11:26:10 +03006746 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006747 "number-of-instances", 1
6748 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006749
aktas5f75f102021-03-15 11:26:10 +03006750 # Control if new count is over max and instance_num is less than max.
6751 # Then assign max instance number to kdu replica count
6752 if kdu_replica_count > max_instance_count > instance_num:
6753 kdu_replica_count = max_instance_count
6754 if kdu_replica_count > max_instance_count:
6755 raise LcmException(
6756 "reached the limit of {} (max-instance-count) "
6757 "scaling-out operations for the "
6758 "scaling-group-descriptor '{}'".format(
6759 instance_num, scaling_group
6760 )
6761 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006762
aktas5f75f102021-03-15 11:26:10 +03006763 for x in range(kdu_delta.get("number-of-instances", 1)):
6764 vca_scaling_info.append(
6765 {
6766 "osm_kdu_id": kdu_name,
6767 "member-vnf-index": vnf_index,
6768 "type": "create",
6769 "kdu_index": instance_num + x - 1,
6770 }
6771 )
6772 scaling_info["kdu-create"][kdu_name].append(
6773 {
6774 "member-vnf-index": vnf_index,
6775 "type": "create",
6776 "k8s-cluster-type": k8s_cluster_type,
6777 "resource-name": resource_name,
6778 "scale": kdu_replica_count,
6779 }
6780 )
6781 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006782 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006783
6784 scaling_info["scaling_direction"] = "IN"
6785 scaling_info["vdu-delete"] = {}
6786 scaling_info["kdu-delete"] = {}
6787
bravof832f8992020-12-07 12:57:31 -03006788 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006789 for vdu_delta in delta.get("vdu-delta", {}):
6790 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006791 min_instance_count = 0
6792 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6793 if vdu_profile and "min-number-of-instances" in vdu_profile:
6794 min_instance_count = vdu_profile["min-number-of-instances"]
6795
garciadeblas5697b8b2021-03-24 09:17:02 +01006796 default_instance_num = get_number_of_instances(
6797 db_vnfd, vdu_delta["id"]
6798 )
aktas5f75f102021-03-15 11:26:10 +03006799 instance_num = vdu_delta.get("number-of-instances", 1)
6800 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006801
aktas5f75f102021-03-15 11:26:10 +03006802 new_instance_count = nb_scale_op + default_instance_num
6803
6804 if new_instance_count < min_instance_count < vdu_count:
6805 instances_number = min_instance_count - new_instance_count
6806 else:
6807 instances_number = instance_num
6808
6809 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006810 raise LcmException(
6811 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006812 "scaling-group-descriptor '{}'".format(
6813 nb_scale_op, scaling_group
6814 )
bravof832f8992020-12-07 12:57:31 -03006815 )
aktas13251562021-02-12 22:19:10 +03006816 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006817 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006818 {
6819 "osm_vdu_id": vdu_delta["id"],
6820 "member-vnf-index": vnf_index,
6821 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006822 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006823 }
6824 )
aktas5f75f102021-03-15 11:26:10 +03006825 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6826 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006827 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006828 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006829 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006830
6831 if not scaling_info["kdu-delete"].get(kdu_name, None):
6832 scaling_info["kdu-delete"][kdu_name] = []
6833
6834 kdur = get_kdur(db_vnfr, kdu_name)
6835 if kdur.get("helm-chart"):
6836 k8s_cluster_type = "helm-chart-v3"
6837 self.logger.debug("kdur: {}".format(kdur))
6838 if (
6839 kdur.get("helm-version")
6840 and kdur.get("helm-version") == "v2"
6841 ):
6842 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006843 elif kdur.get("juju-bundle"):
6844 k8s_cluster_type = "juju-bundle"
6845 else:
6846 raise LcmException(
6847 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6848 "juju-bundle. Maybe an old NBI version is running".format(
6849 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6850 )
6851 )
6852
6853 min_instance_count = 0
6854 if kdu_profile and "min-number-of-instances" in kdu_profile:
6855 min_instance_count = kdu_profile["min-number-of-instances"]
6856
6857 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6858 deployed_kdu, _ = get_deployed_kdu(
6859 nsr_deployed, kdu_name, vnf_index
6860 )
6861 if deployed_kdu is None:
6862 raise LcmException(
6863 "KDU '{}' for vnf '{}' not deployed".format(
6864 kdu_name, vnf_index
6865 )
6866 )
6867 kdu_instance = deployed_kdu.get("kdu-instance")
6868 instance_num = await self.k8scluster_map[
6869 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006870 ].get_scale_count(
6871 resource_name,
6872 kdu_instance,
6873 vca_id=vca_id,
6874 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6875 kdu_model=deployed_kdu.get("kdu-model"),
6876 )
aktas5f75f102021-03-15 11:26:10 +03006877 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006878 "number-of-instances", 1
6879 )
tierno59d22d22018-09-25 18:10:19 +02006880
aktas5f75f102021-03-15 11:26:10 +03006881 if kdu_replica_count < min_instance_count < instance_num:
6882 kdu_replica_count = min_instance_count
6883 if kdu_replica_count < min_instance_count:
6884 raise LcmException(
6885 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6886 "scaling-group-descriptor '{}'".format(
6887 instance_num, scaling_group
6888 )
6889 )
6890
6891 for x in range(kdu_delta.get("number-of-instances", 1)):
6892 vca_scaling_info.append(
6893 {
6894 "osm_kdu_id": kdu_name,
6895 "member-vnf-index": vnf_index,
6896 "type": "delete",
6897 "kdu_index": instance_num - x - 1,
6898 }
6899 )
6900 scaling_info["kdu-delete"][kdu_name].append(
6901 {
6902 "member-vnf-index": vnf_index,
6903 "type": "delete",
6904 "k8s-cluster-type": k8s_cluster_type,
6905 "resource-name": resource_name,
6906 "scale": kdu_replica_count,
6907 }
6908 )
6909
tierno59d22d22018-09-25 18:10:19 +02006910 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006911 vdu_delete = copy(scaling_info.get("vdu-delete"))
6912 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006913 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006914 if vdu_delete.get(vdur["vdu-id-ref"]):
6915 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006916 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006917 {
6918 "name": vdur.get("name") or vdur.get("vdu-name"),
6919 "vdu_id": vdur["vdu-id-ref"],
6920 "interface": [],
6921 }
6922 )
tierno59d22d22018-09-25 18:10:19 +02006923 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006924 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006925 {
6926 "name": interface["name"],
6927 "ip_address": interface["ip-address"],
6928 "mac_address": interface.get("mac-address"),
6929 }
6930 )
tierno2357f4e2020-10-19 16:38:59 +00006931 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006932
kuuseac3a8882019-10-03 10:48:06 +02006933 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006934 step = "Executing pre-scale vnf-config-primitive"
6935 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006936 for scaling_config_action in scaling_descriptor[
6937 "scaling-config-action"
6938 ]:
6939 if (
6940 scaling_config_action.get("trigger") == "pre-scale-in"
6941 and scaling_type == "SCALE_IN"
6942 ) or (
6943 scaling_config_action.get("trigger") == "pre-scale-out"
6944 and scaling_type == "SCALE_OUT"
6945 ):
6946 vnf_config_primitive = scaling_config_action[
6947 "vnf-config-primitive-name-ref"
6948 ]
6949 step = db_nslcmop_update[
6950 "detailed-status"
6951 ] = "executing pre-scale scaling-config-action '{}'".format(
6952 vnf_config_primitive
6953 )
tiernoda964822019-01-14 15:53:47 +00006954
tierno59d22d22018-09-25 18:10:19 +02006955 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006956 for config_primitive in (
6957 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6958 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006959 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006960 break
6961 else:
6962 raise LcmException(
6963 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006964 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006965 "primitive".format(scaling_group, vnf_config_primitive)
6966 )
tiernoda964822019-01-14 15:53:47 +00006967
aktas5f75f102021-03-15 11:26:10 +03006968 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006969 if db_vnfr.get("additionalParamsForVnf"):
6970 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006971
tierno9ab95942018-10-10 16:44:22 +02006972 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006973 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006974 primitive_params = self._map_primitive_params(
6975 config_primitive, {}, vnfr_params
6976 )
kuuseac3a8882019-10-03 10:48:06 +02006977
tierno7c4e24c2020-05-13 08:41:35 +00006978 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006979 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006980 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006981 vnf_index,
6982 vnf_config_primitive,
6983 primitive_params,
6984 "PRE-SCALE",
6985 )
tierno7c4e24c2020-05-13 08:41:35 +00006986 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006987 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006988 result = "COMPLETED"
6989 result_detail = "Done"
6990 self.logger.debug(
6991 logging_text
6992 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6993 vnf_config_primitive, result, result_detail
6994 )
6995 )
kuuseac3a8882019-10-03 10:48:06 +02006996 else:
tierno7c4e24c2020-05-13 08:41:35 +00006997 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006998 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006999 op_index = (
7000 len(db_nslcmop.get("_admin", {}).get("operations"))
7001 - 1
7002 )
7003 self.logger.debug(
7004 logging_text
7005 + "vnf_config_primitive={} New sub-operation".format(
7006 vnf_config_primitive
7007 )
7008 )
kuuseac3a8882019-10-03 10:48:06 +02007009 else:
tierno7c4e24c2020-05-13 08:41:35 +00007010 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007011 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7012 op_index
7013 ]
7014 vnf_index = op.get("member_vnf_index")
7015 vnf_config_primitive = op.get("primitive")
7016 primitive_params = op.get("primitive_params")
7017 self.logger.debug(
7018 logging_text
7019 + "vnf_config_primitive={} Sub-operation retry".format(
7020 vnf_config_primitive
7021 )
7022 )
tierno588547c2020-07-01 15:30:20 +00007023 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007024 ee_descriptor_id = config_primitive.get(
7025 "execution-environment-ref"
7026 )
7027 primitive_name = config_primitive.get(
7028 "execution-environment-primitive", vnf_config_primitive
7029 )
7030 ee_id, vca_type = self._look_for_deployed_vca(
7031 nsr_deployed["VCA"],
7032 member_vnf_index=vnf_index,
7033 vdu_id=None,
7034 vdu_count_index=None,
7035 ee_descriptor_id=ee_descriptor_id,
7036 )
kuuseac3a8882019-10-03 10:48:06 +02007037 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01007038 ee_id,
7039 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02007040 primitive_params,
7041 vca_type=vca_type,
7042 vca_id=vca_id,
7043 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007044 self.logger.debug(
7045 logging_text
7046 + "vnf_config_primitive={} Done with result {} {}".format(
7047 vnf_config_primitive, result, result_detail
7048 )
7049 )
kuuseac3a8882019-10-03 10:48:06 +02007050 # Update operationState = COMPLETED | FAILED
7051 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007052 db_nslcmop, op_index, result, result_detail
7053 )
kuuseac3a8882019-10-03 10:48:06 +02007054
tierno59d22d22018-09-25 18:10:19 +02007055 if result == "FAILED":
7056 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007057 db_nsr_update["config-status"] = old_config_status
7058 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007059 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007060
garciadeblas5697b8b2021-03-24 09:17:02 +01007061 db_nsr_update[
7062 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
7063 ] = nb_scale_op
7064 db_nsr_update[
7065 "_admin.scaling-group.{}.time".format(admin_scale_index)
7066 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00007067
aktas13251562021-02-12 22:19:10 +03007068 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007069 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007070 step = db_nslcmop_update[
7071 "detailed-status"
7072 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007073 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007074 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007075 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007076 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007077 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007078 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007079 )
aktas5f75f102021-03-15 11:26:10 +03007080 if vca_info.get("osm_vdu_id"):
7081 vdu_id = vca_info["osm_vdu_id"]
7082 vdu_index = int(vca_info["vdu_index"])
7083 stage[
7084 1
7085 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7086 member_vnf_index, vdu_id, vdu_index
7087 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007088 stage[2] = step = "Scaling in VCA"
7089 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007090 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7091 config_update = db_nsr["configurationStatus"]
7092 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007093 if (
7094 (vca or vca.get("ee_id"))
7095 and vca["member-vnf-index"] == member_vnf_index
7096 and vca["vdu_count_index"] == vdu_index
7097 ):
aktas13251562021-02-12 22:19:10 +03007098 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007099 config_descriptor = get_configuration(
7100 db_vnfd, vca.get("vdu_id")
7101 )
aktas13251562021-02-12 22:19:10 +03007102 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007103 config_descriptor = get_configuration(
7104 db_vnfd, vca.get("kdu_name")
7105 )
aktas13251562021-02-12 22:19:10 +03007106 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007107 config_descriptor = get_configuration(
7108 db_vnfd, db_vnfd["id"]
7109 )
7110 operation_params = (
7111 db_nslcmop.get("operationParams") or {}
7112 )
7113 exec_terminate_primitives = not operation_params.get(
7114 "skip_terminate_primitives"
7115 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007116 task = asyncio.ensure_future(
7117 asyncio.wait_for(
7118 self.destroy_N2VC(
7119 logging_text,
7120 db_nslcmop,
7121 vca,
7122 config_descriptor,
7123 vca_index,
7124 destroy_ee=True,
7125 exec_primitives=exec_terminate_primitives,
7126 scaling_in=True,
7127 vca_id=vca_id,
7128 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007129 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007130 )
7131 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007132 tasks_dict_info[task] = "Terminating VCA {}".format(
7133 vca.get("ee_id")
7134 )
aktas13251562021-02-12 22:19:10 +03007135 del vca_update[vca_index]
7136 del config_update[vca_index]
7137 # wait for pending tasks of terminate primitives
7138 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007139 self.logger.debug(
7140 logging_text
7141 + "Waiting for tasks {}".format(
7142 list(tasks_dict_info.keys())
7143 )
7144 )
7145 error_list = await self._wait_for_tasks(
7146 logging_text,
7147 tasks_dict_info,
7148 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007149 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007150 ),
7151 stage,
7152 nslcmop_id,
7153 )
aktas13251562021-02-12 22:19:10 +03007154 tasks_dict_info.clear()
7155 if error_list:
7156 raise LcmException("; ".join(error_list))
7157
7158 db_vca_and_config_update = {
7159 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007160 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007161 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007162 self.update_db_2(
7163 "nsrs", db_nsr["_id"], db_vca_and_config_update
7164 )
aktas13251562021-02-12 22:19:10 +03007165 scale_process = None
7166 # SCALE-IN VCA - END
7167
kuuseac3a8882019-10-03 10:48:06 +02007168 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007169 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007170 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007171 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007172 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007173 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007174 )
aktas5f75f102021-03-15 11:26:10 +03007175 scaling_info.pop("vdu-create", None)
7176 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007177
tierno9ab95942018-10-10 16:44:22 +02007178 scale_process = None
aktas13251562021-02-12 22:19:10 +03007179 # SCALE RO - END
7180
aktas5f75f102021-03-15 11:26:10 +03007181 # SCALE KDU - BEGIN
7182 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7183 scale_process = "KDU"
7184 await self._scale_kdu(
7185 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7186 )
7187 scaling_info.pop("kdu-create", None)
7188 scaling_info.pop("kdu-delete", None)
7189
7190 scale_process = None
7191 # SCALE KDU - END
7192
7193 if db_nsr_update:
7194 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7195
aktas13251562021-02-12 22:19:10 +03007196 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007197 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007198 step = db_nslcmop_update[
7199 "detailed-status"
7200 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007201 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007202 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007203 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007204 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007205 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007206 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007207 )
aktas13251562021-02-12 22:19:10 +03007208 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007209 if vca_info.get("osm_vdu_id"):
7210 vdu_index = int(vca_info["vdu_index"])
7211 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7212 if db_vnfr.get("additionalParamsForVnf"):
7213 deploy_params.update(
7214 parse_yaml_strings(
7215 db_vnfr["additionalParamsForVnf"].copy()
7216 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007217 )
aktas5f75f102021-03-15 11:26:10 +03007218 descriptor_config = get_configuration(
7219 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007220 )
aktas5f75f102021-03-15 11:26:10 +03007221 if descriptor_config:
7222 vdu_id = None
7223 vdu_name = None
7224 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007225 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007226 self._deploy_n2vc(
7227 logging_text=logging_text
7228 + "member_vnf_index={} ".format(member_vnf_index),
7229 db_nsr=db_nsr,
7230 db_vnfr=db_vnfr,
7231 nslcmop_id=nslcmop_id,
7232 nsr_id=nsr_id,
7233 nsi_id=nsi_id,
7234 vnfd_id=vnfd_id,
7235 vdu_id=vdu_id,
7236 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007237 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007238 member_vnf_index=member_vnf_index,
7239 vdu_index=vdu_index,
7240 vdu_name=vdu_name,
7241 deploy_params=deploy_params,
7242 descriptor_config=descriptor_config,
7243 base_folder=base_folder,
7244 task_instantiation_info=tasks_dict_info,
7245 stage=stage,
7246 )
7247 vdu_id = vca_info["osm_vdu_id"]
7248 vdur = find_in_list(
7249 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007250 )
aktas5f75f102021-03-15 11:26:10 +03007251 descriptor_config = get_configuration(db_vnfd, vdu_id)
7252 if vdur.get("additionalParams"):
7253 deploy_params_vdu = parse_yaml_strings(
7254 vdur["additionalParams"]
7255 )
7256 else:
7257 deploy_params_vdu = deploy_params
7258 deploy_params_vdu["OSM"] = get_osm_params(
7259 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007260 )
aktas5f75f102021-03-15 11:26:10 +03007261 if descriptor_config:
7262 vdu_name = None
7263 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007264 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007265 stage[
7266 1
7267 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007268 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007269 )
7270 stage[2] = step = "Scaling out VCA"
7271 self._write_op_status(op_id=nslcmop_id, stage=stage)
7272 self._deploy_n2vc(
7273 logging_text=logging_text
7274 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7275 member_vnf_index, vdu_id, vdu_index
7276 ),
7277 db_nsr=db_nsr,
7278 db_vnfr=db_vnfr,
7279 nslcmop_id=nslcmop_id,
7280 nsr_id=nsr_id,
7281 nsi_id=nsi_id,
7282 vnfd_id=vnfd_id,
7283 vdu_id=vdu_id,
7284 kdu_name=kdu_name,
7285 member_vnf_index=member_vnf_index,
7286 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007287 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007288 vdu_name=vdu_name,
7289 deploy_params=deploy_params_vdu,
7290 descriptor_config=descriptor_config,
7291 base_folder=base_folder,
7292 task_instantiation_info=tasks_dict_info,
7293 stage=stage,
7294 )
aktas13251562021-02-12 22:19:10 +03007295 # SCALE-UP VCA - END
7296 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007297
kuuseac3a8882019-10-03 10:48:06 +02007298 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007299 # execute primitive service POST-SCALING
7300 step = "Executing post-scale vnf-config-primitive"
7301 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007302 for scaling_config_action in scaling_descriptor[
7303 "scaling-config-action"
7304 ]:
7305 if (
7306 scaling_config_action.get("trigger") == "post-scale-in"
7307 and scaling_type == "SCALE_IN"
7308 ) or (
7309 scaling_config_action.get("trigger") == "post-scale-out"
7310 and scaling_type == "SCALE_OUT"
7311 ):
7312 vnf_config_primitive = scaling_config_action[
7313 "vnf-config-primitive-name-ref"
7314 ]
7315 step = db_nslcmop_update[
7316 "detailed-status"
7317 ] = "executing post-scale scaling-config-action '{}'".format(
7318 vnf_config_primitive
7319 )
tiernoda964822019-01-14 15:53:47 +00007320
aktas5f75f102021-03-15 11:26:10 +03007321 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007322 if db_vnfr.get("additionalParamsForVnf"):
7323 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7324
tierno59d22d22018-09-25 18:10:19 +02007325 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007326 for config_primitive in (
7327 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7328 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007329 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007330 break
7331 else:
tiernoa278b842020-07-08 15:33:55 +00007332 raise LcmException(
7333 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7334 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007335 "config-primitive".format(
7336 scaling_group, vnf_config_primitive
7337 )
7338 )
tierno9ab95942018-10-10 16:44:22 +02007339 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007340 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007341 primitive_params = self._map_primitive_params(
7342 config_primitive, {}, vnfr_params
7343 )
tiernod6de1992018-10-11 13:05:52 +02007344
tierno7c4e24c2020-05-13 08:41:35 +00007345 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007346 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007347 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007348 vnf_index,
7349 vnf_config_primitive,
7350 primitive_params,
7351 "POST-SCALE",
7352 )
quilesj4cda56b2019-12-05 10:02:20 +00007353 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007354 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007355 result = "COMPLETED"
7356 result_detail = "Done"
7357 self.logger.debug(
7358 logging_text
7359 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7360 vnf_config_primitive, result, result_detail
7361 )
7362 )
kuuseac3a8882019-10-03 10:48:06 +02007363 else:
quilesj4cda56b2019-12-05 10:02:20 +00007364 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007365 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007366 op_index = (
7367 len(db_nslcmop.get("_admin", {}).get("operations"))
7368 - 1
7369 )
7370 self.logger.debug(
7371 logging_text
7372 + "vnf_config_primitive={} New sub-operation".format(
7373 vnf_config_primitive
7374 )
7375 )
kuuseac3a8882019-10-03 10:48:06 +02007376 else:
tierno7c4e24c2020-05-13 08:41:35 +00007377 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007378 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7379 op_index
7380 ]
7381 vnf_index = op.get("member_vnf_index")
7382 vnf_config_primitive = op.get("primitive")
7383 primitive_params = op.get("primitive_params")
7384 self.logger.debug(
7385 logging_text
7386 + "vnf_config_primitive={} Sub-operation retry".format(
7387 vnf_config_primitive
7388 )
7389 )
tierno588547c2020-07-01 15:30:20 +00007390 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007391 ee_descriptor_id = config_primitive.get(
7392 "execution-environment-ref"
7393 )
7394 primitive_name = config_primitive.get(
7395 "execution-environment-primitive", vnf_config_primitive
7396 )
7397 ee_id, vca_type = self._look_for_deployed_vca(
7398 nsr_deployed["VCA"],
7399 member_vnf_index=vnf_index,
7400 vdu_id=None,
7401 vdu_count_index=None,
7402 ee_descriptor_id=ee_descriptor_id,
7403 )
kuuseac3a8882019-10-03 10:48:06 +02007404 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007405 ee_id,
7406 primitive_name,
7407 primitive_params,
7408 vca_type=vca_type,
7409 vca_id=vca_id,
7410 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007411 self.logger.debug(
7412 logging_text
7413 + "vnf_config_primitive={} Done with result {} {}".format(
7414 vnf_config_primitive, result, result_detail
7415 )
7416 )
kuuseac3a8882019-10-03 10:48:06 +02007417 # Update operationState = COMPLETED | FAILED
7418 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007419 db_nslcmop, op_index, result, result_detail
7420 )
kuuseac3a8882019-10-03 10:48:06 +02007421
tierno59d22d22018-09-25 18:10:19 +02007422 if result == "FAILED":
7423 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007424 db_nsr_update["config-status"] = old_config_status
7425 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007426 # POST-SCALE END
Rahul Kumar2864cff2023-11-09 08:34:27 +00007427 # Check if each vnf has exporter for metric collection if so update prometheus job records
7428 if scaling_type == "SCALE_OUT":
7429 if "exporters-endpoints" in db_vnfd.get("df")[0]:
7430 vnfr_id = db_vnfr["id"]
7431 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7432 exporter_config = db_vnfd.get("df")[0].get("exporters-endpoints")
7433 self.logger.debug("exporter config :{}".format(exporter_config))
7434 artifact_path = "{}/{}/{}".format(
7435 base_folder["folder"],
7436 base_folder["pkg-dir"],
7437 "exporter-endpoint",
7438 )
7439 ee_id = None
7440 ee_config_descriptor = exporter_config
7441 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
7442 logging_text,
7443 nsr_id,
7444 vnfr_id,
7445 vdu_id=db_vnfr["vdur"][-1]["vdu-id-ref"],
7446 vdu_index=db_vnfr["vdur"][-1]["count-index"],
7447 user=None,
7448 pub_key=None,
7449 )
7450 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
7451 self.logger.debug("Artifact_path:{}".format(artifact_path))
7452 vdu_id_for_prom = None
7453 vdu_index_for_prom = None
7454 for x in get_iterable(db_vnfr, "vdur"):
7455 vdu_id_for_prom = x.get("vdu-id-ref")
7456 vdu_index_for_prom = x.get("count-index")
7457 vnfr_id = vnfr_id + vdu_id + str(vdu_index)
7458 vnfr_id = vnfr_id.replace("_", "")
7459 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
7460 ee_id=ee_id,
7461 artifact_path=artifact_path,
7462 ee_config_descriptor=ee_config_descriptor,
7463 vnfr_id=vnfr_id,
7464 nsr_id=nsr_id,
7465 target_ip=rw_mgmt_ip,
7466 element_type="VDU",
7467 vdu_id=vdu_id_for_prom,
7468 vdu_index=vdu_index_for_prom,
7469 )
tierno59d22d22018-09-25 18:10:19 +02007470
Rahul Kumar2864cff2023-11-09 08:34:27 +00007471 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
7472 if prometheus_jobs:
7473 db_nsr_update[
7474 "_admin.deployed.prometheus_jobs"
7475 ] = prometheus_jobs
7476 self.update_db_2(
7477 "nsrs",
7478 nsr_id,
7479 db_nsr_update,
7480 )
7481
7482 for job in prometheus_jobs:
7483 self.db.set_one(
7484 "prometheus_jobs",
7485 {"job_name": ""},
7486 job,
7487 upsert=True,
7488 fail_on_empty=False,
7489 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007490 db_nsr_update[
7491 "detailed-status"
7492 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7493 db_nsr_update["operational-status"] = (
7494 "running"
7495 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007496 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007497 )
tiernod6de1992018-10-11 13:05:52 +02007498 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007499 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007500 except (
7501 ROclient.ROClientException,
7502 DbException,
7503 LcmException,
7504 NgRoException,
7505 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007506 self.logger.error(logging_text + "Exit Exception {}".format(e))
7507 exc = e
7508 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007509 self.logger.error(
7510 logging_text + "Cancelled Exception while '{}'".format(step)
7511 )
tierno59d22d22018-09-25 18:10:19 +02007512 exc = "Operation was cancelled"
7513 except Exception as e:
7514 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007515 self.logger.critical(
7516 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7517 exc_info=True,
7518 )
tierno59d22d22018-09-25 18:10:19 +02007519 finally:
garciadeblas5697b8b2021-03-24 09:17:02 +01007520 self._write_ns_status(
7521 nsr_id=nsr_id,
7522 ns_state=None,
7523 current_operation="IDLE",
7524 current_operation_id=None,
7525 )
aktas13251562021-02-12 22:19:10 +03007526 if tasks_dict_info:
7527 stage[1] = "Waiting for instantiate pending tasks."
7528 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01007529 exc = await self._wait_for_tasks(
7530 logging_text,
7531 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007532 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007533 stage,
7534 nslcmop_id,
7535 nsr_id=nsr_id,
7536 )
tierno59d22d22018-09-25 18:10:19 +02007537 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01007538 db_nslcmop_update[
7539 "detailed-status"
7540 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tiernoa17d4f42020-04-28 09:59:23 +00007541 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007542 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007543 db_nsr_update["operational-status"] = old_operational_status
7544 db_nsr_update["config-status"] = old_config_status
7545 db_nsr_update["detailed-status"] = ""
7546 if scale_process:
7547 if "VCA" in scale_process:
7548 db_nsr_update["config-status"] = "failed"
7549 if "RO" in scale_process:
7550 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007551 db_nsr_update[
7552 "detailed-status"
7553 ] = "FAILED scaling nslcmop={} {}: {}".format(
7554 nslcmop_id, step, exc
7555 )
tiernoa17d4f42020-04-28 09:59:23 +00007556 else:
7557 error_description_nslcmop = None
7558 nslcmop_operation_state = "COMPLETED"
7559 db_nslcmop_update["detailed-status"] = "Done"
Rahul Kumar2864cff2023-11-09 08:34:27 +00007560 if scaling_type == "SCALE_IN" and prom_job_name is not None:
7561 self.db.del_one(
7562 "prometheus_jobs",
7563 {"job_name": prom_job_name},
7564 fail_on_empty=False,
7565 )
quilesj4cda56b2019-12-05 10:02:20 +00007566
garciadeblas5697b8b2021-03-24 09:17:02 +01007567 self._write_op_status(
7568 op_id=nslcmop_id,
7569 stage="",
7570 error_message=error_description_nslcmop,
7571 operation_state=nslcmop_operation_state,
7572 other_update=db_nslcmop_update,
7573 )
tiernoa17d4f42020-04-28 09:59:23 +00007574 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007575 self._write_ns_status(
7576 nsr_id=nsr_id,
7577 ns_state=None,
7578 current_operation="IDLE",
7579 current_operation_id=None,
7580 other_update=db_nsr_update,
7581 )
tiernoa17d4f42020-04-28 09:59:23 +00007582
tierno59d22d22018-09-25 18:10:19 +02007583 if nslcmop_operation_state:
7584 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007585 msg = {
7586 "nsr_id": nsr_id,
7587 "nslcmop_id": nslcmop_id,
7588 "operationState": nslcmop_operation_state,
7589 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007590 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007591 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007592 self.logger.error(
7593 logging_text + "kafka_write notification Exception {}".format(e)
7594 )
tierno59d22d22018-09-25 18:10:19 +02007595 self.logger.debug(logging_text + "Exit")
7596 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007597
aktas5f75f102021-03-15 11:26:10 +03007598 async def _scale_kdu(
7599 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7600 ):
7601 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7602 for kdu_name in _scaling_info:
7603 for kdu_scaling_info in _scaling_info[kdu_name]:
7604 deployed_kdu, index = get_deployed_kdu(
7605 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7606 )
7607 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7608 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007609 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007610 scale = int(kdu_scaling_info["scale"])
7611 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7612
7613 db_dict = {
7614 "collection": "nsrs",
7615 "filter": {"_id": nsr_id},
7616 "path": "_admin.deployed.K8s.{}".format(index),
7617 }
7618
7619 step = "scaling application {}".format(
7620 kdu_scaling_info["resource-name"]
7621 )
7622 self.logger.debug(logging_text + step)
7623
7624 if kdu_scaling_info["type"] == "delete":
7625 kdu_config = get_configuration(db_vnfd, kdu_name)
7626 if (
7627 kdu_config
7628 and kdu_config.get("terminate-config-primitive")
7629 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7630 ):
7631 terminate_config_primitive_list = kdu_config.get(
7632 "terminate-config-primitive"
7633 )
7634 terminate_config_primitive_list.sort(
7635 key=lambda val: int(val["seq"])
7636 )
7637
7638 for (
7639 terminate_config_primitive
7640 ) in terminate_config_primitive_list:
7641 primitive_params_ = self._map_primitive_params(
7642 terminate_config_primitive, {}, {}
7643 )
7644 step = "execute terminate config primitive"
7645 self.logger.debug(logging_text + step)
7646 await asyncio.wait_for(
7647 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7648 cluster_uuid=cluster_uuid,
7649 kdu_instance=kdu_instance,
7650 primitive_name=terminate_config_primitive["name"],
7651 params=primitive_params_,
7652 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007653 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007654 vca_id=vca_id,
7655 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007656 timeout=self.timeout.primitive
7657 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007658 )
7659
7660 await asyncio.wait_for(
7661 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007662 kdu_instance=kdu_instance,
7663 scale=scale,
7664 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007665 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007666 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007667 cluster_uuid=cluster_uuid,
7668 kdu_model=kdu_model,
7669 atomic=True,
7670 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007671 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007672 timeout=self.timeout.scale_on_error
7673 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007674 )
7675
7676 if kdu_scaling_info["type"] == "create":
7677 kdu_config = get_configuration(db_vnfd, kdu_name)
7678 if (
7679 kdu_config
7680 and kdu_config.get("initial-config-primitive")
7681 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7682 ):
7683 initial_config_primitive_list = kdu_config.get(
7684 "initial-config-primitive"
7685 )
7686 initial_config_primitive_list.sort(
7687 key=lambda val: int(val["seq"])
7688 )
7689
7690 for initial_config_primitive in initial_config_primitive_list:
7691 primitive_params_ = self._map_primitive_params(
7692 initial_config_primitive, {}, {}
7693 )
7694 step = "execute initial config primitive"
7695 self.logger.debug(logging_text + step)
7696 await asyncio.wait_for(
7697 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7698 cluster_uuid=cluster_uuid,
7699 kdu_instance=kdu_instance,
7700 primitive_name=initial_config_primitive["name"],
7701 params=primitive_params_,
7702 db_dict=db_dict,
7703 vca_id=vca_id,
7704 ),
7705 timeout=600,
7706 )
7707
garciadeblas5697b8b2021-03-24 09:17:02 +01007708 async def _scale_ng_ro(
7709 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7710 ):
tierno2357f4e2020-10-19 16:38:59 +00007711 nsr_id = db_nslcmop["nsInstanceId"]
7712 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7713 db_vnfrs = {}
7714
7715 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007716 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007717
7718 # for each vnf in ns, read vnfd
7719 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7720 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7721 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007722 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007723 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007724 # read from db
7725 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007726 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007727 n2vc_key = self.n2vc.get_public_key()
7728 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007729 self.scale_vnfr(
7730 db_vnfr,
7731 vdu_scaling_info.get("vdu-create"),
7732 vdu_scaling_info.get("vdu-delete"),
7733 mark_delete=True,
7734 )
tierno2357f4e2020-10-19 16:38:59 +00007735 # db_vnfr has been updated, update db_vnfrs to use it
7736 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007737 await self._instantiate_ng_ro(
7738 logging_text,
7739 nsr_id,
7740 db_nsd,
7741 db_nsr,
7742 db_nslcmop,
7743 db_vnfrs,
7744 db_vnfds,
7745 n2vc_key_list,
7746 stage=stage,
7747 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007748 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007749 )
tierno2357f4e2020-10-19 16:38:59 +00007750 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007751 self.scale_vnfr(
7752 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7753 )
tierno2357f4e2020-10-19 16:38:59 +00007754
bravof73bac502021-05-11 07:38:47 -04007755 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007756 self,
7757 ee_id: str,
7758 artifact_path: str,
7759 ee_config_descriptor: dict,
7760 vnfr_id: str,
7761 nsr_id: str,
7762 target_ip: str,
7763 element_type: str,
7764 vnf_member_index: str = "",
7765 vdu_id: str = "",
7766 vdu_index: int = None,
7767 kdu_name: str = "",
7768 kdu_index: int = None,
7769 ) -> dict:
7770 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7771 This method will wait until the corresponding VDU or KDU is fully instantiated
7772
7773 Args:
7774 ee_id (str): Execution Environment ID
7775 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7776 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7777 vnfr_id (str): VNFR ID where this EE applies
7778 nsr_id (str): NSR ID where this EE applies
7779 target_ip (str): VDU/KDU instance IP address
7780 element_type (str): NS or VNF or VDU or KDU
7781 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7782 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7783 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7784 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7785 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7786
7787 Raises:
7788 LcmException: When the VDU or KDU instance was not found in an hour
7789
7790 Returns:
7791 _type_: Prometheus jobs
7792 """
7793 # default the vdur and kdur names to an empty string, to avoid any later
7794 # problem with Prometheus when the element type is not VDU or KDU
7795 vdur_name = ""
7796 kdur_name = ""
7797
tiernob996d942020-07-03 14:52:28 +00007798 # look if exist a file called 'prometheus*.j2' and
7799 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007800 job_file = next(
7801 (
7802 f
7803 for f in artifact_content
7804 if f.startswith("prometheus") and f.endswith(".j2")
7805 ),
7806 None,
7807 )
tiernob996d942020-07-03 14:52:28 +00007808 if not job_file:
7809 return
k4.rahul74944982023-04-19 17:00:52 +05307810 self.logger.debug("Artifact path{}".format(artifact_path))
7811 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007812 with self.fs.file_open((artifact_path, job_file), "r") as f:
7813 job_data = f.read()
7814
Pedro Escaleira120695e2022-06-11 21:17:26 +01007815 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7816 if element_type in ("VDU", "KDU"):
7817 for _ in range(360):
7818 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7819 if vdu_id and vdu_index is not None:
7820 vdur = next(
7821 (
7822 x
7823 for x in get_iterable(db_vnfr, "vdur")
7824 if (
7825 x.get("vdu-id-ref") == vdu_id
7826 and x.get("count-index") == vdu_index
7827 )
7828 ),
7829 {},
7830 )
7831 if vdur.get("name"):
7832 vdur_name = vdur.get("name")
7833 break
7834 if kdu_name and kdu_index is not None:
7835 kdur = next(
7836 (
7837 x
7838 for x in get_iterable(db_vnfr, "kdur")
7839 if (
7840 x.get("kdu-name") == kdu_name
7841 and x.get("count-index") == kdu_index
7842 )
7843 ),
7844 {},
7845 )
7846 if kdur.get("name"):
7847 kdur_name = kdur.get("name")
7848 break
7849
Gabriel Cubae7898982023-05-11 01:57:21 -05007850 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007851 else:
7852 if vdu_id and vdu_index is not None:
7853 raise LcmException(
7854 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7855 )
7856 if kdu_name and kdu_index is not None:
7857 raise LcmException(
7858 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7859 )
7860
k4.rahul74944982023-04-19 17:00:52 +05307861 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007862 _, namespace, helm_id = get_ee_id_parts(
7863 ee_id
7864 ) # get namespace and EE gRPC service name
7865 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307866 host_port = "80"
7867 vnfr_id = vnfr_id.replace("-", "")
7868 variables = {
7869 "JOB_NAME": vnfr_id,
7870 "TARGET_IP": target_ip,
7871 "EXPORTER_POD_IP": host_name,
7872 "EXPORTER_POD_PORT": host_port,
7873 "NSR_ID": nsr_id,
7874 "VNF_MEMBER_INDEX": vnf_member_index,
7875 "VDUR_NAME": vdur_name,
7876 "KDUR_NAME": kdur_name,
7877 "ELEMENT_TYPE": element_type,
7878 }
7879 else:
7880 metric_path = ee_config_descriptor["metric-path"]
7881 target_port = ee_config_descriptor["metric-port"]
7882 vnfr_id = vnfr_id.replace("-", "")
7883 variables = {
7884 "JOB_NAME": vnfr_id,
7885 "TARGET_IP": target_ip,
7886 "TARGET_PORT": target_port,
7887 "METRIC_PATH": metric_path,
7888 }
7889
bravof73bac502021-05-11 07:38:47 -04007890 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007891 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7892 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007893 if (
7894 not isinstance(job.get("job_name"), str)
7895 or vnfr_id not in job["job_name"]
7896 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307897 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007898 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007899 job["vnfr_id"] = vnfr_id
7900 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007901
preethika.p28b0bf82022-09-23 07:36:28 +00007902 async def rebuild_start_stop(
7903 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7904 ):
k4.rahulb827de92022-05-02 16:35:02 +00007905 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7906 self.logger.info(logging_text + "Enter")
7907 stage = ["Preparing the environment", ""]
7908 # database nsrs record
7909 db_nsr_update = {}
7910 vdu_vim_name = None
7911 vim_vm_id = None
7912 # in case of error, indicates what part of scale was failed to put nsr at error status
7913 start_deploy = time()
7914 try:
7915 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7916 vim_account_id = db_vnfr.get("vim-account-id")
7917 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007918 vdu_id = additional_param["vdu_id"]
7919 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007920 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007921 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007922 )
k4.rahulb827de92022-05-02 16:35:02 +00007923 if vdur:
7924 vdu_vim_name = vdur["name"]
7925 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7926 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007927 else:
7928 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007929 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7930 # wait for any previous tasks in process
7931 stage[1] = "Waiting for previous operations to terminate"
7932 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007933 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007934
7935 stage[1] = "Reading from database."
7936 self.logger.info(stage[1])
7937 self._write_ns_status(
7938 nsr_id=nsr_id,
7939 ns_state=None,
7940 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007941 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007942 )
7943 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7944
7945 # read from db: ns
7946 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7947 db_nsr_update["operational-status"] = operation_type
7948 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7949 # Payload for RO
7950 desc = {
7951 operation_type: {
7952 "vim_vm_id": vim_vm_id,
7953 "vnf_id": vnf_id,
7954 "vdu_index": additional_param["count-index"],
7955 "vdu_id": vdur["id"],
7956 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007957 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007958 }
7959 }
7960 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7961 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7962 self.logger.info("ro nsr id: {}".format(nsr_id))
7963 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7964 self.logger.info("response from RO: {}".format(result_dict))
7965 action_id = result_dict["action_id"]
7966 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007967 nsr_id,
7968 action_id,
7969 nslcmop_id,
7970 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007971 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007972 None,
7973 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007974 )
7975 return "COMPLETED", "Done"
7976 except (ROclient.ROClientException, DbException, LcmException) as e:
7977 self.logger.error("Exit Exception {}".format(e))
7978 exc = e
7979 except asyncio.CancelledError:
7980 self.logger.error("Cancelled Exception while '{}'".format(stage))
7981 exc = "Operation was cancelled"
7982 except Exception as e:
7983 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007984 self.logger.critical(
7985 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7986 )
k4.rahulb827de92022-05-02 16:35:02 +00007987 return "FAILED", "Error in operate VNF {}".format(exc)
7988
David Garciaaae391f2020-11-09 11:12:54 +01007989 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7990 """
7991 Get VCA Cloud and VCA Cloud Credentials for the VIM account
7992
7993 :param: vim_account_id: VIM Account ID
7994
7995 :return: (cloud_name, cloud_credential)
7996 """
bravof922c4172020-11-24 21:21:43 -03007997 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007998 return config.get("vca_cloud"), config.get("vca_cloud_credential")
7999
8000 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
8001 """
8002 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
8003
8004 :param: vim_account_id: VIM Account ID
8005
8006 :return: (cloud_name, cloud_credential)
8007 """
bravof922c4172020-11-24 21:21:43 -03008008 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01008009 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")
elumalai80bcf1c2022-04-28 18:05:01 +05308010
8011 async def migrate(self, nsr_id, nslcmop_id):
8012 """
8013 Migrate VNFs and VDUs instances in a NS
8014
8015 :param: nsr_id: NS Instance ID
8016 :param: nslcmop_id: nslcmop ID of migrate
8017
8018 """
8019 # Try to lock HA task here
8020 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8021 if not task_is_locked_by_me:
8022 return
8023 logging_text = "Task ns={} migrate ".format(nsr_id)
8024 self.logger.debug(logging_text + "Enter")
8025 # get all needed from database
8026 db_nslcmop = None
8027 db_nslcmop_update = {}
8028 nslcmop_operation_state = None
8029 db_nsr_update = {}
8030 target = {}
8031 exc = None
8032 # in case of error, indicates what part of scale was failed to put nsr at error status
8033 start_deploy = time()
8034
8035 try:
8036 # wait for any previous tasks in process
8037 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03008038 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05308039
8040 self._write_ns_status(
8041 nsr_id=nsr_id,
8042 ns_state=None,
8043 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03008044 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05308045 )
8046 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03008047 self.logger.debug(
8048 step + " after having waited for previous tasks to be completed"
8049 )
elumalai80bcf1c2022-04-28 18:05:01 +05308050 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8051 migrate_params = db_nslcmop.get("operationParams")
8052
8053 target = {}
8054 target.update(migrate_params)
8055 desc = await self.RO.migrate(nsr_id, target)
8056 self.logger.debug("RO return > {}".format(desc))
8057 action_id = desc["action_id"]
8058 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008059 nsr_id,
8060 action_id,
8061 nslcmop_id,
8062 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00008063 self.timeout.migrate,
preethika.p28b0bf82022-09-23 07:36:28 +00008064 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05308065 )
8066 except (ROclient.ROClientException, DbException, LcmException) as e:
8067 self.logger.error("Exit Exception {}".format(e))
8068 exc = e
8069 except asyncio.CancelledError:
8070 self.logger.error("Cancelled Exception while '{}'".format(step))
8071 exc = "Operation was cancelled"
8072 except Exception as e:
8073 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03008074 self.logger.critical(
8075 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8076 )
elumalai80bcf1c2022-04-28 18:05:01 +05308077 finally:
8078 self._write_ns_status(
8079 nsr_id=nsr_id,
8080 ns_state=None,
8081 current_operation="IDLE",
8082 current_operation_id=None,
8083 )
8084 if exc:
aticig349aa462022-05-19 12:29:35 +03008085 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05308086 nslcmop_operation_state = "FAILED"
8087 else:
8088 nslcmop_operation_state = "COMPLETED"
8089 db_nslcmop_update["detailed-status"] = "Done"
8090 db_nsr_update["detailed-status"] = "Done"
8091
8092 self._write_op_status(
8093 op_id=nslcmop_id,
8094 stage="",
8095 error_message="",
8096 operation_state=nslcmop_operation_state,
8097 other_update=db_nslcmop_update,
8098 )
8099 if nslcmop_operation_state:
8100 try:
8101 msg = {
8102 "nsr_id": nsr_id,
8103 "nslcmop_id": nslcmop_id,
8104 "operationState": nslcmop_operation_state,
8105 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008106 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05308107 except Exception as e:
8108 self.logger.error(
8109 logging_text + "kafka_write notification Exception {}".format(e)
8110 )
8111 self.logger.debug(logging_text + "Exit")
8112 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008113
garciadeblas07f4e4c2022-06-09 09:42:58 +02008114 async def heal(self, nsr_id, nslcmop_id):
8115 """
8116 Heal NS
8117
8118 :param nsr_id: ns instance to heal
8119 :param nslcmop_id: operation to run
8120 :return:
8121 """
8122
8123 # Try to lock HA task here
8124 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8125 if not task_is_locked_by_me:
8126 return
8127
8128 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
8129 stage = ["", "", ""]
8130 tasks_dict_info = {}
8131 # ^ stage, step, VIM progress
8132 self.logger.debug(logging_text + "Enter")
8133 # get all needed from database
8134 db_nsr = None
8135 db_nslcmop_update = {}
8136 db_nsr_update = {}
8137 db_vnfrs = {} # vnf's info indexed by _id
8138 exc = None
8139 old_operational_status = ""
8140 old_config_status = ""
8141 nsi_id = None
8142 try:
8143 # wait for any previous tasks in process
8144 step = "Waiting for previous operations to terminate"
8145 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8146 self._write_ns_status(
8147 nsr_id=nsr_id,
8148 ns_state=None,
8149 current_operation="HEALING",
8150 current_operation_id=nslcmop_id,
8151 )
8152
8153 step = "Getting nslcmop from database"
8154 self.logger.debug(
8155 step + " after having waited for previous tasks to be completed"
8156 )
8157 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8158
8159 step = "Getting nsr from database"
8160 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8161 old_operational_status = db_nsr["operational-status"]
8162 old_config_status = db_nsr["config-status"]
8163
8164 db_nsr_update = {
8165 "_admin.deployed.RO.operational-status": "healing",
8166 }
8167 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8168
8169 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008170 await self.heal_RO(
8171 logging_text=logging_text,
8172 nsr_id=nsr_id,
8173 db_nslcmop=db_nslcmop,
8174 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008175 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008176 # VCA tasks
8177 # read from db: nsd
8178 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8179 self.logger.debug(logging_text + stage[1])
8180 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8181 self.fs.sync(db_nsr["nsd-id"])
8182 db_nsr["nsd"] = nsd
8183 # read from db: vnfr's of this ns
8184 step = "Getting vnfrs from db"
8185 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8186 for vnfr in db_vnfrs_list:
8187 db_vnfrs[vnfr["_id"]] = vnfr
8188 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8189
8190 # Check for each target VNF
8191 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8192 for target_vnf in target_list:
8193 # Find this VNF in the list from DB
8194 vnfr_id = target_vnf.get("vnfInstanceId", None)
8195 if vnfr_id:
8196 db_vnfr = db_vnfrs[vnfr_id]
8197 vnfd_id = db_vnfr.get("vnfd-id")
8198 vnfd_ref = db_vnfr.get("vnfd-ref")
8199 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8200 base_folder = vnfd["_admin"]["storage"]
8201 vdu_id = None
8202 vdu_index = 0
8203 vdu_name = None
8204 kdu_name = None
8205 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8206 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8207
8208 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008209 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8210 "vdu", []
8211 )
garciadeblas50639832022-09-01 13:09:47 +02008212 if not target_vdu_list:
8213 # Codigo nuevo para crear diccionario
8214 target_vdu_list = []
8215 for existing_vdu in db_vnfr.get("vdur"):
8216 vdu_name = existing_vdu.get("vdu-name", None)
8217 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008218 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8219 "run-day1", False
8220 )
8221 vdu_to_be_healed = {
8222 "vdu-id": vdu_name,
8223 "count-index": vdu_index,
8224 "run-day1": vdu_run_day1,
8225 }
garciadeblas50639832022-09-01 13:09:47 +02008226 target_vdu_list.append(vdu_to_be_healed)
8227 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008228 deploy_params_vdu = target_vdu
8229 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008230 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8231 "additionalParams", {}
8232 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008233 deploy_params_vdu["run-day1"] = target_vnf[
8234 "additionalParams"
8235 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008236 vdu_name = target_vdu.get("vdu-id", None)
8237 # TODO: Get vdu_id from vdud.
8238 vdu_id = vdu_name
8239 # For multi instance VDU count-index is mandatory
8240 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008241 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008242
8243 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8244 stage[1] = "Deploying Execution Environments."
8245 self.logger.debug(logging_text + stage[1])
8246
8247 # VNF Level charm. Normal case when proxy charms.
8248 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8249 descriptor_config = get_configuration(vnfd, vnfd_ref)
8250 if descriptor_config:
8251 # Continue if healed machine is management machine
8252 vnf_ip_address = db_vnfr.get("ip-address")
8253 target_instance = None
8254 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008255 if (
8256 instance["vdu-name"] == vdu_name
8257 and instance["count-index"] == vdu_index
8258 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008259 target_instance = instance
8260 break
8261 if vnf_ip_address == target_instance.get("ip-address"):
8262 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008263 logging_text=logging_text
8264 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8265 member_vnf_index, vdu_name, vdu_index
8266 ),
8267 db_nsr=db_nsr,
8268 db_vnfr=db_vnfr,
8269 nslcmop_id=nslcmop_id,
8270 nsr_id=nsr_id,
8271 nsi_id=nsi_id,
8272 vnfd_id=vnfd_ref,
8273 vdu_id=None,
8274 kdu_name=None,
8275 member_vnf_index=member_vnf_index,
8276 vdu_index=0,
8277 vdu_name=None,
8278 deploy_params=deploy_params_vdu,
8279 descriptor_config=descriptor_config,
8280 base_folder=base_folder,
8281 task_instantiation_info=tasks_dict_info,
8282 stage=stage,
8283 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008284
8285 # VDU Level charm. Normal case with native charms.
8286 descriptor_config = get_configuration(vnfd, vdu_name)
8287 if descriptor_config:
8288 self._heal_n2vc(
8289 logging_text=logging_text
8290 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8291 member_vnf_index, vdu_name, vdu_index
8292 ),
8293 db_nsr=db_nsr,
8294 db_vnfr=db_vnfr,
8295 nslcmop_id=nslcmop_id,
8296 nsr_id=nsr_id,
8297 nsi_id=nsi_id,
8298 vnfd_id=vnfd_ref,
8299 vdu_id=vdu_id,
8300 kdu_name=kdu_name,
8301 member_vnf_index=member_vnf_index,
8302 vdu_index=vdu_index,
8303 vdu_name=vdu_name,
8304 deploy_params=deploy_params_vdu,
8305 descriptor_config=descriptor_config,
8306 base_folder=base_folder,
8307 task_instantiation_info=tasks_dict_info,
8308 stage=stage,
8309 )
8310
8311 except (
8312 ROclient.ROClientException,
8313 DbException,
8314 LcmException,
8315 NgRoException,
8316 ) as e:
8317 self.logger.error(logging_text + "Exit Exception {}".format(e))
8318 exc = e
8319 except asyncio.CancelledError:
8320 self.logger.error(
8321 logging_text + "Cancelled Exception while '{}'".format(step)
8322 )
8323 exc = "Operation was cancelled"
8324 except Exception as e:
8325 exc = traceback.format_exc()
8326 self.logger.critical(
8327 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8328 exc_info=True,
8329 )
8330 finally:
8331 if tasks_dict_info:
8332 stage[1] = "Waiting for healing pending tasks."
8333 self.logger.debug(logging_text + stage[1])
8334 exc = await self._wait_for_tasks(
8335 logging_text,
8336 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008337 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008338 stage,
8339 nslcmop_id,
8340 nsr_id=nsr_id,
8341 )
8342 if exc:
8343 db_nslcmop_update[
8344 "detailed-status"
8345 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
8346 nslcmop_operation_state = "FAILED"
8347 if db_nsr:
8348 db_nsr_update["operational-status"] = old_operational_status
8349 db_nsr_update["config-status"] = old_config_status
8350 db_nsr_update[
8351 "detailed-status"
preethika.p28b0bf82022-09-23 07:36:28 +00008352 ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008353 for task, task_name in tasks_dict_info.items():
8354 if not task.done() or task.cancelled() or task.exception():
8355 if task_name.startswith(self.task_name_deploy_vca):
8356 # A N2VC task is pending
8357 db_nsr_update["config-status"] = "failed"
8358 else:
8359 # RO task is pending
8360 db_nsr_update["operational-status"] = "failed"
8361 else:
8362 error_description_nslcmop = None
8363 nslcmop_operation_state = "COMPLETED"
8364 db_nslcmop_update["detailed-status"] = "Done"
8365 db_nsr_update["detailed-status"] = "Done"
8366 db_nsr_update["operational-status"] = "running"
8367 db_nsr_update["config-status"] = "configured"
8368
8369 self._write_op_status(
8370 op_id=nslcmop_id,
8371 stage="",
8372 error_message=error_description_nslcmop,
8373 operation_state=nslcmop_operation_state,
8374 other_update=db_nslcmop_update,
8375 )
8376 if db_nsr:
8377 self._write_ns_status(
8378 nsr_id=nsr_id,
8379 ns_state=None,
8380 current_operation="IDLE",
8381 current_operation_id=None,
8382 other_update=db_nsr_update,
8383 )
8384
8385 if nslcmop_operation_state:
8386 try:
8387 msg = {
8388 "nsr_id": nsr_id,
8389 "nslcmop_id": nslcmop_id,
8390 "operationState": nslcmop_operation_state,
8391 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008392 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008393 except Exception as e:
8394 self.logger.error(
8395 logging_text + "kafka_write notification Exception {}".format(e)
8396 )
8397 self.logger.debug(logging_text + "Exit")
8398 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8399
8400 async def heal_RO(
8401 self,
8402 logging_text,
8403 nsr_id,
8404 db_nslcmop,
8405 stage,
8406 ):
8407 """
8408 Heal at RO
8409 :param logging_text: preffix text to use at logging
8410 :param nsr_id: nsr identity
8411 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8412 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8413 :return: None or exception
8414 """
preethika.p28b0bf82022-09-23 07:36:28 +00008415
garciadeblas07f4e4c2022-06-09 09:42:58 +02008416 def get_vim_account(vim_account_id):
8417 nonlocal db_vims
8418 if vim_account_id in db_vims:
8419 return db_vims[vim_account_id]
8420 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8421 db_vims[vim_account_id] = db_vim
8422 return db_vim
8423
8424 try:
8425 start_heal = time()
8426 ns_params = db_nslcmop.get("operationParams")
8427 if ns_params and ns_params.get("timeout_ns_heal"):
8428 timeout_ns_heal = ns_params["timeout_ns_heal"]
8429 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008430 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008431
8432 db_vims = {}
8433
8434 nslcmop_id = db_nslcmop["_id"]
8435 target = {
8436 "action_id": nslcmop_id,
8437 }
preethika.p28b0bf82022-09-23 07:36:28 +00008438 self.logger.warning(
8439 "db_nslcmop={} and timeout_ns_heal={}".format(
8440 db_nslcmop, timeout_ns_heal
8441 )
8442 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008443 target.update(db_nslcmop.get("operationParams", {}))
8444
8445 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8446 desc = await self.RO.recreate(nsr_id, target)
8447 self.logger.debug("RO return > {}".format(desc))
8448 action_id = desc["action_id"]
8449 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8450 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008451 nsr_id,
8452 action_id,
8453 nslcmop_id,
8454 start_heal,
8455 timeout_ns_heal,
8456 stage,
8457 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008458 )
8459
8460 # Updating NSR
8461 db_nsr_update = {
8462 "_admin.deployed.RO.operational-status": "running",
8463 "detailed-status": " ".join(stage),
8464 }
8465 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8466 self._write_op_status(nslcmop_id, stage)
8467 self.logger.debug(
8468 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8469 )
8470
8471 except Exception as e:
8472 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008473 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008474 self.logger.error(
8475 "Error healing at VIM {}".format(e),
8476 exc_info=not isinstance(
8477 e,
8478 (
8479 ROclient.ROClientException,
8480 LcmException,
8481 DbException,
8482 NgRoException,
8483 ),
8484 ),
8485 )
8486 raise
8487
8488 def _heal_n2vc(
8489 self,
8490 logging_text,
8491 db_nsr,
8492 db_vnfr,
8493 nslcmop_id,
8494 nsr_id,
8495 nsi_id,
8496 vnfd_id,
8497 vdu_id,
8498 kdu_name,
8499 member_vnf_index,
8500 vdu_index,
8501 vdu_name,
8502 deploy_params,
8503 descriptor_config,
8504 base_folder,
8505 task_instantiation_info,
8506 stage,
8507 ):
8508 # launch instantiate_N2VC in a asyncio task and register task object
8509 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8510 # if not found, create one entry and update database
8511 # fill db_nsr._admin.deployed.VCA.<index>
8512
8513 self.logger.debug(
8514 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8515 )
aticig9bc63ac2022-07-27 09:32:06 +03008516
8517 charm_name = ""
8518 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008519 if "execution-environment-list" in descriptor_config:
8520 ee_list = descriptor_config.get("execution-environment-list", [])
8521 elif "juju" in descriptor_config:
8522 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008523 if "execution-environment-list" not in descriptor_config:
8524 # charm name is only required for ns charms
8525 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008526 else: # other types as script are not supported
8527 ee_list = []
8528
8529 for ee_item in ee_list:
8530 self.logger.debug(
8531 logging_text
8532 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8533 ee_item.get("juju"), ee_item.get("helm-chart")
8534 )
8535 )
8536 ee_descriptor_id = ee_item.get("id")
8537 if ee_item.get("juju"):
8538 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03008539 if get_charm_name:
8540 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008541 vca_type = (
8542 "lxc_proxy_charm"
8543 if ee_item["juju"].get("charm") is not None
8544 else "native_charm"
8545 )
8546 if ee_item["juju"].get("cloud") == "k8s":
8547 vca_type = "k8s_proxy_charm"
8548 elif ee_item["juju"].get("proxy") is False:
8549 vca_type = "native_charm"
8550 elif ee_item.get("helm-chart"):
8551 vca_name = ee_item["helm-chart"]
8552 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
8553 vca_type = "helm"
8554 else:
8555 vca_type = "helm-v3"
8556 else:
8557 self.logger.debug(
8558 logging_text + "skipping non juju neither charm configuration"
8559 )
8560 continue
8561
8562 vca_index = -1
8563 for vca_index, vca_deployed in enumerate(
8564 db_nsr["_admin"]["deployed"]["VCA"]
8565 ):
8566 if not vca_deployed:
8567 continue
8568 if (
8569 vca_deployed.get("member-vnf-index") == member_vnf_index
8570 and vca_deployed.get("vdu_id") == vdu_id
8571 and vca_deployed.get("kdu_name") == kdu_name
8572 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8573 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8574 ):
8575 break
8576 else:
8577 # not found, create one.
8578 target = (
8579 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8580 )
8581 if vdu_id:
8582 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8583 elif kdu_name:
8584 target += "/kdu/{}".format(kdu_name)
8585 vca_deployed = {
8586 "target_element": target,
8587 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8588 "member-vnf-index": member_vnf_index,
8589 "vdu_id": vdu_id,
8590 "kdu_name": kdu_name,
8591 "vdu_count_index": vdu_index,
8592 "operational-status": "init", # TODO revise
8593 "detailed-status": "", # TODO revise
8594 "step": "initial-deploy", # TODO revise
8595 "vnfd_id": vnfd_id,
8596 "vdu_name": vdu_name,
8597 "type": vca_type,
8598 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008599 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008600 }
8601 vca_index += 1
8602
8603 # create VCA and configurationStatus in db
8604 db_dict = {
8605 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8606 "configurationStatus.{}".format(vca_index): dict(),
8607 }
8608 self.update_db_2("nsrs", nsr_id, db_dict)
8609
8610 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8611
8612 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8613 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8614 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8615
8616 # Launch task
8617 task_n2vc = asyncio.ensure_future(
8618 self.heal_N2VC(
8619 logging_text=logging_text,
8620 vca_index=vca_index,
8621 nsi_id=nsi_id,
8622 db_nsr=db_nsr,
8623 db_vnfr=db_vnfr,
8624 vdu_id=vdu_id,
8625 kdu_name=kdu_name,
8626 vdu_index=vdu_index,
8627 deploy_params=deploy_params,
8628 config_descriptor=descriptor_config,
8629 base_folder=base_folder,
8630 nslcmop_id=nslcmop_id,
8631 stage=stage,
8632 vca_type=vca_type,
8633 vca_name=vca_name,
8634 ee_config_descriptor=ee_item,
8635 )
8636 )
8637 self.lcm_tasks.register(
8638 "ns",
8639 nsr_id,
8640 nslcmop_id,
8641 "instantiate_N2VC-{}".format(vca_index),
8642 task_n2vc,
8643 )
8644 task_instantiation_info[
8645 task_n2vc
8646 ] = self.task_name_deploy_vca + " {}.{}".format(
8647 member_vnf_index or "", vdu_id or ""
8648 )
8649
8650 async def heal_N2VC(
8651 self,
8652 logging_text,
8653 vca_index,
8654 nsi_id,
8655 db_nsr,
8656 db_vnfr,
8657 vdu_id,
8658 kdu_name,
8659 vdu_index,
8660 config_descriptor,
8661 deploy_params,
8662 base_folder,
8663 nslcmop_id,
8664 stage,
8665 vca_type,
8666 vca_name,
8667 ee_config_descriptor,
8668 ):
8669 nsr_id = db_nsr["_id"]
8670 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8671 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8672 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8673 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8674 db_dict = {
8675 "collection": "nsrs",
8676 "filter": {"_id": nsr_id},
8677 "path": db_update_entry,
8678 }
8679 step = ""
8680 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008681 element_type = "NS"
8682 element_under_configuration = nsr_id
8683
8684 vnfr_id = None
8685 if db_vnfr:
8686 vnfr_id = db_vnfr["_id"]
8687 osm_config["osm"]["vnf_id"] = vnfr_id
8688
8689 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8690
8691 if vca_type == "native_charm":
8692 index_number = 0
8693 else:
8694 index_number = vdu_index or 0
8695
8696 if vnfr_id:
8697 element_type = "VNF"
8698 element_under_configuration = vnfr_id
8699 namespace += ".{}-{}".format(vnfr_id, index_number)
8700 if vdu_id:
8701 namespace += ".{}-{}".format(vdu_id, index_number)
8702 element_type = "VDU"
8703 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8704 osm_config["osm"]["vdu_id"] = vdu_id
8705 elif kdu_name:
8706 namespace += ".{}".format(kdu_name)
8707 element_type = "KDU"
8708 element_under_configuration = kdu_name
8709 osm_config["osm"]["kdu_name"] = kdu_name
8710
8711 # Get artifact path
8712 if base_folder["pkg-dir"]:
8713 artifact_path = "{}/{}/{}/{}".format(
8714 base_folder["folder"],
8715 base_folder["pkg-dir"],
8716 "charms"
8717 if vca_type
8718 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8719 else "helm-charts",
8720 vca_name,
8721 )
8722 else:
8723 artifact_path = "{}/Scripts/{}/{}/".format(
8724 base_folder["folder"],
8725 "charms"
8726 if vca_type
8727 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8728 else "helm-charts",
8729 vca_name,
8730 )
8731
8732 self.logger.debug("Artifact path > {}".format(artifact_path))
8733
8734 # get initial_config_primitive_list that applies to this element
8735 initial_config_primitive_list = config_descriptor.get(
8736 "initial-config-primitive"
8737 )
8738
8739 self.logger.debug(
8740 "Initial config primitive list > {}".format(
8741 initial_config_primitive_list
8742 )
8743 )
8744
8745 # add config if not present for NS charm
8746 ee_descriptor_id = ee_config_descriptor.get("id")
8747 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8748 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8749 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8750 )
8751
8752 self.logger.debug(
8753 "Initial config primitive list #2 > {}".format(
8754 initial_config_primitive_list
8755 )
8756 )
8757 # n2vc_redesign STEP 3.1
8758 # find old ee_id if exists
8759 ee_id = vca_deployed.get("ee_id")
8760
8761 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8762 # create or register execution environment in VCA. Only for native charms when healing
8763 if vca_type == "native_charm":
8764 step = "Waiting to VM being up and getting IP address"
8765 self.logger.debug(logging_text + step)
8766 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8767 logging_text,
8768 nsr_id,
8769 vnfr_id,
8770 vdu_id,
8771 vdu_index,
8772 user=None,
8773 pub_key=None,
8774 )
8775 credentials = {"hostname": rw_mgmt_ip}
8776 # get username
8777 username = deep_get(
8778 config_descriptor, ("config-access", "ssh-access", "default-user")
8779 )
8780 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8781 # merged. Meanwhile let's get username from initial-config-primitive
8782 if not username and initial_config_primitive_list:
8783 for config_primitive in initial_config_primitive_list:
8784 for param in config_primitive.get("parameter", ()):
8785 if param["name"] == "ssh-username":
8786 username = param["value"]
8787 break
8788 if not username:
8789 raise LcmException(
8790 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8791 "'config-access.ssh-access.default-user'"
8792 )
8793 credentials["username"] = username
8794
8795 # n2vc_redesign STEP 3.2
8796 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8797 self._write_configuration_status(
8798 nsr_id=nsr_id,
8799 vca_index=vca_index,
8800 status="REGISTERING",
8801 element_under_configuration=element_under_configuration,
8802 element_type=element_type,
8803 )
8804
8805 step = "register execution environment {}".format(credentials)
8806 self.logger.debug(logging_text + step)
8807 ee_id = await self.vca_map[vca_type].register_execution_environment(
8808 credentials=credentials,
8809 namespace=namespace,
8810 db_dict=db_dict,
8811 vca_id=vca_id,
8812 )
8813
8814 # update ee_id en db
8815 db_dict_ee_id = {
8816 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8817 }
8818 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8819
8820 # for compatibility with MON/POL modules, the need model and application name at database
8821 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8822 # Not sure if this need to be done when healing
8823 """
8824 ee_id_parts = ee_id.split(".")
8825 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8826 if len(ee_id_parts) >= 2:
8827 model_name = ee_id_parts[0]
8828 application_name = ee_id_parts[1]
8829 db_nsr_update[db_update_entry + "model"] = model_name
8830 db_nsr_update[db_update_entry + "application"] = application_name
8831 """
8832
8833 # n2vc_redesign STEP 3.3
8834 # Install configuration software. Only for native charms.
8835 step = "Install configuration Software"
8836
8837 self._write_configuration_status(
8838 nsr_id=nsr_id,
8839 vca_index=vca_index,
8840 status="INSTALLING SW",
8841 element_under_configuration=element_under_configuration,
8842 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008843 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008844 other_update=None,
8845 )
8846
8847 # TODO check if already done
8848 self.logger.debug(logging_text + step)
8849 config = None
8850 if vca_type == "native_charm":
8851 config_primitive = next(
8852 (p for p in initial_config_primitive_list if p["name"] == "config"),
8853 None,
8854 )
8855 if config_primitive:
8856 config = self._map_primitive_params(
8857 config_primitive, {}, deploy_params
8858 )
8859 await self.vca_map[vca_type].install_configuration_sw(
8860 ee_id=ee_id,
8861 artifact_path=artifact_path,
8862 db_dict=db_dict,
8863 config=config,
8864 num_units=1,
8865 vca_id=vca_id,
8866 vca_type=vca_type,
8867 )
8868
8869 # write in db flag of configuration_sw already installed
8870 self.update_db_2(
8871 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8872 )
8873
8874 # Not sure if this need to be done when healing
8875 """
8876 # add relations for this VCA (wait for other peers related with this VCA)
8877 await self._add_vca_relations(
8878 logging_text=logging_text,
8879 nsr_id=nsr_id,
8880 vca_type=vca_type,
8881 vca_index=vca_index,
8882 )
8883 """
8884
8885 # if SSH access is required, then get execution environment SSH public
8886 # if native charm we have waited already to VM be UP
8887 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
8888 pub_key = None
8889 user = None
8890 # self.logger.debug("get ssh key block")
8891 if deep_get(
8892 config_descriptor, ("config-access", "ssh-access", "required")
8893 ):
8894 # self.logger.debug("ssh key needed")
8895 # Needed to inject a ssh key
8896 user = deep_get(
8897 config_descriptor,
8898 ("config-access", "ssh-access", "default-user"),
8899 )
8900 step = "Install configuration Software, getting public ssh key"
8901 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8902 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8903 )
8904
8905 step = "Insert public key into VM user={} ssh_key={}".format(
8906 user, pub_key
8907 )
8908 else:
8909 # self.logger.debug("no need to get ssh key")
8910 step = "Waiting to VM being up and getting IP address"
8911 self.logger.debug(logging_text + step)
8912
8913 # n2vc_redesign STEP 5.1
8914 # wait for RO (ip-address) Insert pub_key into VM
8915 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008916 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008917 if vnfr_id:
8918 if kdu_name:
8919 rw_mgmt_ip = await self.wait_kdu_up(
8920 logging_text, nsr_id, vnfr_id, kdu_name
8921 )
8922 else:
8923 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8924 logging_text,
8925 nsr_id,
8926 vnfr_id,
8927 vdu_id,
8928 vdu_index,
8929 user=user,
8930 pub_key=pub_key,
8931 )
8932 else:
8933 rw_mgmt_ip = None # This is for a NS configuration
8934
8935 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8936
8937 # store rw_mgmt_ip in deploy params for later replacement
8938 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8939
8940 # Day1 operations.
8941 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008942 runDay1 = deploy_params.get("run-day1", False)
8943 self.logger.debug(
8944 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8945 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008946 if runDay1:
8947 # n2vc_redesign STEP 6 Execute initial config primitive
8948 step = "execute initial config primitive"
8949
8950 # wait for dependent primitives execution (NS -> VNF -> VDU)
8951 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008952 await self._wait_dependent_n2vc(
8953 nsr_id, vca_deployed_list, vca_index
8954 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008955
8956 # stage, in function of element type: vdu, kdu, vnf or ns
8957 my_vca = vca_deployed_list[vca_index]
8958 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8959 # VDU or KDU
8960 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8961 elif my_vca.get("member-vnf-index"):
8962 # VNF
8963 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8964 else:
8965 # NS
8966 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8967
8968 self._write_configuration_status(
8969 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8970 )
8971
8972 self._write_op_status(op_id=nslcmop_id, stage=stage)
8973
8974 check_if_terminated_needed = True
8975 for initial_config_primitive in initial_config_primitive_list:
8976 # adding information on the vca_deployed if it is a NS execution environment
8977 if not vca_deployed["member-vnf-index"]:
8978 deploy_params["ns_config_info"] = json.dumps(
8979 self._get_ns_config_info(nsr_id)
8980 )
8981 # TODO check if already done
8982 primitive_params_ = self._map_primitive_params(
8983 initial_config_primitive, {}, deploy_params
8984 )
8985
8986 step = "execute primitive '{}' params '{}'".format(
8987 initial_config_primitive["name"], primitive_params_
8988 )
8989 self.logger.debug(logging_text + step)
8990 await self.vca_map[vca_type].exec_primitive(
8991 ee_id=ee_id,
8992 primitive_name=initial_config_primitive["name"],
8993 params_dict=primitive_params_,
8994 db_dict=db_dict,
8995 vca_id=vca_id,
8996 vca_type=vca_type,
8997 )
8998 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8999 if check_if_terminated_needed:
9000 if config_descriptor.get("terminate-config-primitive"):
9001 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00009002 "nsrs",
9003 nsr_id,
9004 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02009005 )
9006 check_if_terminated_needed = False
9007
9008 # TODO register in database that primitive is done
9009
9010 # STEP 7 Configure metrics
9011 # Not sure if this need to be done when healing
9012 """
9013 if vca_type == "helm" or vca_type == "helm-v3":
9014 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
9015 ee_id=ee_id,
9016 artifact_path=artifact_path,
9017 ee_config_descriptor=ee_config_descriptor,
9018 vnfr_id=vnfr_id,
9019 nsr_id=nsr_id,
9020 target_ip=rw_mgmt_ip,
9021 )
9022 if prometheus_jobs:
9023 self.update_db_2(
9024 "nsrs",
9025 nsr_id,
9026 {db_update_entry + "prometheus_jobs": prometheus_jobs},
9027 )
9028
9029 for job in prometheus_jobs:
9030 self.db.set_one(
9031 "prometheus_jobs",
9032 {"job_name": job["job_name"]},
9033 job,
9034 upsert=True,
9035 fail_on_empty=False,
9036 )
9037
9038 """
9039 step = "instantiated at VCA"
9040 self.logger.debug(logging_text + step)
9041
9042 self._write_configuration_status(
9043 nsr_id=nsr_id, vca_index=vca_index, status="READY"
9044 )
9045
9046 except Exception as e: # TODO not use Exception but N2VC exception
9047 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
9048 if not isinstance(
9049 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
9050 ):
9051 self.logger.error(
9052 "Exception while {} : {}".format(step, e), exc_info=True
9053 )
9054 self._write_configuration_status(
9055 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
9056 )
9057 raise LcmException("{} {}".format(step, e)) from e
9058
9059 async def _wait_heal_ro(
9060 self,
9061 nsr_id,
9062 timeout=600,
9063 ):
9064 start_time = time()
9065 while time() <= start_time + timeout:
9066 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00009067 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
9068 "operational-status"
9069 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02009070 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
9071 if operational_status_ro != "healing":
9072 break
Gabriel Cubae7898982023-05-11 01:57:21 -05009073 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02009074 else: # timeout_ns_deploy
9075 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05309076
9077 async def vertical_scale(self, nsr_id, nslcmop_id):
9078 """
9079 Vertical Scale the VDUs in a NS
9080
9081 :param: nsr_id: NS Instance ID
9082 :param: nslcmop_id: nslcmop ID of migrate
9083
9084 """
9085 # Try to lock HA task here
9086 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
9087 if not task_is_locked_by_me:
9088 return
9089 logging_text = "Task ns={} vertical scale ".format(nsr_id)
9090 self.logger.debug(logging_text + "Enter")
9091 # get all needed from database
9092 db_nslcmop = None
9093 db_nslcmop_update = {}
9094 nslcmop_operation_state = None
Rahul Kumara24c5ec2023-11-08 05:15:07 +00009095 old_db_update = {}
9096 q_filter = {}
9097 old_vdu_index = None
9098 old_flavor_id = None
govindarajul4ff4b512022-05-02 20:02:41 +05309099 db_nsr_update = {}
9100 target = {}
9101 exc = None
9102 # in case of error, indicates what part of scale was failed to put nsr at error status
9103 start_deploy = time()
9104
9105 try:
9106 # wait for any previous tasks in process
9107 step = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00009108 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05309109
9110 self._write_ns_status(
9111 nsr_id=nsr_id,
9112 ns_state=None,
9113 current_operation="VerticalScale",
preethika.p28b0bf82022-09-23 07:36:28 +00009114 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05309115 )
9116 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00009117 self.logger.debug(
9118 step + " after having waited for previous tasks to be completed"
9119 )
govindarajul4ff4b512022-05-02 20:02:41 +05309120 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
9121 operationParams = db_nslcmop.get("operationParams")
Rahul Kumara24c5ec2023-11-08 05:15:07 +00009122 # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
9123 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
9124 db_flavor = db_nsr.get("flavor")
9125 db_flavor_index = str(len(db_flavor))
9126 change_vnf_flavor_data = operationParams["changeVnfFlavorData"]
9127 flavor_dict = change_vnf_flavor_data["additionalParams"]
9128 count_index = flavor_dict["vduCountIndex"]
9129 vdu_id_ref = flavor_dict["vduid"]
9130 flavor_dict_update = {
9131 "id": db_flavor_index,
9132 "memory-mb": flavor_dict["virtualMemory"],
9133 "name": f"{vdu_id_ref}-{count_index}-flv",
9134 "storage-gb": flavor_dict["sizeOfStorage"],
9135 "vcpu-count": flavor_dict["numVirtualCpu"],
9136 }
9137 db_flavor.append(flavor_dict_update)
9138 db_update = {}
9139 db_update["flavor"] = db_flavor
9140 ns_q_filter = {
9141 "_id": nsr_id,
9142 }
9143 self.db.set_one(
9144 "nsrs",
9145 q_filter=ns_q_filter,
9146 update_dict=db_update,
9147 fail_on_empty=True,
9148 )
9149 db_vnfr = self.db.get_one(
9150 "vnfrs", {"_id": change_vnf_flavor_data["vnfInstanceId"]}
9151 )
9152 for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
9153 if (
9154 vdur.get("count-index") == count_index
9155 and vdur.get("vdu-id-ref") == vdu_id_ref
9156 ):
9157 old_flavor_id = vdur.get("ns-flavor-id", 0)
9158 old_vdu_index = vdu_index
9159 filter_text = {
9160 "_id": change_vnf_flavor_data["vnfInstanceId"],
9161 "vdur.count-index": count_index,
9162 "vdur.vdu-id-ref": vdu_id_ref,
9163 }
9164 q_filter.update(filter_text)
9165 db_update = {}
9166 db_update[
9167 "vdur.{}.ns-flavor-id".format(vdu_index)
9168 ] = db_flavor_index
9169 self.db.set_one(
9170 "vnfrs",
9171 q_filter=q_filter,
9172 update_dict=db_update,
9173 fail_on_empty=True,
9174 )
govindarajul4ff4b512022-05-02 20:02:41 +05309175 target = {}
9176 target.update(operationParams)
9177 desc = await self.RO.vertical_scale(nsr_id, target)
9178 self.logger.debug("RO return > {}".format(desc))
9179 action_id = desc["action_id"]
9180 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00009181 nsr_id,
9182 action_id,
9183 nslcmop_id,
9184 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00009185 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00009186 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05309187 )
Rahul Kumara24c5ec2023-11-08 05:15:07 +00009188 except (
9189 NgRoException,
9190 ROclient.ROClientException,
9191 DbException,
9192 LcmException,
9193 ) as e:
govindarajul4ff4b512022-05-02 20:02:41 +05309194 self.logger.error("Exit Exception {}".format(e))
9195 exc = e
9196 except asyncio.CancelledError:
9197 self.logger.error("Cancelled Exception while '{}'".format(step))
9198 exc = "Operation was cancelled"
9199 except Exception as e:
9200 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009201 self.logger.critical(
9202 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9203 )
govindarajul4ff4b512022-05-02 20:02:41 +05309204 finally:
9205 self._write_ns_status(
9206 nsr_id=nsr_id,
9207 ns_state=None,
9208 current_operation="IDLE",
9209 current_operation_id=None,
9210 )
9211 if exc:
preethika.p28b0bf82022-09-23 07:36:28 +00009212 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
govindarajul4ff4b512022-05-02 20:02:41 +05309213 nslcmop_operation_state = "FAILED"
Rahul Kumara24c5ec2023-11-08 05:15:07 +00009214 old_db_update[
9215 "vdur.{}.ns-flavor-id".format(old_vdu_index)
9216 ] = old_flavor_id
govindarajul4ff4b512022-05-02 20:02:41 +05309217 else:
9218 nslcmop_operation_state = "COMPLETED"
9219 db_nslcmop_update["detailed-status"] = "Done"
9220 db_nsr_update["detailed-status"] = "Done"
9221
9222 self._write_op_status(
9223 op_id=nslcmop_id,
9224 stage="",
9225 error_message="",
9226 operation_state=nslcmop_operation_state,
9227 other_update=db_nslcmop_update,
9228 )
Rahul Kumara24c5ec2023-11-08 05:15:07 +00009229 if old_vdu_index and old_db_update != {}:
9230 self.logger.critical(
9231 "Reverting Old Flavor -- : {}".format(old_db_update)
9232 )
9233 self.db.set_one(
9234 "vnfrs",
9235 q_filter=q_filter,
9236 update_dict=old_db_update,
9237 fail_on_empty=True,
9238 )
govindarajul4ff4b512022-05-02 20:02:41 +05309239 if nslcmop_operation_state:
9240 try:
9241 msg = {
9242 "nsr_id": nsr_id,
9243 "nslcmop_id": nslcmop_id,
9244 "operationState": nslcmop_operation_state,
9245 }
Gabriel Cubae7898982023-05-11 01:57:21 -05009246 await self.msg.aiowrite("ns", "verticalscaled", msg)
govindarajul4ff4b512022-05-02 20:02:41 +05309247 except Exception as e:
9248 self.logger.error(
9249 logging_text + "kafka_write notification Exception {}".format(e)
9250 )
9251 self.logger.debug(logging_text + "Exit")
9252 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")