blob: fda67221b268f0a7c8b3037305ebccbe3d17174a [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
David Garciad4816682019-12-09 14:57:43 +010026import json
garciadeblas5697b8b2021-03-24 09:17:02 +010027from jinja2 import (
28 Environment,
29 TemplateError,
30 TemplateNotFound,
31 StrictUndefined,
32 UndefinedError,
garciadeblasef91e082022-08-02 15:12:18 +020033 select_autoescape,
garciadeblas5697b8b2021-03-24 09:17:02 +010034)
tierno59d22d22018-09-25 18:10:19 +020035
tierno77677d92019-08-22 13:46:35 +000036from osm_lcm import ROclient
Luis Vegaa27dc532022-11-11 20:10:49 +000037from osm_lcm.data_utils.lcm_config import LcmCfg
David Garciab4ebcd02021-10-28 02:00:43 +020038from osm_lcm.data_utils.nsr import (
39 get_deployed_kdu,
40 get_deployed_vca,
41 get_deployed_vca_list,
42 get_nsd,
43)
44from osm_lcm.data_utils.vca import (
45 DeployedComponent,
46 DeployedK8sResource,
47 DeployedVCA,
48 EELevel,
49 Relation,
50 EERelation,
51 safe_get_ee_relation,
52)
tierno69f0d382020-05-07 13:08:09 +000053from osm_lcm.ng_ro import NgRoClient, NgRoException
garciadeblas5697b8b2021-03-24 09:17:02 +010054from osm_lcm.lcm_utils import (
55 LcmException,
56 LcmExceptionNoMgmtIP,
57 LcmBase,
58 deep_get,
59 get_iterable,
60 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030061 check_juju_bundle_existence,
62 get_charm_artifact_path,
Gabriel Cubae539a8d2022-10-10 11:34:51 -050063 get_ee_id_parts,
Gabriel Cubac7737442023-02-14 13:09:18 -050064 vld_to_ro_ip_profile,
garciadeblas5697b8b2021-03-24 09:17:02 +010065)
David Garciab4ebcd02021-10-28 02:00:43 +020066from osm_lcm.data_utils.nsd import (
67 get_ns_configuration_relation_list,
68 get_vnf_profile,
69 get_vnf_profiles,
70)
garciadeblas5697b8b2021-03-24 09:17:02 +010071from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020072 get_kdu,
73 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020074 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010075 get_vdu_list,
76 get_vdu_profile,
77 get_ee_sorted_initial_config_primitive_list,
78 get_ee_sorted_terminate_config_primitive_list,
79 get_kdu_list,
80 get_virtual_link_profiles,
81 get_vdu,
82 get_configuration,
83 get_vdu_index,
84 get_scaling_aspect,
85 get_number_of_instances,
86 get_juju_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020087 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030088 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050089 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010090)
bravof922c4172020-11-24 21:21:43 -030091from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030092from osm_lcm.data_utils.vnfr import (
93 get_osm_params,
94 get_vdur_index,
95 get_kdur,
96 get_volumes_from_instantiation_params,
97)
bravof922c4172020-11-24 21:21:43 -030098from osm_lcm.data_utils.dict_utils import parse_yaml_strings
99from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +0200100from n2vc.definitions import RelationEndpoint
calvinosanch9f9c6f22019-11-04 13:37:39 +0100101from n2vc.k8s_helm_conn import K8sHelmConnector
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000102from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -0500103from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200104
tierno27246d82018-09-27 15:59:09 +0200105from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200106from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200107
bravof922c4172020-11-24 21:21:43 -0300108from osm_lcm.data_utils.database.database import Database
109from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000110from osm_lcm.data_utils.wim import (
111 get_sdn_ports,
112 get_target_wim_attrs,
113 select_feasible_wim_account,
114)
bravof922c4172020-11-24 21:21:43 -0300115
quilesj7e13aeb2019-10-08 13:34:55 +0200116from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000117from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200118
tierno588547c2020-07-01 15:30:20 +0000119from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200120from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400121from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000122
tierno27246d82018-09-27 15:59:09 +0200123from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200124from time import time
tierno27246d82018-09-27 15:59:09 +0200125from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000126
k4.rahulcf47a3b2023-04-27 12:08:48 +0530127from random import SystemRandom
tierno59d22d22018-09-25 18:10:19 +0200128
tierno69f0d382020-05-07 13:08:09 +0000129__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200130
131
132class NsLcm(LcmBase):
kuuseac3a8882019-10-03 10:48:06 +0200133 SUBOPERATION_STATUS_NOT_FOUND = -1
134 SUBOPERATION_STATUS_NEW = -2
135 SUBOPERATION_STATUS_SKIP = -3
Gabriel Cubaeb585dd2023-04-25 16:48:41 -0500136 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000137 task_name_deploy_vca = "Deploying VCA"
garciadeblas9148fa82023-05-30 12:51:14 +0200138 rel_operation_types = {
139 "GE": ">=",
140 "LE": "<=",
141 "GT": ">",
142 "LT": "<",
143 "EQ": "==",
144 "NE": "!=",
145 }
kuuseac3a8882019-10-03 10:48:06 +0200146
Gabriel Cubae7898982023-05-11 01:57:21 -0500147 def __init__(self, msg, lcm_tasks, config: LcmCfg):
tierno59d22d22018-09-25 18:10:19 +0200148 """
149 Init, Connect to database, filesystem storage, and messaging
150 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
151 :return: None
152 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100153 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200154
bravof922c4172020-11-24 21:21:43 -0300155 self.db = Database().instance.db
156 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200157 self.lcm_tasks = lcm_tasks
Luis Vegaa27dc532022-11-11 20:10:49 +0000158 self.timeout = config.timeout
159 self.ro_config = config.RO
160 self.vca_config = config.VCA
tierno59d22d22018-09-25 18:10:19 +0200161
quilesj7e13aeb2019-10-08 13:34:55 +0200162 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100163 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200164 log=self.logger,
bravof922c4172020-11-24 21:21:43 -0300165 on_update_db=self._on_update_n2vc_db,
166 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100167 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200168 )
quilesj7e13aeb2019-10-08 13:34:55 +0200169
tierno588547c2020-07-01 15:30:20 +0000170 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000171 log=self.logger,
tierno588547c2020-07-01 15:30:20 +0000172 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100173 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000174 )
175
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000176 self.k8sclusterhelm2 = K8sHelmConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000177 kubectl_command=self.vca_config.kubectlpath,
178 helm_command=self.vca_config.helmpath,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100179 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100180 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300181 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100182 db=self.db,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100183 )
184
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000185 self.k8sclusterhelm3 = K8sHelm3Connector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000186 kubectl_command=self.vca_config.kubectlpath,
187 helm_command=self.vca_config.helm3path,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000188 fs=self.fs,
189 log=self.logger,
190 db=self.db,
191 on_update_db=None,
192 )
193
Adam Israelbaacc302019-12-01 12:41:39 -0500194 self.k8sclusterjuju = K8sJujuConnector(
Luis Vegaa27dc532022-11-11 20:10:49 +0000195 kubectl_command=self.vca_config.kubectlpath,
196 juju_command=self.vca_config.jujupath,
Adam Israelbaacc302019-12-01 12:41:39 -0500197 log=self.logger,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530198 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300199 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100200 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500201 )
202
tiernoa2143262020-03-27 16:20:40 +0000203 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000204 "helm-chart": self.k8sclusterhelm2,
205 "helm-chart-v3": self.k8sclusterhelm3,
206 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000207 "juju-bundle": self.k8sclusterjuju,
208 "juju": self.k8sclusterjuju,
209 }
tierno588547c2020-07-01 15:30:20 +0000210
211 self.vca_map = {
212 "lxc_proxy_charm": self.n2vc,
213 "native_charm": self.n2vc,
214 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000215 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100216 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000217 }
218
quilesj7e13aeb2019-10-08 13:34:55 +0200219 # create RO client
Gabriel Cubae7898982023-05-11 01:57:21 -0500220 self.RO = NgRoClient(**self.ro_config.to_dict())
tierno59d22d22018-09-25 18:10:19 +0200221
garciadeblas07f4e4c2022-06-09 09:42:58 +0200222 self.op_status_map = {
223 "instantiation": self.RO.status,
224 "termination": self.RO.status,
225 "migrate": self.RO.status,
226 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000227 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000228 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200229 }
230
tierno2357f4e2020-10-19 16:38:59 +0000231 @staticmethod
232 def increment_ip_mac(ip_mac, vm_index=1):
233 if not isinstance(ip_mac, str):
234 return ip_mac
235 try:
236 # try with ipv4 look for last dot
237 i = ip_mac.rfind(".")
238 if i > 0:
239 i += 1
240 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
241 # try with ipv6 or mac look for last colon. Operate in hex
242 i = ip_mac.rfind(":")
243 if i > 0:
244 i += 1
245 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100246 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
247 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
248 )
tierno2357f4e2020-10-19 16:38:59 +0000249 except Exception:
250 pass
251 return None
252
quilesj3655ae02019-12-12 16:08:35 +0000253 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj3655ae02019-12-12 16:08:35 +0000254 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
255
256 try:
257 # TODO filter RO descriptor fields...
258
259 # write to database
260 db_dict = dict()
261 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
garciadeblas5697b8b2021-03-24 09:17:02 +0100262 db_dict["deploymentStatus"] = ro_descriptor
quilesj3655ae02019-12-12 16:08:35 +0000263 self.update_db_2("nsrs", nsrs_id, db_dict)
264
265 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100266 self.logger.warn(
267 "Cannot write database RO deployment for ns={} -> {}".format(nsrs_id, e)
268 )
quilesj3655ae02019-12-12 16:08:35 +0000269
David Garciac1fe90a2021-03-31 19:12:02 +0200270 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000271 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100272 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000273 path = path[:-1]
274
quilesj3655ae02019-12-12 16:08:35 +0000275 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
276 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000277 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100278 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000279
280 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100281 nsr = self.db.get_one(table="nsrs", q_filter=filter)
282 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000283
284 # get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100285 status_dict = await self.n2vc.get_status(
286 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
287 )
quilesj3655ae02019-12-12 16:08:35 +0000288
289 # vcaStatus
290 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100291 db_dict["vcaStatus"] = status_dict
quilesj3655ae02019-12-12 16:08:35 +0000292
293 # update configurationStatus for this VCA
294 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100295 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000296
garciadeblas5697b8b2021-03-24 09:17:02 +0100297 vca_list = deep_get(
298 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
299 )
300 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000301
garciadeblas5697b8b2021-03-24 09:17:02 +0100302 configuration_status_list = nsr.get("configurationStatus")
303 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000304
garciadeblas5697b8b2021-03-24 09:17:02 +0100305 if config_status == "BROKEN" and vca_status != "failed":
306 db_dict["configurationStatus"][vca_index] = "READY"
307 elif config_status != "BROKEN" and vca_status == "failed":
308 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000309 except Exception as e:
310 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100311 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000312
313 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
314 # if nsState = 'DEGRADED' check if all is OK
315 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100316 if current_ns_status in ("READY", "DEGRADED"):
317 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000318 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100319 if status_dict.get("machines"):
320 for machine_id in status_dict.get("machines"):
321 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000322 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100323 if machine.get("agent-status"):
324 s = machine.get("agent-status").get("status")
325 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000326 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100327 error_description += (
328 "machine {} agent-status={} ; ".format(
329 machine_id, s
330 )
331 )
quilesj3655ae02019-12-12 16:08:35 +0000332 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100333 if machine.get("instance-status"):
334 s = machine.get("instance-status").get("status")
335 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000336 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100337 error_description += (
338 "machine {} instance-status={} ; ".format(
339 machine_id, s
340 )
341 )
quilesj3655ae02019-12-12 16:08:35 +0000342 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100343 if status_dict.get("applications"):
344 for app_id in status_dict.get("applications"):
345 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000346 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100347 if app.get("status"):
348 s = app.get("status").get("status")
349 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000350 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100351 error_description += (
352 "application {} status={} ; ".format(app_id, s)
353 )
quilesj3655ae02019-12-12 16:08:35 +0000354
355 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100356 db_dict["errorDescription"] = error_description
357 if current_ns_status == "READY" and is_degraded:
358 db_dict["nsState"] = "DEGRADED"
359 if current_ns_status == "DEGRADED" and not is_degraded:
360 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000361
362 # write to database
363 self.update_db_2("nsrs", nsr_id, db_dict)
364
tierno51183952020-04-03 15:48:18 +0000365 except (asyncio.CancelledError, asyncio.TimeoutError):
366 raise
quilesj3655ae02019-12-12 16:08:35 +0000367 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100368 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200369
garciadeblas5697b8b2021-03-24 09:17:02 +0100370 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100371 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100372 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530373 """
374 Updating vca status in NSR record
375 :param cluster_uuid: UUID of a k8s cluster
376 :param kdu_instance: The unique name of the KDU instance
377 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100378 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530379 :return: none
380 """
381
382 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
383 # .format(cluster_uuid, kdu_instance, filter))
384
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100385 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530386 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100387 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
388 cluster_uuid=cluster_uuid,
389 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200390 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100391 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200392 vca_id=vca_id,
393 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100394
ksaikiranr656b6dd2021-02-19 10:25:18 +0530395 # vcaStatus
396 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100397 db_dict["vcaStatus"] = {nsr_id: vca_status}
ksaikiranr656b6dd2021-02-19 10:25:18 +0530398
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100399 self.logger.debug(
400 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200401 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530402
403 # write to database
404 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530405 except (asyncio.CancelledError, asyncio.TimeoutError):
406 raise
407 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100408 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530409
tierno72ef84f2020-10-06 08:22:07 +0000410 @staticmethod
411 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
412 try:
garciadeblasef91e082022-08-02 15:12:18 +0200413 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000414 undefined=StrictUndefined,
415 autoescape=select_autoescape(default_for_string=True, default=True),
416 )
tierno72ef84f2020-10-06 08:22:07 +0000417 template = env.from_string(cloud_init_text)
418 return template.render(additional_params or {})
419 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100420 raise LcmException(
421 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
422 "file, must be provided in the instantiation parameters inside the "
423 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
424 )
tierno72ef84f2020-10-06 08:22:07 +0000425 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100426 raise LcmException(
427 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
428 vnfd_id, vdu_id, e
429 )
430 )
tierno72ef84f2020-10-06 08:22:07 +0000431
bravof922c4172020-11-24 21:21:43 -0300432 def _get_vdu_cloud_init_content(self, vdu, vnfd):
433 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000434 try:
tierno72ef84f2020-10-06 08:22:07 +0000435 if vdu.get("cloud-init-file"):
436 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300437 if base_folder["pkg-dir"]:
438 cloud_init_file = "{}/{}/cloud_init/{}".format(
439 base_folder["folder"],
440 base_folder["pkg-dir"],
441 vdu["cloud-init-file"],
442 )
443 else:
444 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
445 base_folder["folder"],
446 vdu["cloud-init-file"],
447 )
tierno72ef84f2020-10-06 08:22:07 +0000448 with self.fs.file_open(cloud_init_file, "r") as ci_file:
449 cloud_init_content = ci_file.read()
450 elif vdu.get("cloud-init"):
451 cloud_init_content = vdu["cloud-init"]
452
453 return cloud_init_content
454 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100455 raise LcmException(
456 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
457 vnfd["id"], vdu["id"], cloud_init_file, e
458 )
459 )
tierno72ef84f2020-10-06 08:22:07 +0000460
tierno72ef84f2020-10-06 08:22:07 +0000461 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100462 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300463 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100464 )
tierno72ef84f2020-10-06 08:22:07 +0000465 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300466 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000467
gcalvino35be9152018-12-20 09:33:12 +0100468 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200469 """
470 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
471 :param vnfd: input vnfd
472 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000473 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100474 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200475 :return: copy of vnfd
476 """
tierno72ef84f2020-10-06 08:22:07 +0000477 vnfd_RO = deepcopy(vnfd)
478 # remove unused by RO configuration, monitoring, scaling and internal keys
479 vnfd_RO.pop("_id", None)
480 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000481 vnfd_RO.pop("monitoring-param", None)
482 vnfd_RO.pop("scaling-group-descriptor", None)
483 vnfd_RO.pop("kdu", None)
484 vnfd_RO.pop("k8s-cluster", None)
485 if new_id:
486 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000487
tierno72ef84f2020-10-06 08:22:07 +0000488 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
489 for vdu in get_iterable(vnfd_RO, "vdu"):
490 vdu.pop("cloud-init-file", None)
491 vdu.pop("cloud-init", None)
492 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200493
tierno2357f4e2020-10-19 16:38:59 +0000494 @staticmethod
495 def ip_profile_2_RO(ip_profile):
496 RO_ip_profile = deepcopy(ip_profile)
497 if "dns-server" in RO_ip_profile:
498 if isinstance(RO_ip_profile["dns-server"], list):
499 RO_ip_profile["dns-address"] = []
500 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100501 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000502 else:
503 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
504 if RO_ip_profile.get("ip-version") == "ipv4":
505 RO_ip_profile["ip-version"] = "IPv4"
506 if RO_ip_profile.get("ip-version") == "ipv6":
507 RO_ip_profile["ip-version"] = "IPv6"
508 if "dhcp-params" in RO_ip_profile:
509 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
510 return RO_ip_profile
511
bravof922c4172020-11-24 21:21:43 -0300512 def _get_ro_vim_id_for_vim_account(self, vim_account):
513 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
514 if db_vim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100515 raise LcmException(
516 "VIM={} is not available. operationalState={}".format(
517 vim_account, db_vim["_admin"]["operationalState"]
518 )
519 )
bravof922c4172020-11-24 21:21:43 -0300520 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
521 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200522
bravof922c4172020-11-24 21:21:43 -0300523 def get_ro_wim_id_for_wim_account(self, wim_account):
524 if isinstance(wim_account, str):
525 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
526 if db_wim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100527 raise LcmException(
528 "WIM={} is not available. operationalState={}".format(
529 wim_account, db_wim["_admin"]["operationalState"]
530 )
531 )
bravof922c4172020-11-24 21:21:43 -0300532 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
533 return RO_wim_id
534 else:
535 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200536
tierno2357f4e2020-10-19 16:38:59 +0000537 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000538 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000539 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000540 db_update = {"_admin.modified": time()}
541 if vdu_create:
542 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100543 vdur = next(
544 (
545 vdur
546 for vdur in reversed(db_vnfr["vdur"])
547 if vdur["vdu-id-ref"] == vdu_id
548 ),
549 None,
550 )
tierno2357f4e2020-10-19 16:38:59 +0000551 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000552 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300553 self.logger.debug(
554 "No vdur in the database. Using the vdur-template to scale"
555 )
vegall8d625f12022-03-22 16:23:30 +0000556 vdur_template = db_vnfr.get("vdur-template")
557 if not vdur_template:
558 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300559 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
560 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000561 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100562 )
vegall8d625f12022-03-22 16:23:30 +0000563 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300564 # Delete a template from the database after using it
565 self.db.set_one(
566 "vnfrs",
567 {"_id": db_vnfr["_id"]},
568 None,
569 pull={"vdur-template": {"_id": vdur["_id"]}},
570 )
tierno2357f4e2020-10-19 16:38:59 +0000571 for count in range(vdu_count):
572 vdur_copy = deepcopy(vdur)
573 vdur_copy["status"] = "BUILD"
574 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100575 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000576 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000577 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100578 vdur_copy["id"] = "{}-{}".format(
579 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
580 )
tierno2357f4e2020-10-19 16:38:59 +0000581 vdur_copy.pop("vim_info", None)
582 for iface in vdur_copy["interfaces"]:
583 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100584 iface["ip-address"] = self.increment_ip_mac(
585 iface["ip-address"], count + 1
586 )
tierno2357f4e2020-10-19 16:38:59 +0000587 else:
588 iface.pop("ip-address", None)
589 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100590 iface["mac-address"] = self.increment_ip_mac(
591 iface["mac-address"], count + 1
592 )
tierno2357f4e2020-10-19 16:38:59 +0000593 else:
594 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000595 if db_vnfr["vdur"]:
596 iface.pop(
597 "mgmt_vnf", None
598 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000599 db_vdu_push_list.append(vdur_copy)
600 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200601 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000602 if len(db_vnfr["vdur"]) == 1:
603 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300604 self.logger.debug(
605 "Scaling to 0 !, creating the template with the last vdur"
606 )
vegall8d625f12022-03-22 16:23:30 +0000607 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000608 for vdu_id, vdu_count in vdu_delete.items():
609 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100610 indexes_to_delete = [
611 iv[0]
612 for iv in enumerate(db_vnfr["vdur"])
613 if iv[1]["vdu-id-ref"] == vdu_id
614 ]
615 db_update.update(
616 {
617 "vdur.{}.status".format(i): "DELETING"
618 for i in indexes_to_delete[-vdu_count:]
619 }
620 )
tierno2357f4e2020-10-19 16:38:59 +0000621 else:
622 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100623 vdus_to_delete = [
624 v
625 for v in reversed(db_vnfr["vdur"])
626 if v["vdu-id-ref"] == vdu_id
627 ]
tierno2357f4e2020-10-19 16:38:59 +0000628 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100629 self.db.set_one(
630 "vnfrs",
631 {"_id": db_vnfr["_id"]},
632 None,
633 pull={"vdur": {"_id": vdu["_id"]}},
634 )
vegall8d625f12022-03-22 16:23:30 +0000635 db_push = {}
636 if db_vdu_push_list:
637 db_push["vdur"] = db_vdu_push_list
638 if template_vdur:
639 db_push["vdur-template"] = template_vdur
640 if not db_push:
641 db_push = None
642 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000643 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
644 # modify passed dictionary db_vnfr
645 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
646 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200647
tiernof578e552018-11-08 19:07:20 +0100648 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
649 """
650 Updates database nsr with the RO info for the created vld
651 :param ns_update_nsr: dictionary to be filled with the updated info
652 :param db_nsr: content of db_nsr. This is also modified
653 :param nsr_desc_RO: nsr descriptor from RO
654 :return: Nothing, LcmException is raised on errors
655 """
656
657 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
658 for net_RO in get_iterable(nsr_desc_RO, "nets"):
659 if vld["id"] != net_RO.get("ns_net_osm_id"):
660 continue
661 vld["vim-id"] = net_RO.get("vim_net_id")
662 vld["name"] = net_RO.get("vim_name")
663 vld["status"] = net_RO.get("status")
664 vld["status-detailed"] = net_RO.get("error_msg")
665 ns_update_nsr["vld.{}".format(vld_index)] = vld
666 break
667 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100668 raise LcmException(
669 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
670 )
tiernof578e552018-11-08 19:07:20 +0100671
tiernoe876f672020-02-13 14:34:48 +0000672 def set_vnfr_at_error(self, db_vnfrs, error_text):
673 try:
674 for db_vnfr in db_vnfrs.values():
675 vnfr_update = {"status": "ERROR"}
676 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
677 if "status" not in vdur:
678 vdur["status"] = "ERROR"
679 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
680 if error_text:
681 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100682 vnfr_update[
683 "vdur.{}.status-detailed".format(vdu_index)
684 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000685 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
686 except DbException as e:
687 self.logger.error("Cannot update vnf. {}".format(e))
688
tierno59d22d22018-09-25 18:10:19 +0200689 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
690 """
691 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 +0200692 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
693 :param nsr_desc_RO: nsr descriptor from RO
694 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200695 """
696 for vnf_index, db_vnfr in db_vnfrs.items():
697 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200698 if vnf_RO["member_vnf_index"] != vnf_index:
699 continue
700 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100701 if vnf_RO.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100702 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO[
703 "ip_address"
704 ].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100705 elif not db_vnfr.get("ip-address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100706 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
707 raise LcmExceptionNoMgmtIP(
708 "ns member_vnf_index '{}' has no IP address".format(
709 vnf_index
710 )
711 )
tierno59d22d22018-09-25 18:10:19 +0200712
tierno27246d82018-09-27 15:59:09 +0200713 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
714 vdur_RO_count_index = 0
715 if vdur.get("pdu-type"):
716 continue
717 for vdur_RO in get_iterable(vnf_RO, "vms"):
718 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
719 continue
720 if vdur["count-index"] != vdur_RO_count_index:
721 vdur_RO_count_index += 1
722 continue
723 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000724 if vdur_RO.get("ip_address"):
725 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000726 else:
727 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200728 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
729 vdur["name"] = vdur_RO.get("vim_name")
730 vdur["status"] = vdur_RO.get("status")
731 vdur["status-detailed"] = vdur_RO.get("error_msg")
732 for ifacer in get_iterable(vdur, "interfaces"):
733 for interface_RO in get_iterable(vdur_RO, "interfaces"):
734 if ifacer["name"] == interface_RO.get("internal_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100735 ifacer["ip-address"] = interface_RO.get(
736 "ip_address"
737 )
738 ifacer["mac-address"] = interface_RO.get(
739 "mac_address"
740 )
tierno27246d82018-09-27 15:59:09 +0200741 break
742 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100743 raise LcmException(
744 "ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
745 "from VIM info".format(
746 vnf_index, vdur["vdu-id-ref"], ifacer["name"]
747 )
748 )
tierno27246d82018-09-27 15:59:09 +0200749 vnfr_update["vdur.{}".format(vdu_index)] = vdur
750 break
751 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100752 raise LcmException(
753 "ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
754 "VIM info".format(
755 vnf_index, vdur["vdu-id-ref"], vdur["count-index"]
756 )
757 )
tiernof578e552018-11-08 19:07:20 +0100758
759 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
760 for net_RO in get_iterable(nsr_desc_RO, "nets"):
761 if vld["id"] != net_RO.get("vnf_net_osm_id"):
762 continue
763 vld["vim-id"] = net_RO.get("vim_net_id")
764 vld["name"] = net_RO.get("vim_name")
765 vld["status"] = net_RO.get("status")
766 vld["status-detailed"] = net_RO.get("error_msg")
767 vnfr_update["vld.{}".format(vld_index)] = vld
768 break
769 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100770 raise LcmException(
771 "ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
772 vnf_index, vld["id"]
773 )
774 )
tiernof578e552018-11-08 19:07:20 +0100775
tierno27246d82018-09-27 15:59:09 +0200776 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
777 break
tierno59d22d22018-09-25 18:10:19 +0200778
779 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100780 raise LcmException(
781 "ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(
782 vnf_index
783 )
784 )
tierno59d22d22018-09-25 18:10:19 +0200785
tierno5ee02052019-12-05 19:55:02 +0000786 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000787 """
788 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000789 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000790 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
791 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
792 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
793 """
tierno5ee02052019-12-05 19:55:02 +0000794 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
795 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000796 mapping = {}
797 ns_config_info = {"osm-config-mapping": mapping}
798 for vca in vca_deployed_list:
799 if not vca["member-vnf-index"]:
800 continue
801 if not vca["vdu_id"]:
802 mapping[vca["member-vnf-index"]] = vca["application"]
803 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100804 mapping[
805 "{}.{}.{}".format(
806 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
807 )
808 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000809 return ns_config_info
810
garciadeblas5697b8b2021-03-24 09:17:02 +0100811 async def _instantiate_ng_ro(
812 self,
813 logging_text,
814 nsr_id,
815 nsd,
816 db_nsr,
817 db_nslcmop,
818 db_vnfrs,
819 db_vnfds,
820 n2vc_key_list,
821 stage,
822 start_deploy,
823 timeout_ns_deploy,
824 ):
tierno2357f4e2020-10-19 16:38:59 +0000825 db_vims = {}
826
827 def get_vim_account(vim_account_id):
828 nonlocal db_vims
829 if vim_account_id in db_vims:
830 return db_vims[vim_account_id]
831 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
832 db_vims[vim_account_id] = db_vim
833 return db_vim
834
835 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100836 def parse_vld_instantiation_params(
837 target_vim, target_vld, vld_params, target_sdn
838 ):
tierno2357f4e2020-10-19 16:38:59 +0000839 if vld_params.get("ip-profile"):
Gabriel Cubac7737442023-02-14 13:09:18 -0500840 target_vld["vim_info"][target_vim]["ip_profile"] = vld_to_ro_ip_profile(
841 vld_params["ip-profile"]
842 )
tierno2357f4e2020-10-19 16:38:59 +0000843 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100844 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
845 "provider-network"
846 ]
tierno2357f4e2020-10-19 16:38:59 +0000847 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100848 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
849 "provider-network"
850 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000851
852 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
853 # if wim_account_id is specified in vld_params, validate if it is feasible.
854 wim_account_id, db_wim = select_feasible_wim_account(
855 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
856 )
857
858 if wim_account_id:
859 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
860 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
861 # update vld_params with correct WIM account Id
862 vld_params["wimAccountId"] = wim_account_id
863
864 target_wim = "wim:{}".format(wim_account_id)
865 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
866 sdn_ports = get_sdn_ports(vld_params, db_wim)
867 if len(sdn_ports) > 0:
868 target_vld["vim_info"][target_wim] = target_wim_attrs
869 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
870
871 self.logger.debug(
872 "Target VLD with WIM data: {:s}".format(str(target_vld))
873 )
874
tierno2357f4e2020-10-19 16:38:59 +0000875 for param in ("vim-network-name", "vim-network-id"):
876 if vld_params.get(param):
877 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300878 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300879 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100880 populate_dict(
881 target_vld["vim_info"],
882 (other_target_vim, param.replace("-", "_")),
883 vim_net,
884 )
tierno2357f4e2020-10-19 16:38:59 +0000885 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100886 target_vld["vim_info"][target_vim][
887 param.replace("-", "_")
888 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300889 if vld_params.get("common_id"):
890 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000891
aticig15db6142022-01-24 12:51:26 +0300892 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
893 def update_ns_vld_target(target, ns_params):
894 for vnf_params in ns_params.get("vnf", ()):
895 if vnf_params.get("vimAccountId"):
896 target_vnf = next(
897 (
898 vnfr
899 for vnfr in db_vnfrs.values()
900 if vnf_params["member-vnf-index"]
901 == vnfr["member-vnf-index-ref"]
902 ),
903 None,
904 )
905 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100906 if not vdur:
Pedro Escaleira556f5c72023-04-20 15:22:16 +0100907 continue
aticig15db6142022-01-24 12:51:26 +0300908 for a_index, a_vld in enumerate(target["ns"]["vld"]):
909 target_vld = find_in_list(
910 get_iterable(vdur, "interfaces"),
911 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
912 )
aticig84bd9a72022-06-14 03:01:36 +0300913
914 vld_params = find_in_list(
915 get_iterable(ns_params, "vld"),
916 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
917 )
aticig15db6142022-01-24 12:51:26 +0300918 if target_vld:
919 if vnf_params.get("vimAccountId") not in a_vld.get(
920 "vim_info", {}
921 ):
aticig84bd9a72022-06-14 03:01:36 +0300922 target_vim_network_list = [
923 v for _, v in a_vld.get("vim_info").items()
924 ]
925 target_vim_network_name = next(
926 (
927 item.get("vim_network_name", "")
928 for item in target_vim_network_list
929 ),
930 "",
931 )
932
aticig15db6142022-01-24 12:51:26 +0300933 target["ns"]["vld"][a_index].get("vim_info").update(
934 {
935 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300936 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300937 }
938 }
939 )
940
aticig84bd9a72022-06-14 03:01:36 +0300941 if vld_params:
942 for param in ("vim-network-name", "vim-network-id"):
943 if vld_params.get(param) and isinstance(
944 vld_params[param], dict
945 ):
946 for vim, vim_net in vld_params[
947 param
948 ].items():
949 other_target_vim = "vim:" + vim
950 populate_dict(
951 target["ns"]["vld"][a_index].get(
952 "vim_info"
953 ),
954 (
955 other_target_vim,
956 param.replace("-", "_"),
957 ),
958 vim_net,
959 )
960
tierno69f0d382020-05-07 13:08:09 +0000961 nslcmop_id = db_nslcmop["_id"]
962 target = {
963 "name": db_nsr["name"],
964 "ns": {"vld": []},
965 "vnf": [],
966 "image": deepcopy(db_nsr["image"]),
967 "flavor": deepcopy(db_nsr["flavor"]),
968 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000969 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000970 }
971 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000972 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000973 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000974 flavor["vim_info"] = {}
vegall63162192023-03-06 14:19:16 +0000975 if db_nsr.get("shared-volumes"):
976 target["shared-volumes"] = deepcopy(db_nsr["shared-volumes"])
977 for shared_volumes in target["shared-volumes"]:
978 shared_volumes["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100979 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100980 target["affinity-or-anti-affinity-group"] = deepcopy(
981 db_nsr["affinity-or-anti-affinity-group"]
982 )
983 for affinity_or_anti_affinity_group in target[
984 "affinity-or-anti-affinity-group"
985 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100986 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000987
tierno2357f4e2020-10-19 16:38:59 +0000988 if db_nslcmop.get("lcmOperationType") != "instantiate":
989 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100990 db_nslcmop_instantiate = self.db.get_list(
991 "nslcmops",
992 {
993 "nsInstanceId": db_nslcmop["nsInstanceId"],
994 "lcmOperationType": "instantiate",
995 },
996 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000997 ns_params = db_nslcmop_instantiate.get("operationParams")
998 else:
999 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -03001000 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
1001 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +00001002
1003 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +00001004 for vld_index, vld in enumerate(db_nsr.get("vld")):
1005 target_vim = "vim:{}".format(ns_params["vimAccountId"])
1006 target_vld = {
1007 "id": vld["id"],
1008 "name": vld["name"],
1009 "mgmt-network": vld.get("mgmt-network", False),
1010 "type": vld.get("type"),
1011 "vim_info": {
bravof922c4172020-11-24 21:21:43 -03001012 target_vim: {
1013 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +01001014 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -03001015 }
garciadeblas5697b8b2021-03-24 09:17:02 +01001016 },
tierno2357f4e2020-10-19 16:38:59 +00001017 }
1018 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +00001019 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +00001020 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici0b430f62023-01-10 14:10:42 +03001021 if vim_config := db_vim.get("config"):
1022 if sdnc_id := vim_config.get("sdn-controller"):
1023 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
1024 target_sdn = "sdn:{}".format(sdnc_id)
1025 target_vld["vim_info"][target_sdn] = {
1026 "sdn": True,
1027 "target_vim": target_vim,
1028 "vlds": [sdn_vld],
1029 "type": vld.get("type"),
1030 }
tierno2357f4e2020-10-19 16:38:59 +00001031
bravof922c4172020-11-24 21:21:43 -03001032 nsd_vnf_profiles = get_vnf_profiles(nsd)
1033 for nsd_vnf_profile in nsd_vnf_profiles:
1034 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
1035 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001036 cp2target[
1037 "member_vnf:{}.{}".format(
1038 cp["constituent-cpd-id"][0][
1039 "constituent-base-element-id"
1040 ],
1041 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
1042 )
1043 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +00001044
1045 # check at nsd descriptor, if there is an ip-profile
1046 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +00001047 nsd_vlp = find_in_list(
1048 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001049 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
1050 == vld["id"],
1051 )
1052 if (
1053 nsd_vlp
1054 and nsd_vlp.get("virtual-link-protocol-data")
1055 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1056 ):
Gabriel Cubac7737442023-02-14 13:09:18 -05001057 vld_params["ip-profile"] = nsd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +01001058 "l3-protocol-data"
1059 ]
bravof922c4172020-11-24 21:21:43 -03001060
tierno2357f4e2020-10-19 16:38:59 +00001061 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +01001062 vld_instantiation_params = find_in_list(
1063 get_iterable(ns_params, "vld"),
1064 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
1065 )
tierno2357f4e2020-10-19 16:38:59 +00001066 if vld_instantiation_params:
1067 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -03001068 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +00001069 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +03001070 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
1071 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -03001072
tierno69f0d382020-05-07 13:08:09 +00001073 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +01001074 vnfd = find_in_list(
1075 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
1076 )
1077 vnf_params = find_in_list(
1078 get_iterable(ns_params, "vnf"),
1079 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
1080 )
tierno69f0d382020-05-07 13:08:09 +00001081 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +00001082 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +00001083 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +00001084 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +01001085 vnf_cp = find_in_list(
1086 vnfd.get("int-virtual-link-desc", ()),
1087 lambda cpd: cpd.get("id") == vld["id"],
1088 )
tierno69f0d382020-05-07 13:08:09 +00001089 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01001090 ns_cp = "member_vnf:{}.{}".format(
1091 vnfr["member-vnf-index-ref"], vnf_cp["id"]
1092 )
tierno69f0d382020-05-07 13:08:09 +00001093 if cp2target.get(ns_cp):
1094 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -03001095
garciadeblas5697b8b2021-03-24 09:17:02 +01001096 vld["vim_info"] = {
1097 target_vim: {"vim_network_name": vld.get("vim-network-name")}
1098 }
tierno2357f4e2020-10-19 16:38:59 +00001099 # check if this network needs SDN assist
1100 target_sdn = None
1101 if vld.get("pci-interfaces"):
1102 db_vim = get_vim_account(vnfr["vim-account-id"])
1103 sdnc_id = db_vim["config"].get("sdn-controller")
1104 if sdnc_id:
1105 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
1106 target_sdn = "sdn:{}".format(sdnc_id)
1107 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001108 "sdn": True,
1109 "target_vim": target_vim,
1110 "vlds": [sdn_vld],
1111 "type": vld.get("type"),
1112 }
tierno69f0d382020-05-07 13:08:09 +00001113
tierno2357f4e2020-10-19 16:38:59 +00001114 # check at vnfd descriptor, if there is an ip-profile
1115 vld_params = {}
bravof922c4172020-11-24 21:21:43 -03001116 vnfd_vlp = find_in_list(
1117 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001118 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -03001119 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001120 if (
1121 vnfd_vlp
1122 and vnfd_vlp.get("virtual-link-protocol-data")
1123 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1124 ):
Gabriel Cubac7737442023-02-14 13:09:18 -05001125 vld_params["ip-profile"] = vnfd_vlp["virtual-link-protocol-data"][
garciadeblas5697b8b2021-03-24 09:17:02 +01001126 "l3-protocol-data"
1127 ]
tierno2357f4e2020-10-19 16:38:59 +00001128 # update vld_params with instantiation params
1129 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01001130 vld_instantiation_params = find_in_list(
1131 get_iterable(vnf_params, "internal-vld"),
1132 lambda i_vld: i_vld["name"] == vld["id"],
1133 )
tierno2357f4e2020-10-19 16:38:59 +00001134 if vld_instantiation_params:
1135 vld_params.update(vld_instantiation_params)
1136 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1137
1138 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001139 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001140 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1141 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001142 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001143
bravof922c4172020-11-24 21:21:43 -03001144 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1145
1146 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001147 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1148 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001149 if (
1150 vdu_configuration
1151 and vdu_configuration.get("config-access")
1152 and vdu_configuration.get("config-access").get("ssh-access")
1153 ):
bravof922c4172020-11-24 21:21:43 -03001154 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001155 vdur["ssh-access-required"] = vdu_configuration[
1156 "config-access"
1157 ]["ssh-access"]["required"]
1158 elif (
1159 vnf_configuration
1160 and vnf_configuration.get("config-access")
1161 and vnf_configuration.get("config-access").get("ssh-access")
1162 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1163 ):
bravof922c4172020-11-24 21:21:43 -03001164 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001165 vdur["ssh-access-required"] = vnf_configuration[
1166 "config-access"
1167 ]["ssh-access"]["required"]
1168 elif ssh_keys_instantiation and find_in_list(
1169 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1170 ):
bravof922c4172020-11-24 21:21:43 -03001171 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001172
bravof922c4172020-11-24 21:21:43 -03001173 self.logger.debug("NS > vdur > {}".format(vdur))
1174
1175 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001176 # cloud-init
1177 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001178 vdur["cloud-init"] = "{}:file:{}".format(
1179 vnfd["_id"], vdud.get("cloud-init-file")
1180 )
tierno2357f4e2020-10-19 16:38:59 +00001181 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1182 if vdur["cloud-init"] not in target["cloud_init_content"]:
1183 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001184 if base_folder["pkg-dir"]:
1185 cloud_init_file = "{}/{}/cloud_init/{}".format(
1186 base_folder["folder"],
1187 base_folder["pkg-dir"],
1188 vdud.get("cloud-init-file"),
1189 )
1190 else:
1191 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1192 base_folder["folder"],
1193 vdud.get("cloud-init-file"),
1194 )
tierno2357f4e2020-10-19 16:38:59 +00001195 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001196 target["cloud_init_content"][
1197 vdur["cloud-init"]
1198 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001199 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001200 vdur["cloud-init"] = "{}:vdu:{}".format(
1201 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1202 )
tierno2357f4e2020-10-19 16:38:59 +00001203 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001204 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1205 "cloud-init"
1206 ]
tierno2357f4e2020-10-19 16:38:59 +00001207 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001208 deploy_params_vdu = self._format_additional_params(
1209 vdur.get("additionalParams") or {}
1210 )
1211 deploy_params_vdu["OSM"] = get_osm_params(
1212 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1213 )
tierno2357f4e2020-10-19 16:38:59 +00001214 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001215
1216 # flavor
1217 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001218 if target_vim not in ns_flavor["vim_info"]:
1219 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001220
1221 # deal with images
1222 # in case alternative images are provided we must check if they should be applied
1223 # for the vim_type, modify the vim_type taking into account
1224 ns_image_id = int(vdur["ns-image-id"])
1225 if vdur.get("alt-image-ids"):
1226 db_vim = get_vim_account(vnfr["vim-account-id"])
1227 vim_type = db_vim["vim_type"]
1228 for alt_image_id in vdur.get("alt-image-ids"):
1229 ns_alt_image = target["image"][int(alt_image_id)]
1230 if vim_type == ns_alt_image.get("vim-type"):
1231 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001232 self.logger.debug(
1233 "use alternative image id: {}".format(alt_image_id)
1234 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001235 ns_image_id = alt_image_id
1236 vdur["ns-image-id"] = ns_image_id
1237 break
1238 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001239 if target_vim not in ns_image["vim_info"]:
1240 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001241
Alexis Romero305b5c42022-03-11 15:29:18 +01001242 # Affinity groups
1243 if vdur.get("affinity-or-anti-affinity-group-id"):
1244 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1245 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1246 if target_vim not in ns_ags["vim_info"]:
1247 ns_ags["vim_info"][target_vim] = {}
1248
vegall63162192023-03-06 14:19:16 +00001249 # shared-volumes
1250 if vdur.get("shared-volumes-id"):
1251 for sv_id in vdur["shared-volumes-id"]:
1252 ns_sv = find_in_list(
1253 target["shared-volumes"], lambda sv: sv_id in sv["id"]
1254 )
1255 if ns_sv:
1256 ns_sv["vim_info"][target_vim] = {}
1257
tierno2357f4e2020-10-19 16:38:59 +00001258 vdur["vim_info"] = {target_vim: {}}
1259 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001260 if vnf_params:
1261 vdu_instantiation_params = find_in_list(
1262 get_iterable(vnf_params, "vdu"),
1263 lambda i_vdu: i_vdu["id"] == vdud["id"],
1264 )
1265 if vdu_instantiation_params:
1266 # Parse the vdu_volumes from the instantiation params
1267 vdu_volumes = get_volumes_from_instantiation_params(
1268 vdu_instantiation_params, vdud
1269 )
1270 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
Gabriel Cubae19017d2023-03-13 22:34:44 -05001271 vdur["additionalParams"]["OSM"][
1272 "vim_flavor_id"
1273 ] = vdu_instantiation_params.get("vim-flavor-id")
tierno2357f4e2020-10-19 16:38:59 +00001274 vdur_list.append(vdur)
1275 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001276 target["vnf"].append(target_vnf)
1277
garciadeblas07f4e4c2022-06-09 09:42:58 +02001278 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001279 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001280 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001281 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001282 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001283 nsr_id,
1284 action_id,
1285 nslcmop_id,
1286 start_deploy,
1287 timeout_ns_deploy,
1288 stage,
1289 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001290 )
tierno69f0d382020-05-07 13:08:09 +00001291
1292 # Updating NSR
1293 db_nsr_update = {
1294 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001295 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001296 }
1297 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1298 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1299 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001300 self.logger.debug(
1301 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1302 )
tierno69f0d382020-05-07 13:08:09 +00001303 return
1304
garciadeblas5697b8b2021-03-24 09:17:02 +01001305 async def _wait_ng_ro(
1306 self,
1307 nsr_id,
1308 action_id,
1309 nslcmop_id=None,
1310 start_time=None,
1311 timeout=600,
1312 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001313 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001314 ):
tierno69f0d382020-05-07 13:08:09 +00001315 detailed_status_old = None
1316 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001317 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001318 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001319 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001320 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001321 if desc_status["status"] == "FAILED":
1322 raise NgRoException(desc_status["details"])
1323 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001324 if stage:
1325 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001326 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001327 if stage:
1328 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001329 break
1330 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001331 assert False, "ROclient.check_ns_status returns unknown {}".format(
1332 desc_status["status"]
1333 )
tierno2357f4e2020-10-19 16:38:59 +00001334 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001335 detailed_status_old = stage[2]
1336 db_nsr_update["detailed-status"] = " ".join(stage)
1337 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1338 self._write_op_status(nslcmop_id, stage)
Gabriel Cubae7898982023-05-11 01:57:21 -05001339 await asyncio.sleep(15)
tierno69f0d382020-05-07 13:08:09 +00001340 else: # timeout_ns_deploy
1341 raise NgRoException("Timeout waiting ns to deploy")
1342
garciadeblas5697b8b2021-03-24 09:17:02 +01001343 async def _terminate_ng_ro(
1344 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1345 ):
tierno69f0d382020-05-07 13:08:09 +00001346 db_nsr_update = {}
1347 failed_detail = []
1348 action_id = None
1349 start_deploy = time()
1350 try:
1351 target = {
1352 "ns": {"vld": []},
1353 "vnf": [],
1354 "image": [],
1355 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001356 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001357 }
1358 desc = await self.RO.deploy(nsr_id, target)
1359 action_id = desc["action_id"]
tierno69f0d382020-05-07 13:08:09 +00001360 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001361 self.logger.debug(
1362 logging_text
1363 + "ns terminate action at RO. action_id={}".format(action_id)
1364 )
tierno69f0d382020-05-07 13:08:09 +00001365
1366 # wait until done
1367 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001368 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001369 nsr_id,
1370 action_id,
1371 nslcmop_id,
1372 start_deploy,
1373 delete_timeout,
1374 stage,
1375 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001376 )
tierno69f0d382020-05-07 13:08:09 +00001377 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1378 # delete all nsr
1379 await self.RO.delete(nsr_id)
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001380 except NgRoException as e:
1381 if e.http_code == 404: # not found
tierno69f0d382020-05-07 13:08:09 +00001382 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1383 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
garciadeblas5697b8b2021-03-24 09:17:02 +01001384 self.logger.debug(
1385 logging_text + "RO_action_id={} already deleted".format(action_id)
1386 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001387 elif e.http_code == 409: # conflict
tierno69f0d382020-05-07 13:08:09 +00001388 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001389 self.logger.debug(
1390 logging_text
1391 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1392 )
tierno69f0d382020-05-07 13:08:09 +00001393 else:
1394 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001395 self.logger.error(
1396 logging_text
1397 + "RO_action_id={} delete error: {}".format(action_id, e)
1398 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001399 except Exception as e:
1400 failed_detail.append("delete error: {}".format(e))
1401 self.logger.error(
1402 logging_text + "RO_action_id={} delete error: {}".format(action_id, e)
1403 )
tierno69f0d382020-05-07 13:08:09 +00001404
1405 if failed_detail:
1406 stage[2] = "Error deleting from VIM"
1407 else:
1408 stage[2] = "Deleted from VIM"
1409 db_nsr_update["detailed-status"] = " ".join(stage)
1410 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1411 self._write_op_status(nslcmop_id, stage)
1412
1413 if failed_detail:
1414 raise LcmException("; ".join(failed_detail))
1415 return
1416
garciadeblas5697b8b2021-03-24 09:17:02 +01001417 async def instantiate_RO(
1418 self,
1419 logging_text,
1420 nsr_id,
1421 nsd,
1422 db_nsr,
1423 db_nslcmop,
1424 db_vnfrs,
1425 db_vnfds,
1426 n2vc_key_list,
1427 stage,
1428 ):
tiernoe95ed362020-04-23 08:24:57 +00001429 """
1430 Instantiate at RO
1431 :param logging_text: preffix text to use at logging
1432 :param nsr_id: nsr identity
1433 :param nsd: database content of ns descriptor
1434 :param db_nsr: database content of ns record
1435 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1436 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001437 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001438 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1439 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1440 :return: None or exception
1441 """
tiernoe876f672020-02-13 14:34:48 +00001442 try:
tiernoe876f672020-02-13 14:34:48 +00001443 start_deploy = time()
1444 ns_params = db_nslcmop.get("operationParams")
1445 if ns_params and ns_params.get("timeout_ns_deploy"):
1446 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1447 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00001448 timeout_ns_deploy = self.timeout.ns_deploy
quilesj7e13aeb2019-10-08 13:34:55 +02001449
tiernoe876f672020-02-13 14:34:48 +00001450 # Check for and optionally request placement optimization. Database will be updated if placement activated
1451 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001452 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1453 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1454 for vnfr in db_vnfrs.values():
1455 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1456 break
1457 else:
1458 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001459
garciadeblas5697b8b2021-03-24 09:17:02 +01001460 return await self._instantiate_ng_ro(
1461 logging_text,
1462 nsr_id,
1463 nsd,
1464 db_nsr,
1465 db_nslcmop,
1466 db_vnfrs,
1467 db_vnfds,
1468 n2vc_key_list,
1469 stage,
1470 start_deploy,
1471 timeout_ns_deploy,
1472 )
tierno2357f4e2020-10-19 16:38:59 +00001473 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001474 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001475 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001476 self.logger.error(
1477 "Error deploying at VIM {}".format(e),
1478 exc_info=not isinstance(
1479 e,
1480 (
1481 ROclient.ROClientException,
1482 LcmException,
1483 DbException,
1484 NgRoException,
1485 ),
1486 ),
1487 )
tiernoe876f672020-02-13 14:34:48 +00001488 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001489
tierno7ecbc342020-09-21 14:05:39 +00001490 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1491 """
1492 Wait for kdu to be up, get ip address
1493 :param logging_text: prefix use for logging
1494 :param nsr_id:
1495 :param vnfr_id:
1496 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001497 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001498 """
1499
1500 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1501 nb_tries = 0
1502
1503 while nb_tries < 360:
1504 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001505 kdur = next(
1506 (
1507 x
1508 for x in get_iterable(db_vnfr, "kdur")
1509 if x.get("kdu-name") == kdu_name
1510 ),
1511 None,
1512 )
tierno7ecbc342020-09-21 14:05:39 +00001513 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001514 raise LcmException(
1515 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1516 )
tierno7ecbc342020-09-21 14:05:39 +00001517 if kdur.get("status"):
1518 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001519 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001520 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001521 raise LcmException(
1522 "target KDU={} is in error state".format(kdu_name)
1523 )
tierno7ecbc342020-09-21 14:05:39 +00001524
Gabriel Cubae7898982023-05-11 01:57:21 -05001525 await asyncio.sleep(10)
tierno7ecbc342020-09-21 14:05:39 +00001526 nb_tries += 1
1527 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1528
garciadeblas5697b8b2021-03-24 09:17:02 +01001529 async def wait_vm_up_insert_key_ro(
1530 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1531 ):
tiernoa5088192019-11-26 16:12:53 +00001532 """
1533 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1534 :param logging_text: prefix use for logging
1535 :param nsr_id:
1536 :param vnfr_id:
1537 :param vdu_id:
1538 :param vdu_index:
1539 :param pub_key: public ssh key to inject, None to skip
1540 :param user: user to apply the public ssh key
1541 :return: IP address
1542 """
quilesj7e13aeb2019-10-08 13:34:55 +02001543
tierno2357f4e2020-10-19 16:38:59 +00001544 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001545 ip_address = None
tiernod8323042019-08-09 11:32:23 +00001546 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001547 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001548
tiernod8323042019-08-09 11:32:23 +00001549 while True:
quilesj3149f262019-12-03 10:58:10 +00001550 ro_retries += 1
1551 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001552 raise LcmException(
1553 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1554 )
quilesj3149f262019-12-03 10:58:10 +00001555
Gabriel Cubae7898982023-05-11 01:57:21 -05001556 await asyncio.sleep(10)
quilesj7e13aeb2019-10-08 13:34:55 +02001557
1558 # get ip address
tiernod8323042019-08-09 11:32:23 +00001559 if not target_vdu_id:
1560 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001561
1562 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001563 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001564 raise LcmException(
1565 "Cannot inject ssh-key because target VNF is in error state"
1566 )
tiernod8323042019-08-09 11:32:23 +00001567 ip_address = db_vnfr.get("ip-address")
1568 if not ip_address:
1569 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001570 vdur = next(
1571 (
1572 x
1573 for x in get_iterable(db_vnfr, "vdur")
1574 if x.get("ip-address") == ip_address
1575 ),
1576 None,
1577 )
quilesj3149f262019-12-03 10:58:10 +00001578 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001579 vdur = next(
1580 (
1581 x
1582 for x in get_iterable(db_vnfr, "vdur")
1583 if x.get("vdu-id-ref") == vdu_id
1584 and x.get("count-index") == vdu_index
1585 ),
1586 None,
1587 )
quilesj3149f262019-12-03 10:58:10 +00001588
garciadeblas5697b8b2021-03-24 09:17:02 +01001589 if (
1590 not vdur and len(db_vnfr.get("vdur", ())) == 1
1591 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001592 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001593 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001594 raise LcmException(
1595 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1596 vnfr_id, vdu_id, vdu_index
1597 )
1598 )
tierno2357f4e2020-10-19 16:38:59 +00001599 # New generation RO stores information at "vim_info"
1600 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001601 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001602 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001603 target_vim = next(
1604 t for t in vdur["vim_info"]
1605 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001606 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001607 if (
1608 vdur.get("pdu-type")
1609 or vdur.get("status") == "ACTIVE"
1610 or ng_ro_status == "ACTIVE"
1611 ):
quilesj3149f262019-12-03 10:58:10 +00001612 ip_address = vdur.get("ip-address")
1613 if not ip_address:
1614 continue
1615 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001616 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001617 raise LcmException(
1618 "Cannot inject ssh-key because target VM is in error state"
1619 )
quilesj3149f262019-12-03 10:58:10 +00001620
tiernod8323042019-08-09 11:32:23 +00001621 if not target_vdu_id:
1622 continue
tiernod8323042019-08-09 11:32:23 +00001623
quilesj7e13aeb2019-10-08 13:34:55 +02001624 # inject public key into machine
1625 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001626 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001627 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001628 if vdur.get("pdu-type"):
1629 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1630 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001631 try:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001632 target = {
1633 "action": {
1634 "action": "inject_ssh_key",
1635 "key": pub_key,
1636 "user": user,
1637 },
1638 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1639 }
1640 desc = await self.RO.deploy(nsr_id, target)
1641 action_id = desc["action_id"]
1642 await self._wait_ng_ro(
1643 nsr_id, action_id, timeout=600, operation="instantiation"
1644 )
1645 break
tierno69f0d382020-05-07 13:08:09 +00001646 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001647 raise LcmException(
1648 "Reaching max tries injecting key. Error: {}".format(e)
1649 )
quilesj7e13aeb2019-10-08 13:34:55 +02001650 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001651 break
1652
1653 return ip_address
1654
tierno5ee02052019-12-05 19:55:02 +00001655 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1656 """
1657 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1658 """
1659 my_vca = vca_deployed_list[vca_index]
1660 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001661 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001662 return
1663 timeout = 300
1664 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001665 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1666 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1667 configuration_status_list = db_nsr["configurationStatus"]
1668 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001669 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001670 # myself
tierno5ee02052019-12-05 19:55:02 +00001671 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001672 if not my_vca.get("member-vnf-index") or (
1673 vca_deployed.get("member-vnf-index")
1674 == my_vca.get("member-vnf-index")
1675 ):
quilesj3655ae02019-12-12 16:08:35 +00001676 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001677 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001678 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001679 elif internal_status == "BROKEN":
1680 raise LcmException(
1681 "Configuration aborted because dependent charm/s has failed"
1682 )
quilesj3655ae02019-12-12 16:08:35 +00001683 else:
1684 break
tierno5ee02052019-12-05 19:55:02 +00001685 else:
quilesj3655ae02019-12-12 16:08:35 +00001686 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001687 return
1688 await asyncio.sleep(10)
1689 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001690
1691 raise LcmException("Configuration aborted because dependent charm/s timeout")
1692
David Garciac1fe90a2021-03-31 19:12:02 +02001693 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001694 vca_id = None
1695 if db_vnfr:
1696 vca_id = deep_get(db_vnfr, ("vca-id",))
1697 elif db_nsr:
1698 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1699 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1700 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001701
garciadeblas5697b8b2021-03-24 09:17:02 +01001702 async def instantiate_N2VC(
1703 self,
1704 logging_text,
1705 vca_index,
1706 nsi_id,
1707 db_nsr,
1708 db_vnfr,
1709 vdu_id,
1710 kdu_name,
1711 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01001712 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001713 config_descriptor,
1714 deploy_params,
1715 base_folder,
1716 nslcmop_id,
1717 stage,
1718 vca_type,
1719 vca_name,
1720 ee_config_descriptor,
1721 ):
tiernod8323042019-08-09 11:32:23 +00001722 nsr_id = db_nsr["_id"]
1723 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001724 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001725 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001726 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001727 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001728 "collection": "nsrs",
1729 "filter": {"_id": nsr_id},
1730 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001731 }
tiernod8323042019-08-09 11:32:23 +00001732 step = ""
1733 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001734 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001735 element_under_configuration = nsr_id
1736
tiernod8323042019-08-09 11:32:23 +00001737 vnfr_id = None
1738 if db_vnfr:
1739 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001740 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001741
garciadeblas5697b8b2021-03-24 09:17:02 +01001742 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001743
aktas98488ed2021-07-29 17:42:49 +03001744 if vca_type == "native_charm":
1745 index_number = 0
1746 else:
1747 index_number = vdu_index or 0
1748
tiernod8323042019-08-09 11:32:23 +00001749 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001750 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001751 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001752 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001753 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001754 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001755 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001756 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001757 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001758 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001759 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001760 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001761 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001762 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001763
1764 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001765 if base_folder["pkg-dir"]:
1766 artifact_path = "{}/{}/{}/{}".format(
1767 base_folder["folder"],
1768 base_folder["pkg-dir"],
1769 "charms"
aticig15db6142022-01-24 12:51:26 +03001770 if vca_type
1771 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001772 else "helm-charts",
1773 vca_name,
1774 )
1775 else:
1776 artifact_path = "{}/Scripts/{}/{}/".format(
1777 base_folder["folder"],
1778 "charms"
aticig15db6142022-01-24 12:51:26 +03001779 if vca_type
1780 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001781 else "helm-charts",
1782 vca_name,
1783 )
bravof922c4172020-11-24 21:21:43 -03001784
1785 self.logger.debug("Artifact path > {}".format(artifact_path))
1786
tiernoa278b842020-07-08 15:33:55 +00001787 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001788 initial_config_primitive_list = config_descriptor.get(
1789 "initial-config-primitive"
1790 )
tiernoa278b842020-07-08 15:33:55 +00001791
garciadeblas5697b8b2021-03-24 09:17:02 +01001792 self.logger.debug(
1793 "Initial config primitive list > {}".format(
1794 initial_config_primitive_list
1795 )
1796 )
bravof922c4172020-11-24 21:21:43 -03001797
tiernoa278b842020-07-08 15:33:55 +00001798 # add config if not present for NS charm
1799 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001800 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001801 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1802 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1803 )
tiernod8323042019-08-09 11:32:23 +00001804
garciadeblas5697b8b2021-03-24 09:17:02 +01001805 self.logger.debug(
1806 "Initial config primitive list #2 > {}".format(
1807 initial_config_primitive_list
1808 )
1809 )
tierno588547c2020-07-01 15:30:20 +00001810 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001811 # find old ee_id if exists
1812 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001813
David Garciac1fe90a2021-03-31 19:12:02 +02001814 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001815 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001816 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001817 self._write_configuration_status(
1818 nsr_id=nsr_id,
1819 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001820 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001821 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001822 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001823 )
tiernod8323042019-08-09 11:32:23 +00001824
tierno588547c2020-07-01 15:30:20 +00001825 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001826 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001827
1828 ee_id = None
1829 credentials = None
1830 if vca_type == "k8s_proxy_charm":
1831 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001832 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001833 namespace=namespace,
1834 artifact_path=artifact_path,
1835 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001836 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001837 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001838 elif vca_type == "helm" or vca_type == "helm-v3":
1839 ee_id, credentials = await self.vca_map[
1840 vca_type
1841 ].create_execution_environment(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05001842 namespace=nsr_id,
bravof922c4172020-11-24 21:21:43 -03001843 reuse_ee_id=ee_id,
1844 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001845 config=osm_config,
1846 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001847 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001848 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001849 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001850 else:
1851 ee_id, credentials = await self.vca_map[
1852 vca_type
1853 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001854 namespace=namespace,
1855 reuse_ee_id=ee_id,
1856 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001857 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001858 )
quilesj3655ae02019-12-12 16:08:35 +00001859
tierno588547c2020-07-01 15:30:20 +00001860 elif vca_type == "native_charm":
1861 step = "Waiting to VM being up and getting IP address"
1862 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001863 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1864 logging_text,
1865 nsr_id,
1866 vnfr_id,
1867 vdu_id,
1868 vdu_index,
1869 user=None,
1870 pub_key=None,
1871 )
tierno588547c2020-07-01 15:30:20 +00001872 credentials = {"hostname": rw_mgmt_ip}
1873 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001874 username = deep_get(
1875 config_descriptor, ("config-access", "ssh-access", "default-user")
1876 )
tierno588547c2020-07-01 15:30:20 +00001877 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1878 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001879 if not username and initial_config_primitive_list:
1880 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001881 for param in config_primitive.get("parameter", ()):
1882 if param["name"] == "ssh-username":
1883 username = param["value"]
1884 break
1885 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001886 raise LcmException(
1887 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1888 "'config-access.ssh-access.default-user'"
1889 )
tierno588547c2020-07-01 15:30:20 +00001890 credentials["username"] = username
1891 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001892
tierno588547c2020-07-01 15:30:20 +00001893 self._write_configuration_status(
1894 nsr_id=nsr_id,
1895 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001896 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001897 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001898 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001899 )
quilesj3655ae02019-12-12 16:08:35 +00001900
tierno588547c2020-07-01 15:30:20 +00001901 step = "register execution environment {}".format(credentials)
1902 self.logger.debug(logging_text + step)
1903 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001904 credentials=credentials,
1905 namespace=namespace,
1906 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001907 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001908 )
tierno3bedc9b2019-11-27 15:46:57 +00001909
tierno588547c2020-07-01 15:30:20 +00001910 # for compatibility with MON/POL modules, the need model and application name at database
1911 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001912 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001913 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1914 if len(ee_id_parts) >= 2:
1915 model_name = ee_id_parts[0]
1916 application_name = ee_id_parts[1]
1917 db_nsr_update[db_update_entry + "model"] = model_name
1918 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001919
1920 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001921 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001922
tiernoc231a872020-01-21 08:49:05 +00001923 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001924 nsr_id=nsr_id,
1925 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001926 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001927 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001928 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001929 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001930 )
1931
tierno3bedc9b2019-11-27 15:46:57 +00001932 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001933 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001934 config = None
tierno588547c2020-07-01 15:30:20 +00001935 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001936 config_primitive = next(
1937 (p for p in initial_config_primitive_list if p["name"] == "config"),
1938 None,
1939 )
tiernoa278b842020-07-08 15:33:55 +00001940 if config_primitive:
1941 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01001942 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00001943 )
tierno588547c2020-07-01 15:30:20 +00001944 num_units = 1
1945 if vca_type == "lxc_proxy_charm":
1946 if element_type == "NS":
1947 num_units = db_nsr.get("config-units") or 1
1948 elif element_type == "VNF":
1949 num_units = db_vnfr.get("config-units") or 1
1950 elif element_type == "VDU":
1951 for v in db_vnfr["vdur"]:
1952 if vdu_id == v["vdu-id-ref"]:
1953 num_units = v.get("config-units") or 1
1954 break
David Garciaaae391f2020-11-09 11:12:54 +01001955 if vca_type != "k8s_proxy_charm":
1956 await self.vca_map[vca_type].install_configuration_sw(
1957 ee_id=ee_id,
1958 artifact_path=artifact_path,
1959 db_dict=db_dict,
1960 config=config,
1961 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001962 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03001963 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01001964 )
quilesj7e13aeb2019-10-08 13:34:55 +02001965
quilesj63f90042020-01-17 09:53:55 +00001966 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01001967 self.update_db_2(
1968 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
1969 )
quilesj63f90042020-01-17 09:53:55 +00001970
1971 # add relations for this VCA (wait for other peers related with this VCA)
Patricia Reinosob4312c02023-01-06 22:28:44 +00001972 is_relation_added = await self._add_vca_relations(
garciadeblas5697b8b2021-03-24 09:17:02 +01001973 logging_text=logging_text,
1974 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001975 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02001976 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001977 )
quilesj63f90042020-01-17 09:53:55 +00001978
Patricia Reinosob4312c02023-01-06 22:28:44 +00001979 if not is_relation_added:
1980 raise LcmException("Relations could not be added to VCA.")
1981
quilesj7e13aeb2019-10-08 13:34:55 +02001982 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001983 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001984 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001985 pub_key = None
1986 user = None
tierno588547c2020-07-01 15:30:20 +00001987 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01001988 if deep_get(
1989 config_descriptor, ("config-access", "ssh-access", "required")
1990 ):
tierno588547c2020-07-01 15:30:20 +00001991 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001992 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01001993 user = deep_get(
1994 config_descriptor,
1995 ("config-access", "ssh-access", "default-user"),
1996 )
tierno3bedc9b2019-11-27 15:46:57 +00001997 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001998 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01001999 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02002000 )
quilesj7e13aeb2019-10-08 13:34:55 +02002001
garciadeblas5697b8b2021-03-24 09:17:02 +01002002 step = "Insert public key into VM user={} ssh_key={}".format(
2003 user, pub_key
2004 )
tierno3bedc9b2019-11-27 15:46:57 +00002005 else:
tierno588547c2020-07-01 15:30:20 +00002006 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00002007 step = "Waiting to VM being up and getting IP address"
2008 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02002009
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002010 # default rw_mgmt_ip to None, avoiding the non definition of the variable
2011 rw_mgmt_ip = None
2012
tierno3bedc9b2019-11-27 15:46:57 +00002013 # n2vc_redesign STEP 5.1
2014 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00002015 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00002016 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02002017 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01002018 logging_text, nsr_id, vnfr_id, kdu_name
2019 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002020 vnfd = self.db.get_one(
2021 "vnfds_revisions",
2022 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
2023 )
2024 kdu = get_kdu(vnfd, kdu_name)
2025 kdu_services = [
2026 service["name"] for service in get_kdu_services(kdu)
2027 ]
2028 exposed_services = []
2029 for service in services:
2030 if any(s in service["name"] for s in kdu_services):
2031 exposed_services.append(service)
2032 await self.vca_map[vca_type].exec_primitive(
2033 ee_id=ee_id,
2034 primitive_name="config",
2035 params_dict={
2036 "osm-config": json.dumps(
2037 OsmConfigBuilder(
2038 k8s={"services": exposed_services}
2039 ).build()
2040 )
2041 },
2042 vca_id=vca_id,
2043 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002044
2045 # This verification is needed in order to avoid trying to add a public key
2046 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
2047 # for a KNF and not for its KDUs, the previous verification gives False, and the code
2048 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
2049 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00002050 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002051 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2052 logging_text,
2053 nsr_id,
2054 vnfr_id,
2055 vdu_id,
2056 vdu_index,
2057 user=user,
2058 pub_key=pub_key,
2059 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002060
garciadeblas5697b8b2021-03-24 09:17:02 +01002061 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02002062
tiernoa5088192019-11-26 16:12:53 +00002063 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02002064 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00002065
2066 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01002067 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00002068
2069 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00002070 if initial_config_primitive_list:
2071 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00002072
2073 # stage, in function of element type: vdu, kdu, vnf or ns
2074 my_vca = vca_deployed_list[vca_index]
2075 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
2076 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01002077 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00002078 elif my_vca.get("member-vnf-index"):
2079 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01002080 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00002081 else:
2082 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01002083 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00002084
tiernoc231a872020-01-21 08:49:05 +00002085 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002086 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002087 )
2088
garciadeblas5697b8b2021-03-24 09:17:02 +01002089 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002090
tiernoe876f672020-02-13 14:34:48 +00002091 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002092 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002093 # adding information on the vca_deployed if it is a NS execution environment
2094 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002095 deploy_params["ns_config_info"] = json.dumps(
2096 self._get_ns_config_info(nsr_id)
2097 )
tiernod8323042019-08-09 11:32:23 +00002098 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002099 primitive_params_ = self._map_primitive_params(
2100 initial_config_primitive, {}, deploy_params
2101 )
tierno3bedc9b2019-11-27 15:46:57 +00002102
garciadeblas5697b8b2021-03-24 09:17:02 +01002103 step = "execute primitive '{}' params '{}'".format(
2104 initial_config_primitive["name"], primitive_params_
2105 )
tiernod8323042019-08-09 11:32:23 +00002106 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002107 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002108 ee_id=ee_id,
2109 primitive_name=initial_config_primitive["name"],
2110 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002111 db_dict=db_dict,
2112 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002113 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002114 )
tiernoe876f672020-02-13 14:34:48 +00002115 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2116 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002117 if config_descriptor.get("terminate-config-primitive"):
2118 self.update_db_2(
2119 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2120 )
tiernoe876f672020-02-13 14:34:48 +00002121 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002122
tiernod8323042019-08-09 11:32:23 +00002123 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002124
tiernob996d942020-07-03 14:52:28 +00002125 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002126 if vca_type == "helm" or vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02002127 # TODO: review for those cases where the helm chart is a reference and
2128 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002129 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002130 ee_id=ee_id,
2131 artifact_path=artifact_path,
2132 ee_config_descriptor=ee_config_descriptor,
2133 vnfr_id=vnfr_id,
2134 nsr_id=nsr_id,
2135 target_ip=rw_mgmt_ip,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002136 element_type=element_type,
2137 vnf_member_index=db_vnfr.get("member-vnf-index-ref", ""),
2138 vdu_id=vdu_id,
2139 vdu_index=vdu_index,
2140 kdu_name=kdu_name,
2141 kdu_index=kdu_index,
tiernob996d942020-07-03 14:52:28 +00002142 )
2143 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002144 self.update_db_2(
2145 "nsrs",
2146 nsr_id,
2147 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2148 )
tiernob996d942020-07-03 14:52:28 +00002149
bravof73bac502021-05-11 07:38:47 -04002150 for job in prometheus_jobs:
2151 self.db.set_one(
2152 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002153 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002154 job,
2155 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002156 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002157 )
2158
quilesj7e13aeb2019-10-08 13:34:55 +02002159 step = "instantiated at VCA"
2160 self.logger.debug(logging_text + step)
2161
tiernoc231a872020-01-21 08:49:05 +00002162 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002163 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002164 )
2165
tiernod8323042019-08-09 11:32:23 +00002166 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002167 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002168 if not isinstance(
2169 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2170 ):
2171 self.logger.error(
2172 "Exception while {} : {}".format(step, e), exc_info=True
2173 )
tiernoc231a872020-01-21 08:49:05 +00002174 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002175 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002176 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00002177 raise LcmException("{}. {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002178
garciadeblas5697b8b2021-03-24 09:17:02 +01002179 def _write_ns_status(
2180 self,
2181 nsr_id: str,
2182 ns_state: str,
2183 current_operation: str,
2184 current_operation_id: str,
2185 error_description: str = None,
2186 error_detail: str = None,
2187 other_update: dict = None,
2188 ):
tiernoe876f672020-02-13 14:34:48 +00002189 """
2190 Update db_nsr fields.
2191 :param nsr_id:
2192 :param ns_state:
2193 :param current_operation:
2194 :param current_operation_id:
2195 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002196 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002197 :param other_update: Other required changes at database if provided, will be cleared
2198 :return:
2199 """
quilesj4cda56b2019-12-05 10:02:20 +00002200 try:
tiernoe876f672020-02-13 14:34:48 +00002201 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002202 db_dict[
2203 "_admin.nslcmop"
2204 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002205 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002206 db_dict["_admin.operation-type"] = (
2207 current_operation if current_operation != "IDLE" else None
2208 )
quilesj4cda56b2019-12-05 10:02:20 +00002209 db_dict["currentOperation"] = current_operation
2210 db_dict["currentOperationID"] = current_operation_id
2211 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002212 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002213
2214 if ns_state:
2215 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002216 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002217 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002218 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002219
garciadeblas5697b8b2021-03-24 09:17:02 +01002220 def _write_op_status(
2221 self,
2222 op_id: str,
2223 stage: list = None,
2224 error_message: str = None,
2225 queuePosition: int = 0,
2226 operation_state: str = None,
2227 other_update: dict = None,
2228 ):
quilesj3655ae02019-12-12 16:08:35 +00002229 try:
tiernoe876f672020-02-13 14:34:48 +00002230 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002231 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002232 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002233 db_dict["stage"] = stage[0]
2234 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002235 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002236 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002237
2238 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002239 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002240 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002241 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002242 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002243 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002244 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002245 self.logger.warn(
2246 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2247 )
quilesj3655ae02019-12-12 16:08:35 +00002248
tierno51183952020-04-03 15:48:18 +00002249 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002250 try:
tierno51183952020-04-03 15:48:18 +00002251 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002252 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002253 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002254 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002255 db_nsr_update = {
2256 "configurationStatus.{}.status".format(index): status
2257 for index, v in enumerate(config_status)
2258 if v
2259 }
quilesj3655ae02019-12-12 16:08:35 +00002260 # update status
tierno51183952020-04-03 15:48:18 +00002261 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002262
tiernoe876f672020-02-13 14:34:48 +00002263 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002264 self.logger.warn(
2265 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2266 )
quilesj3655ae02019-12-12 16:08:35 +00002267
garciadeblas5697b8b2021-03-24 09:17:02 +01002268 def _write_configuration_status(
2269 self,
2270 nsr_id: str,
2271 vca_index: int,
2272 status: str = None,
2273 element_under_configuration: str = None,
2274 element_type: str = None,
2275 other_update: dict = None,
2276 ):
quilesj3655ae02019-12-12 16:08:35 +00002277 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2278 # .format(vca_index, status))
2279
2280 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002281 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002282 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002283 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002284 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002285 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002286 db_dict[
2287 db_path + "elementUnderConfiguration"
2288 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002289 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002290 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002291 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002292 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002293 self.logger.warn(
2294 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2295 status, nsr_id, vca_index, e
2296 )
2297 )
quilesj4cda56b2019-12-05 10:02:20 +00002298
tierno38089af2020-04-16 07:56:58 +00002299 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2300 """
2301 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2302 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2303 Database is used because the result can be obtained from a different LCM worker in case of HA.
2304 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2305 :param db_nslcmop: database content of nslcmop
2306 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002307 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2308 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002309 """
tierno8790a3d2020-04-23 22:49:52 +00002310 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002311 nslcmop_id = db_nslcmop["_id"]
2312 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002313 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002314 self.logger.debug(
2315 logging_text + "Invoke and wait for placement optimization"
2316 )
Gabriel Cubae7898982023-05-11 01:57:21 -05002317 await self.msg.aiowrite("pla", "get_placement", {"nslcmopId": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01002318 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002319 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002320 pla_result = None
2321 while not pla_result and wait >= 0:
2322 await asyncio.sleep(db_poll_interval)
2323 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002324 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002325 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002326
2327 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002328 raise LcmException(
2329 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2330 )
magnussonle9198bb2020-01-21 13:00:51 +01002331
garciadeblas5697b8b2021-03-24 09:17:02 +01002332 for pla_vnf in pla_result["vnf"]:
2333 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2334 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002335 continue
tierno8790a3d2020-04-23 22:49:52 +00002336 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002337 self.db.set_one(
2338 "vnfrs",
2339 {"_id": vnfr["_id"]},
2340 {"vim-account-id": pla_vnf["vimAccountId"]},
2341 )
tierno38089af2020-04-16 07:56:58 +00002342 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002343 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002344 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002345
aguilard1ae3c562023-02-16 17:24:35 +00002346 def _gather_vnfr_healing_alerts(self, vnfr, vnfd):
2347 alerts = []
2348 nsr_id = vnfr["nsr-id-ref"]
2349 df = vnfd.get("df", [{}])[0]
2350 # Checking for auto-healing configuration
2351 if "healing-aspect" in df:
2352 healing_aspects = df["healing-aspect"]
2353 for healing in healing_aspects:
2354 for healing_policy in healing.get("healing-policy", ()):
2355 vdu_id = healing_policy["vdu-id"]
2356 vdur = next(
2357 (vdur for vdur in vnfr["vdur"] if vdu_id == vdur["vdu-id-ref"]),
2358 {},
2359 )
2360 if not vdur:
2361 continue
2362 metric_name = "vm_status"
2363 vdu_name = vdur.get("name")
2364 vnf_member_index = vnfr["member-vnf-index-ref"]
2365 uuid = str(uuid4())
2366 name = f"healing_{uuid}"
2367 action = healing_policy
2368 # action_on_recovery = healing.get("action-on-recovery")
2369 # cooldown_time = healing.get("cooldown-time")
2370 # day1 = healing.get("day1")
2371 alert = {
2372 "uuid": uuid,
2373 "name": name,
2374 "metric": metric_name,
2375 "tags": {
2376 "ns_id": nsr_id,
2377 "vnf_member_index": vnf_member_index,
2378 "vdu_name": vdu_name,
2379 },
2380 "alarm_status": "ok",
2381 "action_type": "healing",
2382 "action": action,
2383 }
2384 alerts.append(alert)
2385 return alerts
2386
2387 def _gather_vnfr_scaling_alerts(self, vnfr, vnfd):
2388 alerts = []
2389 nsr_id = vnfr["nsr-id-ref"]
2390 df = vnfd.get("df", [{}])[0]
2391 # Checking for auto-scaling configuration
2392 if "scaling-aspect" in df:
aguilard1ae3c562023-02-16 17:24:35 +00002393 scaling_aspects = df["scaling-aspect"]
2394 all_vnfd_monitoring_params = {}
2395 for ivld in vnfd.get("int-virtual-link-desc", ()):
2396 for mp in ivld.get("monitoring-parameters", ()):
2397 all_vnfd_monitoring_params[mp.get("id")] = mp
2398 for vdu in vnfd.get("vdu", ()):
2399 for mp in vdu.get("monitoring-parameter", ()):
2400 all_vnfd_monitoring_params[mp.get("id")] = mp
2401 for df in vnfd.get("df", ()):
2402 for mp in df.get("monitoring-parameter", ()):
2403 all_vnfd_monitoring_params[mp.get("id")] = mp
2404 for scaling_aspect in scaling_aspects:
2405 scaling_group_name = scaling_aspect.get("name", "")
2406 # Get monitored VDUs
2407 all_monitored_vdus = set()
2408 for delta in scaling_aspect.get("aspect-delta-details", {}).get(
2409 "deltas", ()
2410 ):
2411 for vdu_delta in delta.get("vdu-delta", ()):
2412 all_monitored_vdus.add(vdu_delta.get("id"))
2413 monitored_vdurs = list(
2414 filter(
2415 lambda vdur: vdur["vdu-id-ref"] in all_monitored_vdus,
2416 vnfr["vdur"],
2417 )
2418 )
2419 if not monitored_vdurs:
2420 self.logger.error(
2421 "Scaling criteria is referring to a vnf-monitoring-param that does not contain a reference to a vdu or vnf metric"
2422 )
2423 continue
2424 for scaling_policy in scaling_aspect.get("scaling-policy", ()):
2425 if scaling_policy["scaling-type"] != "automatic":
2426 continue
2427 threshold_time = scaling_policy.get("threshold-time", "1")
2428 cooldown_time = scaling_policy.get("cooldown-time", "0")
2429 for scaling_criteria in scaling_policy["scaling-criteria"]:
2430 monitoring_param_ref = scaling_criteria.get(
2431 "vnf-monitoring-param-ref"
2432 )
2433 vnf_monitoring_param = all_vnfd_monitoring_params[
2434 monitoring_param_ref
2435 ]
2436 for vdur in monitored_vdurs:
2437 vdu_id = vdur["vdu-id-ref"]
2438 metric_name = vnf_monitoring_param.get("performance-metric")
aguilarde416ea02023-05-08 15:09:37 +00002439 metric_name = f"osm_{metric_name}"
aguilard1ae3c562023-02-16 17:24:35 +00002440 vnf_member_index = vnfr["member-vnf-index-ref"]
2441 scalein_threshold = scaling_criteria.get(
2442 "scale-in-threshold"
2443 )
2444 scaleout_threshold = scaling_criteria.get(
2445 "scale-out-threshold"
2446 )
2447 # Looking for min/max-number-of-instances
2448 instances_min_number = 1
2449 instances_max_number = 1
2450 vdu_profile = df["vdu-profile"]
2451 if vdu_profile:
2452 profile = next(
2453 item for item in vdu_profile if item["id"] == vdu_id
2454 )
2455 instances_min_number = profile.get(
2456 "min-number-of-instances", 1
2457 )
2458 instances_max_number = profile.get(
2459 "max-number-of-instances", 1
2460 )
2461
2462 if scalein_threshold:
2463 uuid = str(uuid4())
2464 name = f"scalein_{uuid}"
2465 operation = scaling_criteria[
2466 "scale-in-relational-operation"
2467 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002468 rel_operator = self.rel_operation_types.get(
2469 operation, "<="
2470 )
aguilard1ae3c562023-02-16 17:24:35 +00002471 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2472 expression = f"(count ({metric_selector}) > {instances_min_number}) and (avg({metric_selector}) {rel_operator} {scalein_threshold})"
2473 labels = {
2474 "ns_id": nsr_id,
2475 "vnf_member_index": vnf_member_index,
2476 "vdu_id": vdu_id,
2477 }
2478 prom_cfg = {
2479 "alert": name,
2480 "expr": expression,
2481 "for": str(threshold_time) + "m",
2482 "labels": labels,
2483 }
2484 action = scaling_policy
2485 action = {
2486 "scaling-group": scaling_group_name,
2487 "cooldown-time": cooldown_time,
2488 }
2489 alert = {
2490 "uuid": uuid,
2491 "name": name,
2492 "metric": metric_name,
2493 "tags": {
2494 "ns_id": nsr_id,
2495 "vnf_member_index": vnf_member_index,
2496 "vdu_id": vdu_id,
2497 },
2498 "alarm_status": "ok",
2499 "action_type": "scale_in",
2500 "action": action,
2501 "prometheus_config": prom_cfg,
2502 }
2503 alerts.append(alert)
2504
2505 if scaleout_threshold:
2506 uuid = str(uuid4())
2507 name = f"scaleout_{uuid}"
2508 operation = scaling_criteria[
2509 "scale-out-relational-operation"
2510 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002511 rel_operator = self.rel_operation_types.get(
2512 operation, "<="
2513 )
aguilard1ae3c562023-02-16 17:24:35 +00002514 metric_selector = f'{metric_name}{{ns_id="{nsr_id}", vnf_member_index="{vnf_member_index}", vdu_id="{vdu_id}"}}'
2515 expression = f"(count ({metric_selector}) < {instances_max_number}) and (avg({metric_selector}) {rel_operator} {scaleout_threshold})"
2516 labels = {
2517 "ns_id": nsr_id,
2518 "vnf_member_index": vnf_member_index,
2519 "vdu_id": vdu_id,
2520 }
2521 prom_cfg = {
2522 "alert": name,
2523 "expr": expression,
2524 "for": str(threshold_time) + "m",
2525 "labels": labels,
2526 }
2527 action = scaling_policy
2528 action = {
2529 "scaling-group": scaling_group_name,
2530 "cooldown-time": cooldown_time,
2531 }
2532 alert = {
2533 "uuid": uuid,
2534 "name": name,
2535 "metric": metric_name,
2536 "tags": {
2537 "ns_id": nsr_id,
2538 "vnf_member_index": vnf_member_index,
2539 "vdu_id": vdu_id,
2540 },
2541 "alarm_status": "ok",
2542 "action_type": "scale_out",
2543 "action": action,
2544 "prometheus_config": prom_cfg,
2545 }
2546 alerts.append(alert)
2547 return alerts
2548
garciadeblas9148fa82023-05-30 12:51:14 +02002549 def _gather_vnfr_alarm_alerts(self, vnfr, vnfd):
2550 alerts = []
2551 nsr_id = vnfr["nsr-id-ref"]
2552 vnf_member_index = vnfr["member-vnf-index-ref"]
2553
2554 # Checking for VNF alarm configuration
2555 for vdur in vnfr["vdur"]:
2556 vdu_id = vdur["vdu-id-ref"]
2557 vdu = next(filter(lambda vdu: vdu["id"] == vdu_id, vnfd["vdu"]))
2558 if "alarm" in vdu:
2559 # Get VDU monitoring params, since alerts are based on them
2560 vdu_monitoring_params = {}
2561 for mp in vdu.get("monitoring-parameter", []):
2562 vdu_monitoring_params[mp.get("id")] = mp
2563 if not vdu_monitoring_params:
2564 self.logger.error(
2565 "VDU alarm refers to a VDU monitoring param, but there are no VDU monitoring params in the VDU"
2566 )
2567 continue
2568 # Get alarms in the VDU
2569 alarm_descriptors = vdu["alarm"]
2570 # Create VDU alarms for each alarm in the VDU
2571 for alarm_descriptor in alarm_descriptors:
2572 # Check that the VDU alarm refers to a proper monitoring param
2573 alarm_monitoring_param = alarm_descriptor.get(
2574 "vnf-monitoring-param-ref", ""
2575 )
2576 vdu_specific_monitoring_param = vdu_monitoring_params.get(
2577 alarm_monitoring_param, {}
2578 )
2579 if not vdu_specific_monitoring_param:
2580 self.logger.error(
2581 "VDU alarm refers to a VDU monitoring param not present in the VDU"
2582 )
2583 continue
2584 metric_name = vdu_specific_monitoring_param.get(
2585 "performance-metric"
2586 )
2587 if not metric_name:
2588 self.logger.error(
2589 "VDU alarm refers to a VDU monitoring param that has no associated performance-metric"
2590 )
2591 continue
2592 # Set params of the alarm to be created in Prometheus
2593 metric_name = f"osm_{metric_name}"
2594 metric_threshold = alarm_descriptor.get("value")
2595 uuid = str(uuid4())
2596 alert_name = f"vdu_alarm_{uuid}"
2597 operation = alarm_descriptor["operation"]
2598 rel_operator = self.rel_operation_types.get(operation, "<=")
2599 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 +00002600 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
garciadeblas9148fa82023-05-30 12:51:14 +02002601 labels = {
2602 "ns_id": nsr_id,
2603 "vnf_member_index": vnf_member_index,
2604 "vdu_id": vdu_id,
aguilardeb076722023-05-31 09:45:00 +00002605 "vdu_name": "{{ $labels.vdu_name }}",
garciadeblas9148fa82023-05-30 12:51:14 +02002606 }
2607 prom_cfg = {
2608 "alert": alert_name,
2609 "expr": expression,
2610 "for": "1m", # default value. Ideally, this should be related to an IM param, but there is not such param
2611 "labels": labels,
2612 }
2613 alarm_action = dict()
2614 for action_type in ["ok", "insufficient-data", "alarm"]:
2615 if (
2616 "actions" in alarm_descriptor
2617 and action_type in alarm_descriptor["actions"]
2618 ):
aguilardeb076722023-05-31 09:45:00 +00002619 alarm_action[action_type] = alarm_descriptor["actions"][
2620 action_type
2621 ]
garciadeblas9148fa82023-05-30 12:51:14 +02002622 alert = {
2623 "uuid": uuid,
2624 "name": alert_name,
2625 "metric": metric_name,
2626 "tags": {
2627 "ns_id": nsr_id,
2628 "vnf_member_index": vnf_member_index,
2629 "vdu_id": vdu_id,
2630 },
2631 "alarm_status": "ok",
2632 "action_type": "vdu_alarm",
2633 "action": alarm_action,
2634 "prometheus_config": prom_cfg,
2635 }
2636 alerts.append(alert)
2637 return alerts
2638
magnussonle9198bb2020-01-21 13:00:51 +01002639 def update_nsrs_with_pla_result(self, params):
2640 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002641 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2642 self.update_db_2(
2643 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2644 )
magnussonle9198bb2020-01-21 13:00:51 +01002645 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002646 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002647
tierno59d22d22018-09-25 18:10:19 +02002648 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002649 """
2650
2651 :param nsr_id: ns instance to deploy
2652 :param nslcmop_id: operation to run
2653 :return:
2654 """
kuused124bfe2019-06-18 12:09:24 +02002655
2656 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002657 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002658 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002659 self.logger.debug(
2660 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2661 )
kuused124bfe2019-06-18 12:09:24 +02002662 return
2663
tierno59d22d22018-09-25 18:10:19 +02002664 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2665 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002666
tierno59d22d22018-09-25 18:10:19 +02002667 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002668
2669 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002670 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002671
2672 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002673 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002674
2675 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002676 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002677 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002678 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002679
Gabriel Cuba411af2e2023-01-06 17:23:22 -05002680 timeout_ns_deploy = self.timeout.ns_deploy
2681
tierno59d22d22018-09-25 18:10:19 +02002682 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002683 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002684 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002685 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002686 exc = None
tiernoe876f672020-02-13 14:34:48 +00002687 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002688 stage = [
2689 "Stage 1/5: preparation of the environment.",
2690 "Waiting for previous operations to terminate.",
2691 "",
2692 ]
tiernoe876f672020-02-13 14:34:48 +00002693 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002694 try:
kuused124bfe2019-06-18 12:09:24 +02002695 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002696 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002697
quilesj7e13aeb2019-10-08 13:34:55 +02002698 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002699 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002700 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002701 db_nsr_update["detailed-status"] = "creating"
2702 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002703 self._write_ns_status(
2704 nsr_id=nsr_id,
2705 ns_state="BUILDING",
2706 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002707 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002708 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002709 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002710 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002711
quilesj7e13aeb2019-10-08 13:34:55 +02002712 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002713 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002714 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002715 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2716 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2717 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2718 )
tierno744303e2020-01-13 16:46:31 +00002719 ns_params = db_nslcmop.get("operationParams")
2720 if ns_params and ns_params.get("timeout_ns_deploy"):
2721 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
quilesj7e13aeb2019-10-08 13:34:55 +02002722
2723 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002724 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002725 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002726 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002727 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002728 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002729 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002730 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002731 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002732 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002733
quilesj7e13aeb2019-10-08 13:34:55 +02002734 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002735 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002736 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002737 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002738
quilesj7e13aeb2019-10-08 13:34:55 +02002739 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002740 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002741
2742 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002743 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002744 if vnfr.get("kdur"):
2745 kdur_list = []
2746 for kdur in vnfr["kdur"]:
2747 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002748 kdur["additionalParams"] = json.loads(
2749 kdur["additionalParams"]
2750 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002751 kdur_list.append(kdur)
2752 vnfr["kdur"] = kdur_list
2753
bravof922c4172020-11-24 21:21:43 -03002754 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2755 vnfd_id = vnfr["vnfd-id"]
2756 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002757 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002758
quilesj7e13aeb2019-10-08 13:34:55 +02002759 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002760 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002761 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002762 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2763 vnfd_id, vnfd_ref
2764 )
tiernoe876f672020-02-13 14:34:48 +00002765 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002766 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002767
quilesj7e13aeb2019-10-08 13:34:55 +02002768 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002769 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002770
2771 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002772 vca_deployed_list = None
2773 if db_nsr["_admin"].get("deployed"):
2774 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2775 if vca_deployed_list is None:
2776 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002777 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002778 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002779 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002780 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002781 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002782 elif isinstance(vca_deployed_list, dict):
2783 # maintain backward compatibility. Change a dict to list at database
2784 vca_deployed_list = list(vca_deployed_list.values())
2785 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002786 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002787
garciadeblas5697b8b2021-03-24 09:17:02 +01002788 if not isinstance(
2789 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2790 ):
tiernoa009e552019-01-30 16:45:44 +00002791 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2792 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002793
tiernobaa51102018-12-14 13:16:18 +00002794 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2795 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2796 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002797 self.db.set_list(
2798 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2799 )
quilesj3655ae02019-12-12 16:08:35 +00002800
2801 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002802 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2803 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002804
tiernob5203912020-08-11 11:20:13 +00002805 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002806 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002807 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002808 await self.deploy_kdus(
2809 logging_text=logging_text,
2810 nsr_id=nsr_id,
2811 nslcmop_id=nslcmop_id,
2812 db_vnfrs=db_vnfrs,
2813 db_vnfds=db_vnfds,
2814 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002815 )
tiernoe876f672020-02-13 14:34:48 +00002816
2817 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002818 # n2vc_redesign STEP 1 Get VCA public ssh-key
2819 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002820 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002821 n2vc_key_list = [n2vc_key]
Luis Vegaa27dc532022-11-11 20:10:49 +00002822 if self.vca_config.public_key:
2823 n2vc_key_list.append(self.vca_config.public_key)
tierno98ad6ea2019-05-30 17:16:28 +00002824
tiernoe876f672020-02-13 14:34:48 +00002825 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002826 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002827 self.instantiate_RO(
2828 logging_text=logging_text,
2829 nsr_id=nsr_id,
2830 nsd=nsd,
2831 db_nsr=db_nsr,
2832 db_nslcmop=db_nslcmop,
2833 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002834 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002835 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002836 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002837 )
tiernod8323042019-08-09 11:32:23 +00002838 )
2839 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002840 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002841
tiernod8323042019-08-09 11:32:23 +00002842 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002843 stage[1] = "Deploying Execution Environments."
2844 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002845
Gabriel Cuba1411a002022-10-07 11:38:23 -05002846 # create namespace and certificate if any helm based EE is present in the NS
2847 if check_helm_ee_in_ns(db_vnfds):
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002848 await self.vca_map["helm-v3"].setup_ns_namespace(
2849 name=nsr_id,
2850 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05002851 # create TLS certificates
2852 await self.vca_map["helm-v3"].create_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002853 secret_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002854 dns_prefix="*",
2855 nsr_id=nsr_id,
2856 usage="server auth",
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05002857 namespace=nsr_id,
Gabriel Cuba1411a002022-10-07 11:38:23 -05002858 )
2859
tiernod8323042019-08-09 11:32:23 +00002860 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002861 for vnf_profile in get_vnf_profiles(nsd):
2862 vnfd_id = vnf_profile["vnfd-id"]
2863 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2864 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002865 db_vnfr = db_vnfrs[member_vnf_index]
2866 base_folder = vnfd["_admin"]["storage"]
2867 vdu_id = None
2868 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002869 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002870 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002871 kdu_index = None
tierno59d22d22018-09-25 18:10:19 +02002872
tierno8a518872018-12-21 13:42:14 +00002873 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002874 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002875 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002876 deploy_params.update(
2877 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2878 )
tierno8a518872018-12-21 13:42:14 +00002879
bravofe5a31bc2021-02-17 19:09:12 -03002880 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002881 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002882 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002883 logging_text=logging_text
2884 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002885 db_nsr=db_nsr,
2886 db_vnfr=db_vnfr,
2887 nslcmop_id=nslcmop_id,
2888 nsr_id=nsr_id,
2889 nsi_id=nsi_id,
2890 vnfd_id=vnfd_id,
2891 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002892 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002893 member_vnf_index=member_vnf_index,
2894 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002895 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002896 vdu_name=vdu_name,
2897 deploy_params=deploy_params,
2898 descriptor_config=descriptor_config,
2899 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002900 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002901 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002902 )
tierno59d22d22018-09-25 18:10:19 +02002903
2904 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002905 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002906 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002907 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002908 vdur = find_in_list(
2909 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2910 )
bravof922c4172020-11-24 21:21:43 -03002911
tierno626e0152019-11-29 14:16:16 +00002912 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002913 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002914 else:
2915 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002916 deploy_params_vdu["OSM"] = get_osm_params(
2917 db_vnfr, vdu_id, vdu_count_index=0
2918 )
endika76ba9232021-06-21 18:55:07 +02002919 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002920
2921 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002922 self.logger.debug(
2923 "Descriptor config > {}".format(descriptor_config)
2924 )
tierno588547c2020-07-01 15:30:20 +00002925 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002926 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002927 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002928 kdu_index = None
bravof922c4172020-11-24 21:21:43 -03002929 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002930 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002931 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002932 logging_text=logging_text
2933 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2934 member_vnf_index, vdu_id, vdu_index
2935 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002936 db_nsr=db_nsr,
2937 db_vnfr=db_vnfr,
2938 nslcmop_id=nslcmop_id,
2939 nsr_id=nsr_id,
2940 nsi_id=nsi_id,
2941 vnfd_id=vnfd_id,
2942 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002943 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002944 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02002945 member_vnf_index=member_vnf_index,
2946 vdu_index=vdu_index,
2947 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002948 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002949 descriptor_config=descriptor_config,
2950 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002951 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002952 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002953 )
bravof922c4172020-11-24 21:21:43 -03002954 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002955 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002956 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002957 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002958 vdu_id = None
2959 vdu_index = 0
2960 vdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01002961 kdu_index, kdur = next(
2962 x
2963 for x in enumerate(db_vnfr["kdur"])
2964 if x[1]["kdu-name"] == kdu_name
garciadeblas5697b8b2021-03-24 09:17:02 +01002965 )
bravof922c4172020-11-24 21:21:43 -03002966 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002967 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002968 deploy_params_kdu.update(
2969 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002970 )
tierno59d22d22018-09-25 18:10:19 +02002971
calvinosanch9f9c6f22019-11-04 13:37:39 +01002972 self._deploy_n2vc(
2973 logging_text=logging_text,
2974 db_nsr=db_nsr,
2975 db_vnfr=db_vnfr,
2976 nslcmop_id=nslcmop_id,
2977 nsr_id=nsr_id,
2978 nsi_id=nsi_id,
2979 vnfd_id=vnfd_id,
2980 vdu_id=vdu_id,
2981 kdu_name=kdu_name,
2982 member_vnf_index=member_vnf_index,
2983 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01002984 kdu_index=kdu_index,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002985 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002986 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002987 descriptor_config=descriptor_config,
2988 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002989 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002990 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002991 )
tierno59d22d22018-09-25 18:10:19 +02002992
k4.rahul74944982023-04-19 17:00:52 +05302993 # Check if each vnf has exporter for metric collection if so update prometheus job records
2994 if "exporters-endpoints" in vnfd.get("df")[0]:
2995 exporter_config = vnfd.get("df")[0].get("exporters-endpoints")
2996 self.logger.debug("exporter config :{}".format(exporter_config))
2997 artifact_path = "{}/{}/{}".format(
2998 base_folder["folder"],
2999 base_folder["pkg-dir"],
3000 "exporter-endpoint",
3001 )
3002 ee_id = None
3003 ee_config_descriptor = exporter_config
3004 vnfr_id = db_vnfr["id"]
3005 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
3006 logging_text,
3007 nsr_id,
3008 vnfr_id,
3009 vdu_id=None,
3010 vdu_index=None,
3011 user=None,
3012 pub_key=None,
3013 )
3014 self.logger.debug("rw_mgmt_ip:{}".format(rw_mgmt_ip))
3015 self.logger.debug("Artifact_path:{}".format(artifact_path))
3016 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
3017 vdu_id_for_prom = None
3018 vdu_index_for_prom = None
3019 for x in get_iterable(db_vnfr, "vdur"):
3020 vdu_id_for_prom = x.get("vdu-id-ref")
3021 vdu_index_for_prom = x.get("count-index")
3022 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
3023 ee_id=ee_id,
3024 artifact_path=artifact_path,
3025 ee_config_descriptor=ee_config_descriptor,
3026 vnfr_id=vnfr_id,
3027 nsr_id=nsr_id,
3028 target_ip=rw_mgmt_ip,
3029 element_type="VDU",
3030 vdu_id=vdu_id_for_prom,
3031 vdu_index=vdu_index_for_prom,
3032 )
3033
3034 self.logger.debug("Prometheus job:{}".format(prometheus_jobs))
3035 if prometheus_jobs:
3036 db_nsr_update["_admin.deployed.prometheus_jobs"] = prometheus_jobs
3037 self.update_db_2(
3038 "nsrs",
3039 nsr_id,
3040 db_nsr_update,
3041 )
3042
3043 for job in prometheus_jobs:
3044 self.db.set_one(
3045 "prometheus_jobs",
3046 {"job_name": job["job_name"]},
3047 job,
3048 upsert=True,
3049 fail_on_empty=False,
3050 )
3051
tierno1b633412019-02-25 16:48:23 +00003052 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00003053 descriptor_config = nsd.get("ns-configuration")
3054 if descriptor_config and descriptor_config.get("juju"):
3055 vnfd_id = None
3056 db_vnfr = None
3057 member_vnf_index = None
3058 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01003059 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01003060 kdu_index = None
tiernod8323042019-08-09 11:32:23 +00003061 vdu_index = 0
3062 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00003063
tiernod8323042019-08-09 11:32:23 +00003064 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01003065 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00003066 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003067 deploy_params.update(
3068 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
3069 )
tiernod8323042019-08-09 11:32:23 +00003070 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02003071 self._deploy_n2vc(
3072 logging_text=logging_text,
3073 db_nsr=db_nsr,
3074 db_vnfr=db_vnfr,
3075 nslcmop_id=nslcmop_id,
3076 nsr_id=nsr_id,
3077 nsi_id=nsi_id,
3078 vnfd_id=vnfd_id,
3079 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01003080 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02003081 member_vnf_index=member_vnf_index,
3082 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01003083 kdu_index=kdu_index,
quilesj7e13aeb2019-10-08 13:34:55 +02003084 vdu_name=vdu_name,
3085 deploy_params=deploy_params,
3086 descriptor_config=descriptor_config,
3087 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00003088 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01003089 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02003090 )
tierno1b633412019-02-25 16:48:23 +00003091
tiernoe876f672020-02-13 14:34:48 +00003092 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00003093
garciadeblas5697b8b2021-03-24 09:17:02 +01003094 except (
3095 ROclient.ROClientException,
3096 DbException,
3097 LcmException,
3098 N2VCException,
3099 ) as e:
3100 self.logger.error(
3101 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
3102 )
tierno59d22d22018-09-25 18:10:19 +02003103 exc = e
3104 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01003105 self.logger.error(
3106 logging_text + "Cancelled Exception while '{}'".format(stage[1])
3107 )
tierno59d22d22018-09-25 18:10:19 +02003108 exc = "Operation was cancelled"
3109 except Exception as e:
3110 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01003111 self.logger.critical(
3112 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
3113 exc_info=True,
3114 )
tierno59d22d22018-09-25 18:10:19 +02003115 finally:
3116 if exc:
tiernoe876f672020-02-13 14:34:48 +00003117 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00003118 try:
tiernoe876f672020-02-13 14:34:48 +00003119 # wait for pending tasks
3120 if tasks_dict_info:
3121 stage[1] = "Waiting for instantiate pending tasks."
3122 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01003123 error_list += await self._wait_for_tasks(
3124 logging_text,
3125 tasks_dict_info,
3126 timeout_ns_deploy,
3127 stage,
3128 nslcmop_id,
3129 nsr_id=nsr_id,
3130 )
tiernoe876f672020-02-13 14:34:48 +00003131 stage[1] = stage[2] = ""
3132 except asyncio.CancelledError:
3133 error_list.append("Cancelled")
3134 # TODO cancel all tasks
3135 except Exception as exc:
3136 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00003137
tiernoe876f672020-02-13 14:34:48 +00003138 # update operation-status
3139 db_nsr_update["operational-status"] = "running"
3140 # let's begin with VCA 'configured' status (later we can change it)
3141 db_nsr_update["config-status"] = "configured"
3142 for task, task_name in tasks_dict_info.items():
3143 if not task.done() or task.cancelled() or task.exception():
3144 if task_name.startswith(self.task_name_deploy_vca):
3145 # A N2VC task is pending
3146 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00003147 else:
tiernoe876f672020-02-13 14:34:48 +00003148 # RO or KDU task is pending
3149 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00003150
tiernoe876f672020-02-13 14:34:48 +00003151 # update status at database
3152 if error_list:
tiernoa2143262020-03-27 16:20:40 +00003153 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00003154 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01003155 error_description_nslcmop = "{} Detail: {}".format(
3156 stage[0], error_detail
3157 )
3158 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
3159 nslcmop_id, stage[0]
3160 )
quilesj3655ae02019-12-12 16:08:35 +00003161
garciadeblas5697b8b2021-03-24 09:17:02 +01003162 db_nsr_update["detailed-status"] = (
3163 error_description_nsr + " Detail: " + error_detail
3164 )
tiernoe876f672020-02-13 14:34:48 +00003165 db_nslcmop_update["detailed-status"] = error_detail
3166 nslcmop_operation_state = "FAILED"
3167 ns_state = "BROKEN"
3168 else:
tiernoa2143262020-03-27 16:20:40 +00003169 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003170 error_description_nsr = error_description_nslcmop = None
3171 ns_state = "READY"
3172 db_nsr_update["detailed-status"] = "Done"
3173 db_nslcmop_update["detailed-status"] = "Done"
3174 nslcmop_operation_state = "COMPLETED"
aguilard1ae3c562023-02-16 17:24:35 +00003175 # Gather auto-healing and auto-scaling alerts for each vnfr
3176 healing_alerts = []
3177 scaling_alerts = []
3178 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
3179 vnfd = next(
3180 (sub for sub in db_vnfds if sub["_id"] == vnfr["vnfd-id"]), None
3181 )
3182 healing_alerts = self._gather_vnfr_healing_alerts(vnfr, vnfd)
3183 for alert in healing_alerts:
3184 self.logger.info(f"Storing healing alert in MongoDB: {alert}")
3185 self.db.create("alerts", alert)
3186
3187 scaling_alerts = self._gather_vnfr_scaling_alerts(vnfr, vnfd)
3188 for alert in scaling_alerts:
3189 self.logger.info(f"Storing scaling alert in MongoDB: {alert}")
3190 self.db.create("alerts", alert)
quilesj4cda56b2019-12-05 10:02:20 +00003191
garciadeblas9148fa82023-05-30 12:51:14 +02003192 alarm_alerts = self._gather_vnfr_alarm_alerts(vnfr, vnfd)
3193 for alert in alarm_alerts:
3194 self.logger.info(f"Storing VNF alarm alert in MongoDB: {alert}")
3195 self.db.create("alerts", alert)
tiernoe876f672020-02-13 14:34:48 +00003196 if db_nsr:
3197 self._write_ns_status(
3198 nsr_id=nsr_id,
3199 ns_state=ns_state,
3200 current_operation="IDLE",
3201 current_operation_id=None,
3202 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003203 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01003204 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00003205 )
tiernoa17d4f42020-04-28 09:59:23 +00003206 self._write_op_status(
3207 op_id=nslcmop_id,
3208 stage="",
3209 error_message=error_description_nslcmop,
3210 operation_state=nslcmop_operation_state,
3211 other_update=db_nslcmop_update,
3212 )
quilesj3655ae02019-12-12 16:08:35 +00003213
tierno59d22d22018-09-25 18:10:19 +02003214 if nslcmop_operation_state:
3215 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003216 await self.msg.aiowrite(
3217 "ns",
3218 "instantiated",
3219 {
3220 "nsr_id": nsr_id,
3221 "nslcmop_id": nslcmop_id,
3222 "operationState": nslcmop_operation_state,
rojassa8165d12023-09-18 11:08:00 -05003223 "startTime": db_nslcmop["startTime"],
3224 "links": db_nslcmop["links"],
3225 "operationParams": {
3226 "nsInstanceId": nsr_id,
3227 "nsdId": db_nsr["nsd-id"],
3228 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003229 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003230 )
tierno59d22d22018-09-25 18:10:19 +02003231 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003232 self.logger.error(
3233 logging_text + "kafka_write notification Exception {}".format(e)
3234 )
tierno59d22d22018-09-25 18:10:19 +02003235
3236 self.logger.debug(logging_text + "Exit")
3237 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3238
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003239 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003240 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003241 cached_vnfds[vnfd_id] = self.db.get_one(
3242 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3243 )
David Garciab4ebcd02021-10-28 02:00:43 +02003244 return cached_vnfds[vnfd_id]
3245
3246 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3247 if vnf_profile_id not in cached_vnfrs:
3248 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3249 "vnfrs",
3250 {
3251 "member-vnf-index-ref": vnf_profile_id,
3252 "nsr-id-ref": nsr_id,
3253 },
3254 )
3255 return cached_vnfrs[vnf_profile_id]
3256
3257 def _is_deployed_vca_in_relation(
3258 self, vca: DeployedVCA, relation: Relation
3259 ) -> bool:
3260 found = False
3261 for endpoint in (relation.provider, relation.requirer):
3262 if endpoint["kdu-resource-profile-id"]:
3263 continue
3264 found = (
3265 vca.vnf_profile_id == endpoint.vnf_profile_id
3266 and vca.vdu_profile_id == endpoint.vdu_profile_id
3267 and vca.execution_environment_ref == endpoint.execution_environment_ref
3268 )
3269 if found:
3270 break
3271 return found
3272
3273 def _update_ee_relation_data_with_implicit_data(
3274 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3275 ):
3276 ee_relation_data = safe_get_ee_relation(
3277 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3278 )
3279 ee_relation_level = EELevel.get_level(ee_relation_data)
3280 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3281 "execution-environment-ref"
3282 ]:
3283 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3284 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003285 project = nsd["_admin"]["projects_read"][0]
3286 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003287 entity_id = (
3288 vnfd_id
3289 if ee_relation_level == EELevel.VNF
3290 else ee_relation_data["vdu-profile-id"]
3291 )
3292 ee = get_juju_ee_ref(db_vnfd, entity_id)
3293 if not ee:
3294 raise Exception(
3295 f"not execution environments found for ee_relation {ee_relation_data}"
3296 )
3297 ee_relation_data["execution-environment-ref"] = ee["id"]
3298 return ee_relation_data
3299
3300 def _get_ns_relations(
3301 self,
3302 nsr_id: str,
3303 nsd: Dict[str, Any],
3304 vca: DeployedVCA,
3305 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003306 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003307 relations = []
3308 db_ns_relations = get_ns_configuration_relation_list(nsd)
3309 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003310 provider_dict = None
3311 requirer_dict = None
3312 if all(key in r for key in ("provider", "requirer")):
3313 provider_dict = r["provider"]
3314 requirer_dict = r["requirer"]
3315 elif "entities" in r:
3316 provider_id = r["entities"][0]["id"]
3317 provider_dict = {
3318 "nsr-id": nsr_id,
3319 "endpoint": r["entities"][0]["endpoint"],
3320 }
3321 if provider_id != nsd["id"]:
3322 provider_dict["vnf-profile-id"] = provider_id
3323 requirer_id = r["entities"][1]["id"]
3324 requirer_dict = {
3325 "nsr-id": nsr_id,
3326 "endpoint": r["entities"][1]["endpoint"],
3327 }
3328 if requirer_id != nsd["id"]:
3329 requirer_dict["vnf-profile-id"] = requirer_id
3330 else:
aticig15db6142022-01-24 12:51:26 +03003331 raise Exception(
3332 "provider/requirer or entities must be included in the relation."
3333 )
David Garciab4ebcd02021-10-28 02:00:43 +02003334 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003335 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003336 )
3337 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003338 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003339 )
3340 provider = EERelation(relation_provider)
3341 requirer = EERelation(relation_requirer)
3342 relation = Relation(r["name"], provider, requirer)
3343 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3344 if vca_in_relation:
3345 relations.append(relation)
3346 return relations
3347
3348 def _get_vnf_relations(
3349 self,
3350 nsr_id: str,
3351 nsd: Dict[str, Any],
3352 vca: DeployedVCA,
3353 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003354 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003355 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003356 if vca.target_element == "ns":
3357 self.logger.debug("VCA is a NS charm, not a VNF.")
3358 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003359 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3360 vnf_profile_id = vnf_profile["id"]
3361 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003362 project = nsd["_admin"]["projects_read"][0]
3363 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003364 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3365 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003366 provider_dict = None
3367 requirer_dict = None
3368 if all(key in r for key in ("provider", "requirer")):
3369 provider_dict = r["provider"]
3370 requirer_dict = r["requirer"]
3371 elif "entities" in r:
3372 provider_id = r["entities"][0]["id"]
3373 provider_dict = {
3374 "nsr-id": nsr_id,
3375 "vnf-profile-id": vnf_profile_id,
3376 "endpoint": r["entities"][0]["endpoint"],
3377 }
3378 if provider_id != vnfd_id:
3379 provider_dict["vdu-profile-id"] = provider_id
3380 requirer_id = r["entities"][1]["id"]
3381 requirer_dict = {
3382 "nsr-id": nsr_id,
3383 "vnf-profile-id": vnf_profile_id,
3384 "endpoint": r["entities"][1]["endpoint"],
3385 }
3386 if requirer_id != vnfd_id:
3387 requirer_dict["vdu-profile-id"] = requirer_id
3388 else:
aticig15db6142022-01-24 12:51:26 +03003389 raise Exception(
3390 "provider/requirer or entities must be included in the relation."
3391 )
David Garciab4ebcd02021-10-28 02:00:43 +02003392 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003393 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003394 )
3395 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003396 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003397 )
3398 provider = EERelation(relation_provider)
3399 requirer = EERelation(relation_requirer)
3400 relation = Relation(r["name"], provider, requirer)
3401 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3402 if vca_in_relation:
3403 relations.append(relation)
3404 return relations
3405
3406 def _get_kdu_resource_data(
3407 self,
3408 ee_relation: EERelation,
3409 db_nsr: Dict[str, Any],
3410 cached_vnfds: Dict[str, Any],
3411 ) -> DeployedK8sResource:
3412 nsd = get_nsd(db_nsr)
3413 vnf_profiles = get_vnf_profiles(nsd)
3414 vnfd_id = find_in_list(
3415 vnf_profiles,
3416 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3417 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003418 project = nsd["_admin"]["projects_read"][0]
3419 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003420 kdu_resource_profile = get_kdu_resource_profile(
3421 db_vnfd, ee_relation.kdu_resource_profile_id
3422 )
3423 kdu_name = kdu_resource_profile["kdu-name"]
3424 deployed_kdu, _ = get_deployed_kdu(
3425 db_nsr.get("_admin", ()).get("deployed", ()),
3426 kdu_name,
3427 ee_relation.vnf_profile_id,
3428 )
3429 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3430 return deployed_kdu
3431
3432 def _get_deployed_component(
3433 self,
3434 ee_relation: EERelation,
3435 db_nsr: Dict[str, Any],
3436 cached_vnfds: Dict[str, Any],
3437 ) -> DeployedComponent:
3438 nsr_id = db_nsr["_id"]
3439 deployed_component = None
3440 ee_level = EELevel.get_level(ee_relation)
3441 if ee_level == EELevel.NS:
3442 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3443 if vca:
3444 deployed_component = DeployedVCA(nsr_id, vca)
3445 elif ee_level == EELevel.VNF:
3446 vca = get_deployed_vca(
3447 db_nsr,
3448 {
3449 "vdu_id": None,
3450 "member-vnf-index": ee_relation.vnf_profile_id,
3451 "ee_descriptor_id": ee_relation.execution_environment_ref,
3452 },
3453 )
3454 if vca:
3455 deployed_component = DeployedVCA(nsr_id, vca)
3456 elif ee_level == EELevel.VDU:
3457 vca = get_deployed_vca(
3458 db_nsr,
3459 {
3460 "vdu_id": ee_relation.vdu_profile_id,
3461 "member-vnf-index": ee_relation.vnf_profile_id,
3462 "ee_descriptor_id": ee_relation.execution_environment_ref,
3463 },
3464 )
3465 if vca:
3466 deployed_component = DeployedVCA(nsr_id, vca)
3467 elif ee_level == EELevel.KDU:
3468 kdu_resource_data = self._get_kdu_resource_data(
3469 ee_relation, db_nsr, cached_vnfds
3470 )
3471 if kdu_resource_data:
3472 deployed_component = DeployedK8sResource(kdu_resource_data)
3473 return deployed_component
3474
3475 async def _add_relation(
3476 self,
3477 relation: Relation,
3478 vca_type: str,
3479 db_nsr: Dict[str, Any],
3480 cached_vnfds: Dict[str, Any],
3481 cached_vnfrs: Dict[str, Any],
3482 ) -> bool:
3483 deployed_provider = self._get_deployed_component(
3484 relation.provider, db_nsr, cached_vnfds
3485 )
3486 deployed_requirer = self._get_deployed_component(
3487 relation.requirer, db_nsr, cached_vnfds
3488 )
3489 if (
3490 deployed_provider
3491 and deployed_requirer
3492 and deployed_provider.config_sw_installed
3493 and deployed_requirer.config_sw_installed
3494 ):
3495 provider_db_vnfr = (
3496 self._get_vnfr(
3497 relation.provider.nsr_id,
3498 relation.provider.vnf_profile_id,
3499 cached_vnfrs,
3500 )
3501 if relation.provider.vnf_profile_id
3502 else None
3503 )
3504 requirer_db_vnfr = (
3505 self._get_vnfr(
3506 relation.requirer.nsr_id,
3507 relation.requirer.vnf_profile_id,
3508 cached_vnfrs,
3509 )
3510 if relation.requirer.vnf_profile_id
3511 else None
3512 )
3513 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3514 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3515 provider_relation_endpoint = RelationEndpoint(
3516 deployed_provider.ee_id,
3517 provider_vca_id,
3518 relation.provider.endpoint,
3519 )
3520 requirer_relation_endpoint = RelationEndpoint(
3521 deployed_requirer.ee_id,
3522 requirer_vca_id,
3523 relation.requirer.endpoint,
3524 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003525 try:
3526 await self.vca_map[vca_type].add_relation(
3527 provider=provider_relation_endpoint,
3528 requirer=requirer_relation_endpoint,
3529 )
3530 except N2VCException as exception:
3531 self.logger.error(exception)
3532 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003533 return True
3534 return False
3535
David Garciac1fe90a2021-03-31 19:12:02 +02003536 async def _add_vca_relations(
3537 self,
3538 logging_text,
3539 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003540 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003541 vca_index: int,
3542 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003543 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003544 # steps:
3545 # 1. find all relations for this VCA
3546 # 2. wait for other peers related
3547 # 3. add relations
3548
3549 try:
quilesj63f90042020-01-17 09:53:55 +00003550 # STEP 1: find all relations for this VCA
3551
3552 # read nsr record
3553 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003554 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003555
3556 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003557 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3558 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003559
David Garciab4ebcd02021-10-28 02:00:43 +02003560 cached_vnfds = {}
3561 cached_vnfrs = {}
3562 relations = []
3563 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3564 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003565
3566 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003567 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003568 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003569 return True
3570
David Garciab4ebcd02021-10-28 02:00:43 +02003571 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003572
3573 # add all relations
3574 start = time()
3575 while True:
3576 # check timeout
3577 now = time()
3578 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003579 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003580 return False
3581
David Garciab4ebcd02021-10-28 02:00:43 +02003582 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003583 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3584
David Garciab4ebcd02021-10-28 02:00:43 +02003585 # for each relation, find the VCA's related
3586 for relation in relations.copy():
3587 added = await self._add_relation(
3588 relation,
3589 vca_type,
3590 db_nsr,
3591 cached_vnfds,
3592 cached_vnfrs,
3593 )
3594 if added:
3595 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003596
David Garciab4ebcd02021-10-28 02:00:43 +02003597 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003598 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003599 break
David Garciab4ebcd02021-10-28 02:00:43 +02003600 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003601
3602 return True
3603
3604 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003605 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003606 return False
3607
garciadeblas5697b8b2021-03-24 09:17:02 +01003608 async def _install_kdu(
3609 self,
3610 nsr_id: str,
3611 nsr_db_path: str,
3612 vnfr_data: dict,
3613 kdu_index: int,
3614 kdud: dict,
3615 vnfd: dict,
3616 k8s_instance_info: dict,
3617 k8params: dict = None,
3618 timeout: int = 600,
3619 vca_id: str = None,
3620 ):
tiernob9018152020-04-16 14:18:24 +00003621 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003622 k8sclustertype = k8s_instance_info["k8scluster-type"]
3623 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003624 db_dict_install = {
3625 "collection": "nsrs",
3626 "filter": {"_id": nsr_id},
3627 "path": nsr_db_path,
3628 }
lloretgalleg7c121132020-07-08 07:53:22 +00003629
romeromonser4554a702021-05-28 12:00:08 +02003630 if k8s_instance_info.get("kdu-deployment-name"):
3631 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3632 else:
3633 kdu_instance = self.k8scluster_map[
3634 k8sclustertype
3635 ].generate_kdu_instance_name(
3636 db_dict=db_dict_install,
3637 kdu_model=k8s_instance_info["kdu-model"],
3638 kdu_name=k8s_instance_info["kdu-name"],
3639 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003640
3641 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003642 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003643 item="nsrs",
3644 _id=nsr_id,
3645 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003646 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003647
3648 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3649 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3650 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3651 # namespace, this first verification could be removed, and the next step would be done for any kind
3652 # of KNF.
3653 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3654 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3655 if k8sclustertype in ("juju", "juju-bundle"):
3656 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3657 # that the user passed a namespace which he wants its KDU to be deployed in)
3658 if (
3659 self.db.count(
3660 table="nsrs",
3661 q_filter={
3662 "_id": nsr_id,
3663 "_admin.projects_write": k8s_instance_info["namespace"],
3664 "_admin.projects_read": k8s_instance_info["namespace"],
3665 },
3666 )
3667 > 0
3668 ):
3669 self.logger.debug(
3670 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3671 )
3672 self.update_db_2(
3673 item="nsrs",
3674 _id=nsr_id,
3675 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3676 )
3677 k8s_instance_info["namespace"] = kdu_instance
3678
David Garciad64e2742021-02-25 20:19:18 +01003679 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003680 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3681 kdu_model=k8s_instance_info["kdu-model"],
3682 atomic=True,
3683 params=k8params,
3684 db_dict=db_dict_install,
3685 timeout=timeout,
3686 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003687 namespace=k8s_instance_info["namespace"],
3688 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003689 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003690 )
lloretgalleg7c121132020-07-08 07:53:22 +00003691
3692 # Obtain services to obtain management service ip
3693 services = await self.k8scluster_map[k8sclustertype].get_services(
3694 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3695 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003696 namespace=k8s_instance_info["namespace"],
3697 )
lloretgalleg7c121132020-07-08 07:53:22 +00003698
3699 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003700 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003701 kdu_config = get_configuration(vnfd, kdud["name"])
3702 if kdu_config:
3703 target_ee_list = kdu_config.get("execution-environment-list", [])
3704 else:
3705 target_ee_list = []
3706
lloretgalleg7c121132020-07-08 07:53:22 +00003707 if services:
tierno7ecbc342020-09-21 14:05:39 +00003708 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003709 mgmt_services = [
3710 service
3711 for service in kdud.get("service", [])
3712 if service.get("mgmt-service")
3713 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003714 for mgmt_service in mgmt_services:
3715 for service in services:
3716 if service["name"].startswith(mgmt_service["name"]):
3717 # Mgmt service found, Obtain service ip
3718 ip = service.get("external_ip", service.get("cluster_ip"))
3719 if isinstance(ip, list) and len(ip) == 1:
3720 ip = ip[0]
3721
garciadeblas5697b8b2021-03-24 09:17:02 +01003722 vnfr_update_dict[
3723 "kdur.{}.ip-address".format(kdu_index)
3724 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003725
3726 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003727 service_external_cp = mgmt_service.get(
3728 "external-connection-point-ref"
3729 )
lloretgalleg7c121132020-07-08 07:53:22 +00003730 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003731 if (
3732 deep_get(vnfd, ("mgmt-interface", "cp"))
3733 == service_external_cp
3734 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003735 vnfr_update_dict["ip-address"] = ip
3736
bravof6ec62b72021-02-25 17:20:35 -03003737 if find_in_list(
3738 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003739 lambda ee: ee.get(
3740 "external-connection-point-ref", ""
3741 )
3742 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003743 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003744 vnfr_update_dict[
3745 "kdur.{}.ip-address".format(kdu_index)
3746 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003747 break
3748 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003749 self.logger.warn(
3750 "Mgmt service name: {} not found".format(
3751 mgmt_service["name"]
3752 )
3753 )
lloretgalleg7c121132020-07-08 07:53:22 +00003754
tierno7ecbc342020-09-21 14:05:39 +00003755 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3756 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003757
bravof9a256db2021-02-22 18:02:07 -03003758 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003759 if (
3760 kdu_config
3761 and kdu_config.get("initial-config-primitive")
3762 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3763 ):
3764 initial_config_primitive_list = kdu_config.get(
3765 "initial-config-primitive"
3766 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003767 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3768
3769 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003770 primitive_params_ = self._map_primitive_params(
3771 initial_config_primitive, {}, {}
3772 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003773
3774 await asyncio.wait_for(
3775 self.k8scluster_map[k8sclustertype].exec_primitive(
3776 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3777 kdu_instance=kdu_instance,
3778 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003779 params=primitive_params_,
3780 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003781 vca_id=vca_id,
3782 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003783 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003784 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003785
tiernob9018152020-04-16 14:18:24 +00003786 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003787 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003788 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003789 self.update_db_2(
3790 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3791 )
3792 self.update_db_2(
3793 "vnfrs",
3794 vnfr_data.get("_id"),
3795 {"kdur.{}.status".format(kdu_index): "ERROR"},
3796 )
tiernob9018152020-04-16 14:18:24 +00003797 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00003798 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00003799 pass
lloretgalleg7c121132020-07-08 07:53:22 +00003800 # reraise original error
3801 raise
3802
3803 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003804
garciadeblas5697b8b2021-03-24 09:17:02 +01003805 async def deploy_kdus(
3806 self,
3807 logging_text,
3808 nsr_id,
3809 nslcmop_id,
3810 db_vnfrs,
3811 db_vnfds,
3812 task_instantiation_info,
3813 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003814 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003815
garciadeblas5697b8b2021-03-24 09:17:02 +01003816 k8scluster_id_2_uuic = {
3817 "helm-chart-v3": {},
3818 "helm-chart": {},
3819 "juju-bundle": {},
3820 }
tierno626e0152019-11-29 14:16:16 +00003821
tierno16f4a4e2020-07-20 09:05:51 +00003822 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003823 nonlocal k8scluster_id_2_uuic
3824 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3825 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3826
tierno16f4a4e2020-07-20 09:05:51 +00003827 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003828 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3829 "k8scluster", cluster_id
3830 )
tierno16f4a4e2020-07-20 09:05:51 +00003831 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003832 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3833 task_name, cluster_id
3834 )
tierno16f4a4e2020-07-20 09:05:51 +00003835 self.logger.debug(logging_text + text)
3836 await asyncio.wait(task_dependency, timeout=3600)
3837
garciadeblas5697b8b2021-03-24 09:17:02 +01003838 db_k8scluster = self.db.get_one(
3839 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3840 )
tierno626e0152019-11-29 14:16:16 +00003841 if not db_k8scluster:
3842 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003843
tierno626e0152019-11-29 14:16:16 +00003844 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3845 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003846 if cluster_type == "helm-chart-v3":
3847 try:
3848 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003849 k8s_credentials = yaml.safe_dump(
3850 db_k8scluster.get("credentials")
3851 )
3852 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3853 k8s_credentials, reuse_cluster_uuid=cluster_id
3854 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003855 db_k8scluster_update = {}
3856 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3857 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003858 db_k8scluster_update[
3859 "_admin.helm-chart-v3.created"
3860 ] = uninstall_sw
3861 db_k8scluster_update[
3862 "_admin.helm-chart-v3.operationalState"
3863 ] = "ENABLED"
3864 self.update_db_2(
3865 "k8sclusters", cluster_id, db_k8scluster_update
3866 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003867 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003868 self.logger.error(
3869 logging_text
3870 + "error initializing helm-v3 cluster: {}".format(str(e))
3871 )
3872 raise LcmException(
3873 "K8s cluster '{}' has not been initialized for '{}'".format(
3874 cluster_id, cluster_type
3875 )
3876 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003877 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003878 raise LcmException(
3879 "K8s cluster '{}' has not been initialized for '{}'".format(
3880 cluster_id, cluster_type
3881 )
3882 )
tierno626e0152019-11-29 14:16:16 +00003883 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3884 return k8s_id
3885
3886 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003887 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003888 try:
tierno626e0152019-11-29 14:16:16 +00003889 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003890 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003891
tierno626e0152019-11-29 14:16:16 +00003892 index = 0
tiernoe876f672020-02-13 14:34:48 +00003893 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003894 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003895
tierno626e0152019-11-29 14:16:16 +00003896 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003897 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003898 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3899 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003900 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003901 vnfd_id = vnfr_data.get("vnfd-id")
3902 vnfd_with_id = find_in_list(
3903 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3904 )
3905 kdud = next(
3906 kdud
3907 for kdud in vnfd_with_id["kdu"]
3908 if kdud["name"] == kdur["kdu-name"]
3909 )
tiernode1584f2020-04-07 09:07:33 +00003910 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003911 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003912 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003913 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003914 # Default version: helm3, if helm-version is v2 assign v2
3915 k8sclustertype = "helm-chart-v3"
3916 self.logger.debug("kdur: {}".format(kdur))
garciadeblas5697b8b2021-03-24 09:17:02 +01003917 if (
3918 kdur.get("helm-version")
3919 and kdur.get("helm-version") == "v2"
3920 ):
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003921 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00003922 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003923 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003924 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003925 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003926 raise LcmException(
3927 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3928 "juju-bundle. Maybe an old NBI version is running".format(
3929 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3930 )
3931 )
quilesjacde94f2020-01-23 10:07:08 +00003932 # check if kdumodel is a file and exists
3933 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003934 vnfd_with_id = find_in_list(
3935 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3936 )
3937 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003938 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003939 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003940 if storage["pkg-dir"]:
3941 filename = "{}/{}/{}s/{}".format(
3942 storage["folder"],
3943 storage["pkg-dir"],
3944 k8sclustertype,
3945 kdumodel,
3946 )
3947 else:
3948 filename = "{}/Scripts/{}s/{}".format(
3949 storage["folder"],
3950 k8sclustertype,
3951 kdumodel,
3952 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003953 if self.fs.file_exists(
3954 filename, mode="file"
3955 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003956 kdumodel = self.fs.path + filename
3957 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003958 raise
garciadeblas5697b8b2021-03-24 09:17:02 +01003959 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00003960 pass
lloretgallegedc5f332020-02-20 11:50:50 +01003961
tiernoe876f672020-02-13 14:34:48 +00003962 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003963 step = "Synchronize repos for k8s cluster '{}'".format(
3964 k8s_cluster_id
3965 )
tierno16f4a4e2020-07-20 09:05:51 +00003966 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003967
lloretgalleg7c121132020-07-08 07:53:22 +00003968 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003969 if (
3970 k8sclustertype == "helm-chart"
3971 and cluster_uuid not in updated_cluster_list
3972 ) or (
3973 k8sclustertype == "helm-chart-v3"
3974 and cluster_uuid not in updated_v3_cluster_list
3975 ):
tiernoe876f672020-02-13 14:34:48 +00003976 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003977 self.k8scluster_map[k8sclustertype].synchronize_repos(
3978 cluster_uuid=cluster_uuid
3979 )
3980 )
tiernoe876f672020-02-13 14:34:48 +00003981 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003982 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003983 unset = {
3984 "_admin.helm_charts_added." + item: None
3985 for item in del_repo_list
3986 }
3987 updated = {
3988 "_admin.helm_charts_added." + item: name
3989 for item, name in added_repo_dict.items()
3990 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003991 updated_cluster_list.append(cluster_uuid)
3992 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003993 unset = {
3994 "_admin.helm_charts_v3_added." + item: None
3995 for item in del_repo_list
3996 }
3997 updated = {
3998 "_admin.helm_charts_v3_added." + item: name
3999 for item, name in added_repo_dict.items()
4000 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00004001 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01004002 self.logger.debug(
4003 logging_text + "repos synchronized on k8s cluster "
4004 "'{}' to_delete: {}, to_add: {}".format(
4005 k8s_cluster_id, del_repo_list, added_repo_dict
4006 )
4007 )
4008 self.db.set_one(
4009 "k8sclusters",
4010 {"_id": k8s_cluster_id},
4011 updated,
4012 unset=unset,
4013 )
lloretgallegedc5f332020-02-20 11:50:50 +01004014
lloretgalleg7c121132020-07-08 07:53:22 +00004015 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01004016 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
4017 vnfr_data["member-vnf-index-ref"],
4018 kdur["kdu-name"],
4019 k8s_cluster_id,
4020 )
4021 k8s_instance_info = {
4022 "kdu-instance": None,
4023 "k8scluster-uuid": cluster_uuid,
4024 "k8scluster-type": k8sclustertype,
4025 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
4026 "kdu-name": kdur["kdu-name"],
4027 "kdu-model": kdumodel,
4028 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02004029 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004030 }
tiernob9018152020-04-16 14:18:24 +00004031 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00004032 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00004033 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01004034 vnfd_with_id = find_in_list(
4035 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
4036 )
tiernoa2143262020-03-27 16:20:40 +00004037 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004038 self._install_kdu(
4039 nsr_id,
4040 db_path,
4041 vnfr_data,
4042 kdu_index,
4043 kdud,
4044 vnfd_with_id,
4045 k8s_instance_info,
4046 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02004047 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01004048 vca_id=vca_id,
4049 )
4050 )
4051 self.lcm_tasks.register(
4052 "ns",
4053 nsr_id,
4054 nslcmop_id,
4055 "instantiate_KDU-{}".format(index),
4056 task,
4057 )
4058 task_instantiation_info[task] = "Deploying KDU {}".format(
4059 kdur["kdu-name"]
4060 )
tiernoe876f672020-02-13 14:34:48 +00004061
tierno626e0152019-11-29 14:16:16 +00004062 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00004063
tiernoe876f672020-02-13 14:34:48 +00004064 except (LcmException, asyncio.CancelledError):
4065 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01004066 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00004067 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
4068 if isinstance(e, (N2VCException, DbException)):
4069 self.logger.error(logging_text + msg)
4070 else:
4071 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00004072 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01004073 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01004074 if db_nsr_update:
4075 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00004076
garciadeblas5697b8b2021-03-24 09:17:02 +01004077 def _deploy_n2vc(
4078 self,
4079 logging_text,
4080 db_nsr,
4081 db_vnfr,
4082 nslcmop_id,
4083 nsr_id,
4084 nsi_id,
4085 vnfd_id,
4086 vdu_id,
4087 kdu_name,
4088 member_vnf_index,
4089 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004090 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004091 vdu_name,
4092 deploy_params,
4093 descriptor_config,
4094 base_folder,
4095 task_instantiation_info,
4096 stage,
4097 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004098 # launch instantiate_N2VC in a asyncio task and register task object
4099 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4100 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004101 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004102
garciadeblas5697b8b2021-03-24 09:17:02 +01004103 self.logger.debug(
4104 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4105 )
aticig9bc63ac2022-07-27 09:32:06 +03004106
4107 charm_name = ""
4108 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004109 if "execution-environment-list" in descriptor_config:
4110 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004111 elif "juju" in descriptor_config:
4112 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004113 if "execution-environment-list" not in descriptor_config:
4114 # charm name is only required for ns charms
4115 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004116 else: # other types as script are not supported
4117 ee_list = []
4118
4119 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004120 self.logger.debug(
4121 logging_text
4122 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4123 ee_item.get("juju"), ee_item.get("helm-chart")
4124 )
4125 )
tiernoa278b842020-07-08 15:33:55 +00004126 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00004127 if ee_item.get("juju"):
garciadeblas5697b8b2021-03-24 09:17:02 +01004128 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03004129 if get_charm_name:
4130 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas5697b8b2021-03-24 09:17:02 +01004131 vca_type = (
4132 "lxc_proxy_charm"
4133 if ee_item["juju"].get("charm") is not None
4134 else "native_charm"
4135 )
4136 if ee_item["juju"].get("cloud") == "k8s":
tierno588547c2020-07-01 15:30:20 +00004137 vca_type = "k8s_proxy_charm"
garciadeblas5697b8b2021-03-24 09:17:02 +01004138 elif ee_item["juju"].get("proxy") is False:
tierno588547c2020-07-01 15:30:20 +00004139 vca_type = "native_charm"
4140 elif ee_item.get("helm-chart"):
garciadeblas5697b8b2021-03-24 09:17:02 +01004141 vca_name = ee_item["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00004142 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
4143 vca_type = "helm"
4144 else:
4145 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00004146 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004147 self.logger.debug(
4148 logging_text + "skipping non juju neither charm configuration"
4149 )
quilesj7e13aeb2019-10-08 13:34:55 +02004150 continue
quilesj3655ae02019-12-12 16:08:35 +00004151
tierno588547c2020-07-01 15:30:20 +00004152 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004153 for vca_index, vca_deployed in enumerate(
4154 db_nsr["_admin"]["deployed"]["VCA"]
4155 ):
tierno588547c2020-07-01 15:30:20 +00004156 if not vca_deployed:
4157 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004158 if (
4159 vca_deployed.get("member-vnf-index") == member_vnf_index
4160 and vca_deployed.get("vdu_id") == vdu_id
4161 and vca_deployed.get("kdu_name") == kdu_name
4162 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4163 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4164 ):
tierno588547c2020-07-01 15:30:20 +00004165 break
4166 else:
4167 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004168 target = (
4169 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4170 )
tiernoa278b842020-07-08 15:33:55 +00004171 if vdu_id:
4172 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4173 elif kdu_name:
4174 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004175 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004176 "target_element": target,
4177 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004178 "member-vnf-index": member_vnf_index,
4179 "vdu_id": vdu_id,
4180 "kdu_name": kdu_name,
4181 "vdu_count_index": vdu_index,
4182 "operational-status": "init", # TODO revise
4183 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004184 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004185 "vnfd_id": vnfd_id,
4186 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004187 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004188 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004189 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004190 }
4191 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004192
tierno588547c2020-07-01 15:30:20 +00004193 # create VCA and configurationStatus in db
4194 db_dict = {
4195 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004196 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004197 }
4198 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004199
tierno588547c2020-07-01 15:30:20 +00004200 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4201
bravof922c4172020-11-24 21:21:43 -03004202 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4203 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4204 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4205
tierno588547c2020-07-01 15:30:20 +00004206 # Launch task
4207 task_n2vc = asyncio.ensure_future(
4208 self.instantiate_N2VC(
4209 logging_text=logging_text,
4210 vca_index=vca_index,
4211 nsi_id=nsi_id,
4212 db_nsr=db_nsr,
4213 db_vnfr=db_vnfr,
4214 vdu_id=vdu_id,
4215 kdu_name=kdu_name,
4216 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004217 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004218 deploy_params=deploy_params,
4219 config_descriptor=descriptor_config,
4220 base_folder=base_folder,
4221 nslcmop_id=nslcmop_id,
4222 stage=stage,
4223 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004224 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004225 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004226 )
quilesj7e13aeb2019-10-08 13:34:55 +02004227 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004228 self.lcm_tasks.register(
4229 "ns",
4230 nsr_id,
4231 nslcmop_id,
4232 "instantiate_N2VC-{}".format(vca_index),
4233 task_n2vc,
4234 )
4235 task_instantiation_info[
4236 task_n2vc
4237 ] = self.task_name_deploy_vca + " {}.{}".format(
4238 member_vnf_index or "", vdu_id or ""
4239 )
tiernobaa51102018-12-14 13:16:18 +00004240
tiernoc9556972019-07-05 15:25:25 +00004241 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02004242 def _create_nslcmop(nsr_id, operation, params):
4243 """
4244 Creates a ns-lcm-opp content to be stored at database.
4245 :param nsr_id: internal id of the instance
4246 :param operation: instantiate, terminate, scale, action, ...
4247 :param params: user parameters for the operation
4248 :return: dictionary following SOL005 format
4249 """
4250 # Raise exception if invalid arguments
4251 if not (nsr_id and operation and params):
4252 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004253 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided"
4254 )
kuuse0ca67472019-05-13 15:59:27 +02004255 now = time()
4256 _id = str(uuid4())
4257 nslcmop = {
4258 "id": _id,
4259 "_id": _id,
4260 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
4261 "operationState": "PROCESSING",
4262 "statusEnteredTime": now,
4263 "nsInstanceId": nsr_id,
4264 "lcmOperationType": operation,
4265 "startTime": now,
4266 "isAutomaticInvocation": False,
4267 "operationParams": params,
4268 "isCancelPending": False,
4269 "links": {
4270 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
4271 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004272 },
kuuse0ca67472019-05-13 15:59:27 +02004273 }
4274 return nslcmop
4275
calvinosanch9f9c6f22019-11-04 13:37:39 +01004276 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004277 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004278 for key, value in params.items():
4279 if str(value).startswith("!!yaml "):
4280 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004281 return params
4282
kuuse8b998e42019-07-30 15:22:16 +02004283 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004284 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004285 primitive_params = {}
4286 params = {
4287 "member_vnf_index": vnf_index,
4288 "primitive": primitive,
4289 "primitive_params": primitive_params,
4290 }
4291 desc_params = {}
4292 return self._map_primitive_params(seq, params, desc_params)
4293
kuuseac3a8882019-10-03 10:48:06 +02004294 # sub-operations
4295
tierno51183952020-04-03 15:48:18 +00004296 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004297 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4298 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004299 # b. Skip sub-operation
4300 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4301 return self.SUBOPERATION_STATUS_SKIP
4302 else:
tierno7c4e24c2020-05-13 08:41:35 +00004303 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004304 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004305 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004306 operationState = "PROCESSING"
4307 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004308 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004309 db_nslcmop, op_index, operationState, detailed_status
4310 )
kuuseac3a8882019-10-03 10:48:06 +02004311 # Return the sub-operation index
4312 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4313 # with arguments extracted from the sub-operation
4314 return op_index
4315
4316 # Find a sub-operation where all keys in a matching dictionary must match
4317 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4318 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004319 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004320 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004321 for i, op in enumerate(op_list):
4322 if all(op.get(k) == match[k] for k in match):
4323 return i
4324 return self.SUBOPERATION_STATUS_NOT_FOUND
4325
4326 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004327 def _update_suboperation_status(
4328 self, db_nslcmop, op_index, operationState, detailed_status
4329 ):
kuuseac3a8882019-10-03 10:48:06 +02004330 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004331 q_filter = {"_id": db_nslcmop["_id"]}
4332 update_dict = {
4333 "_admin.operations.{}.operationState".format(op_index): operationState,
4334 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4335 }
4336 self.db.set_one(
4337 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4338 )
kuuseac3a8882019-10-03 10:48:06 +02004339
4340 # Add sub-operation, return the index of the added sub-operation
4341 # Optionally, set operationState, detailed-status, and operationType
4342 # Status and type are currently set for 'scale' sub-operations:
4343 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4344 # 'detailed-status' : status message
4345 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4346 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004347 def _add_suboperation(
4348 self,
4349 db_nslcmop,
4350 vnf_index,
4351 vdu_id,
4352 vdu_count_index,
4353 vdu_name,
4354 primitive,
4355 mapped_primitive_params,
4356 operationState=None,
4357 detailed_status=None,
4358 operationType=None,
4359 RO_nsr_id=None,
4360 RO_scaling_info=None,
4361 ):
tiernoe876f672020-02-13 14:34:48 +00004362 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004363 return self.SUBOPERATION_STATUS_NOT_FOUND
4364 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004365 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4366 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004367 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004368 new_op = {
4369 "member_vnf_index": vnf_index,
4370 "vdu_id": vdu_id,
4371 "vdu_count_index": vdu_count_index,
4372 "primitive": primitive,
4373 "primitive_params": mapped_primitive_params,
4374 }
kuuseac3a8882019-10-03 10:48:06 +02004375 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004376 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004377 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004378 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004379 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004380 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004381 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004382 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004383 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004384 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004385 if not op_list:
4386 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004387 db_nslcmop_admin.update({"operations": [new_op]})
4388 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004389 else:
4390 # Existing operations, append operation to list
4391 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004392
garciadeblas5697b8b2021-03-24 09:17:02 +01004393 db_nslcmop_update = {"_admin.operations": op_list}
4394 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004395 op_index = len(op_list) - 1
4396 return op_index
4397
4398 # Helper methods for scale() sub-operations
4399
4400 # pre-scale/post-scale:
4401 # Check for 3 different cases:
4402 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4403 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004404 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004405 def _check_or_add_scale_suboperation(
4406 self,
4407 db_nslcmop,
4408 vnf_index,
4409 vnf_config_primitive,
4410 primitive_params,
4411 operationType,
4412 RO_nsr_id=None,
4413 RO_scaling_info=None,
4414 ):
kuuseac3a8882019-10-03 10:48:06 +02004415 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004416 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004417 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004418 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004419 "member_vnf_index": vnf_index,
4420 "RO_nsr_id": RO_nsr_id,
4421 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004422 }
4423 else:
4424 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004425 "member_vnf_index": vnf_index,
4426 "primitive": vnf_config_primitive,
4427 "primitive_params": primitive_params,
4428 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004429 }
4430 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004431 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004432 # a. New sub-operation
4433 # The sub-operation does not exist, add it.
4434 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4435 # The following parameters are set to None for all kind of scaling:
4436 vdu_id = None
4437 vdu_count_index = None
4438 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004439 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004440 vnf_config_primitive = None
4441 primitive_params = None
4442 else:
4443 RO_nsr_id = None
4444 RO_scaling_info = None
4445 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004446 operationState = "PROCESSING"
4447 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004448 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004449 self._add_suboperation(
4450 db_nslcmop,
4451 vnf_index,
4452 vdu_id,
4453 vdu_count_index,
4454 vdu_name,
4455 vnf_config_primitive,
4456 primitive_params,
4457 operationState,
4458 detailed_status,
4459 operationType,
4460 RO_nsr_id,
4461 RO_scaling_info,
4462 )
kuuseac3a8882019-10-03 10:48:06 +02004463 return self.SUBOPERATION_STATUS_NEW
4464 else:
4465 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4466 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004467 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004468
preethika.pdf7d8e02019-12-10 13:10:48 +00004469 # Function to return execution_environment id
4470
4471 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00004472 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00004473 for vca in vca_deployed_list:
4474 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
k4.rahul74944982023-04-19 17:00:52 +05304475 return vca.get("ee_id")
preethika.pdf7d8e02019-12-10 13:10:48 +00004476
David Garciac1fe90a2021-03-31 19:12:02 +02004477 async def destroy_N2VC(
4478 self,
4479 logging_text,
4480 db_nslcmop,
4481 vca_deployed,
4482 config_descriptor,
4483 vca_index,
4484 destroy_ee=True,
4485 exec_primitives=True,
4486 scaling_in=False,
4487 vca_id: str = None,
4488 ):
tiernoe876f672020-02-13 14:34:48 +00004489 """
4490 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4491 :param logging_text:
4492 :param db_nslcmop:
4493 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4494 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4495 :param vca_index: index in the database _admin.deployed.VCA
4496 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004497 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4498 not executed properly
aktas13251562021-02-12 22:19:10 +03004499 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004500 :return: None or exception
4501 """
tiernoe876f672020-02-13 14:34:48 +00004502
tierno588547c2020-07-01 15:30:20 +00004503 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004504 logging_text
4505 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004506 vca_index, vca_deployed, config_descriptor, destroy_ee
4507 )
4508 )
4509
4510 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4511
4512 # execute terminate_primitives
4513 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004514 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004515 config_descriptor.get("terminate-config-primitive"),
4516 vca_deployed.get("ee_descriptor_id"),
4517 )
tierno588547c2020-07-01 15:30:20 +00004518 vdu_id = vca_deployed.get("vdu_id")
4519 vdu_count_index = vca_deployed.get("vdu_count_index")
4520 vdu_name = vca_deployed.get("vdu_name")
4521 vnf_index = vca_deployed.get("member-vnf-index")
4522 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004523 for seq in terminate_primitives:
4524 # For each sequence in list, get primitive and call _ns_execute_primitive()
4525 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004526 vnf_index, seq.get("name")
4527 )
tierno588547c2020-07-01 15:30:20 +00004528 self.logger.debug(logging_text + step)
4529 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004530 primitive = seq.get("name")
4531 mapped_primitive_params = self._get_terminate_primitive_params(
4532 seq, vnf_index
4533 )
tierno588547c2020-07-01 15:30:20 +00004534
4535 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004536 self._add_suboperation(
4537 db_nslcmop,
4538 vnf_index,
4539 vdu_id,
4540 vdu_count_index,
4541 vdu_name,
4542 primitive,
4543 mapped_primitive_params,
4544 )
tierno588547c2020-07-01 15:30:20 +00004545 # Sub-operations: Call _ns_execute_primitive() instead of action()
4546 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004547 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004548 vca_deployed["ee_id"],
4549 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004550 mapped_primitive_params,
4551 vca_type=vca_type,
4552 vca_id=vca_id,
4553 )
tierno588547c2020-07-01 15:30:20 +00004554 except LcmException:
4555 # this happens when VCA is not deployed. In this case it is not needed to terminate
4556 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004557 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004558 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004559 raise LcmException(
4560 "terminate_primitive {} for vnf_member_index={} fails with "
4561 "error {}".format(seq.get("name"), vnf_index, result_detail)
4562 )
tierno588547c2020-07-01 15:30:20 +00004563 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004564 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4565 vca_index
4566 )
4567 self.update_db_2(
4568 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4569 )
tiernoe876f672020-02-13 14:34:48 +00004570
bravof73bac502021-05-11 07:38:47 -04004571 # Delete Prometheus Jobs if any
4572 # This uses NSR_ID, so it will destroy any jobs under this index
4573 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004574
tiernoe876f672020-02-13 14:34:48 +00004575 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004576 await self.vca_map[vca_type].delete_execution_environment(
4577 vca_deployed["ee_id"],
4578 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004579 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004580 vca_id=vca_id,
4581 )
kuuse0ca67472019-05-13 15:59:27 +02004582
David Garciac1fe90a2021-03-31 19:12:02 +02004583 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004584 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004585 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004586 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004587 await self.n2vc.delete_namespace(
4588 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004589 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004590 vca_id=vca_id,
4591 )
tiernof59ad6c2020-04-08 12:50:52 +00004592 except N2VCNotFound: # already deleted. Skip
4593 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004594 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004595
tiernoe876f672020-02-13 14:34:48 +00004596 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004597 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004598 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004599 if not task_is_locked_by_me:
4600 return
4601
tierno59d22d22018-09-25 18:10:19 +02004602 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4603 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004604 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004605 db_nsr = None
4606 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004607 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004608 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004609 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004610 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004611 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004612 tasks_dict_info = {}
4613 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004614 stage = [
4615 "Stage 1/3: Preparing task.",
4616 "Waiting for previous operations to terminate.",
4617 "",
4618 ]
tiernoe876f672020-02-13 14:34:48 +00004619 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004620 try:
kuused124bfe2019-06-18 12:09:24 +02004621 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004622 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004623
tiernoe876f672020-02-13 14:34:48 +00004624 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4625 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4626 operation_params = db_nslcmop.get("operationParams") or {}
4627 if operation_params.get("timeout_ns_terminate"):
4628 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4629 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4630 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4631
4632 db_nsr_update["operational-status"] = "terminating"
4633 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004634 self._write_ns_status(
4635 nsr_id=nsr_id,
4636 ns_state="TERMINATING",
4637 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004638 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004639 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004640 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004641 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004642 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004643 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4644 return
tierno59d22d22018-09-25 18:10:19 +02004645
tiernoe876f672020-02-13 14:34:48 +00004646 stage[1] = "Getting vnf descriptors from db."
4647 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004648 db_vnfrs_dict = {
4649 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4650 }
tiernoe876f672020-02-13 14:34:48 +00004651 db_vnfds_from_id = {}
4652 db_vnfds_from_member_index = {}
4653 # Loop over VNFRs
4654 for vnfr in db_vnfrs_list:
4655 vnfd_id = vnfr["vnfd-id"]
4656 if vnfd_id not in db_vnfds_from_id:
4657 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4658 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004659 db_vnfds_from_member_index[
4660 vnfr["member-vnf-index-ref"]
4661 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004662
tiernoe876f672020-02-13 14:34:48 +00004663 # Destroy individual execution environments when there are terminating primitives.
4664 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004665 # TODO - check before calling _destroy_N2VC
4666 # if not operation_params.get("skip_terminate_primitives"):#
4667 # or not vca.get("needed_terminate"):
4668 stage[0] = "Stage 2/3 execute terminating primitives."
4669 self.logger.debug(logging_text + stage[0])
4670 stage[1] = "Looking execution environment that needs terminate."
4671 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004672
tierno588547c2020-07-01 15:30:20 +00004673 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004674 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004675 vca_member_vnf_index = vca.get("member-vnf-index")
4676 vca_id = self.get_vca_id(
4677 db_vnfrs_dict.get(vca_member_vnf_index)
4678 if vca_member_vnf_index
4679 else None,
4680 db_nsr,
4681 )
tierno588547c2020-07-01 15:30:20 +00004682 if not vca or not vca.get("ee_id"):
4683 continue
4684 if not vca.get("member-vnf-index"):
4685 # ns
4686 config_descriptor = db_nsr.get("ns-configuration")
4687 elif vca.get("vdu_id"):
4688 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004689 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004690 elif vca.get("kdu_name"):
4691 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004692 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004693 else:
bravofe5a31bc2021-02-17 19:09:12 -03004694 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004695 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004696 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004697 exec_terminate_primitives = not operation_params.get(
4698 "skip_terminate_primitives"
4699 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004700 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4701 # pending native charms
garciadeblas5697b8b2021-03-24 09:17:02 +01004702 destroy_ee = (
4703 True if vca_type in ("helm", "helm-v3", "native_charm") else False
4704 )
tierno86e33612020-09-16 14:13:06 +00004705 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4706 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004707 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004708 self.destroy_N2VC(
4709 logging_text,
4710 db_nslcmop,
4711 vca,
4712 config_descriptor,
4713 vca_index,
4714 destroy_ee,
4715 exec_terminate_primitives,
4716 vca_id=vca_id,
4717 )
4718 )
tierno588547c2020-07-01 15:30:20 +00004719 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004720
tierno588547c2020-07-01 15:30:20 +00004721 # wait for pending tasks of terminate primitives
4722 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004723 self.logger.debug(
4724 logging_text
4725 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4726 )
4727 error_list = await self._wait_for_tasks(
4728 logging_text,
4729 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004730 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004731 stage,
4732 nslcmop_id,
4733 )
tierno86e33612020-09-16 14:13:06 +00004734 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004735 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004736 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004737
tiernoe876f672020-02-13 14:34:48 +00004738 # remove All execution environments at once
4739 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004740
tierno49676be2020-04-07 16:34:35 +00004741 if nsr_deployed.get("VCA"):
4742 stage[1] = "Deleting all execution environments."
4743 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02004744 vca_id = self.get_vca_id({}, db_nsr)
4745 task_delete_ee = asyncio.ensure_future(
4746 asyncio.wait_for(
4747 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
Luis Vegaa27dc532022-11-11 20:10:49 +00004748 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004749 )
4750 )
tierno49676be2020-04-07 16:34:35 +00004751 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
4752 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02004753
Gabriel Cuba1411a002022-10-07 11:38:23 -05004754 # Delete Namespace and Certificates if necessary
4755 if check_helm_ee_in_ns(list(db_vnfds_from_member_index.values())):
4756 await self.vca_map["helm-v3"].delete_tls_certificate(
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05004757 namespace=db_nslcmop["nsInstanceId"],
4758 certificate_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05004759 )
Gabriel Cubaeb585dd2023-04-25 16:48:41 -05004760 await self.vca_map["helm-v3"].delete_namespace(
4761 namespace=db_nslcmop["nsInstanceId"],
4762 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05004763
tiernoe876f672020-02-13 14:34:48 +00004764 # Delete from k8scluster
4765 stage[1] = "Deleting KDUs."
4766 self.logger.debug(logging_text + stage[1])
4767 # print(nsr_deployed)
4768 for kdu in get_iterable(nsr_deployed, "K8s"):
4769 if not kdu or not kdu.get("kdu-instance"):
4770 continue
4771 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004772 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004773 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4774 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004775 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004776 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4777 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004778 kdu_instance=kdu_instance,
4779 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004780 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004781 )
4782 )
tiernoe876f672020-02-13 14:34:48 +00004783 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004784 self.logger.error(
4785 logging_text
4786 + "Unknown k8s deployment type {}".format(
4787 kdu.get("k8scluster-type")
4788 )
4789 )
tiernoe876f672020-02-13 14:34:48 +00004790 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004791 tasks_dict_info[
4792 task_delete_kdu_instance
4793 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004794
4795 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004796 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004797 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004798 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004799 self._terminate_ng_ro(
4800 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4801 )
4802 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004803 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004804
tiernoe876f672020-02-13 14:34:48 +00004805 # rest of staff will be done at finally
4806
garciadeblas5697b8b2021-03-24 09:17:02 +01004807 except (
4808 ROclient.ROClientException,
4809 DbException,
4810 LcmException,
4811 N2VCException,
4812 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004813 self.logger.error(logging_text + "Exit Exception {}".format(e))
4814 exc = e
4815 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004816 self.logger.error(
4817 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4818 )
tiernoe876f672020-02-13 14:34:48 +00004819 exc = "Operation was cancelled"
4820 except Exception as e:
4821 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004822 self.logger.critical(
4823 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4824 exc_info=True,
4825 )
tiernoe876f672020-02-13 14:34:48 +00004826 finally:
4827 if exc:
4828 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004829 try:
tiernoe876f672020-02-13 14:34:48 +00004830 # wait for pending tasks
4831 if tasks_dict_info:
4832 stage[1] = "Waiting for terminate pending tasks."
4833 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004834 error_list += await self._wait_for_tasks(
4835 logging_text,
4836 tasks_dict_info,
4837 timeout_ns_terminate,
4838 stage,
4839 nslcmop_id,
4840 )
tiernoe876f672020-02-13 14:34:48 +00004841 stage[1] = stage[2] = ""
4842 except asyncio.CancelledError:
4843 error_list.append("Cancelled")
4844 # TODO cancell all tasks
4845 except Exception as exc:
4846 error_list.append(str(exc))
4847 # update status at database
4848 if error_list:
4849 error_detail = "; ".join(error_list)
4850 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004851 error_description_nslcmop = "{} Detail: {}".format(
4852 stage[0], error_detail
4853 )
4854 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4855 nslcmop_id, stage[0]
4856 )
tierno59d22d22018-09-25 18:10:19 +02004857
tierno59d22d22018-09-25 18:10:19 +02004858 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004859 db_nsr_update["detailed-status"] = (
4860 error_description_nsr + " Detail: " + error_detail
4861 )
tiernoe876f672020-02-13 14:34:48 +00004862 db_nslcmop_update["detailed-status"] = error_detail
4863 nslcmop_operation_state = "FAILED"
4864 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004865 else:
tiernoa2143262020-03-27 16:20:40 +00004866 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004867 error_description_nsr = error_description_nslcmop = None
4868 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004869 db_nsr_update["operational-status"] = "terminated"
4870 db_nsr_update["detailed-status"] = "Done"
4871 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4872 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004873 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004874
tiernoe876f672020-02-13 14:34:48 +00004875 if db_nsr:
4876 self._write_ns_status(
4877 nsr_id=nsr_id,
4878 ns_state=ns_state,
4879 current_operation="IDLE",
4880 current_operation_id=None,
4881 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004882 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004883 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004884 )
tiernoa17d4f42020-04-28 09:59:23 +00004885 self._write_op_status(
4886 op_id=nslcmop_id,
4887 stage="",
4888 error_message=error_description_nslcmop,
4889 operation_state=nslcmop_operation_state,
4890 other_update=db_nslcmop_update,
4891 )
lloretgalleg6d488782020-07-22 10:13:46 +00004892 if ns_state == "NOT_INSTANTIATED":
4893 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004894 self.db.set_list(
4895 "vnfrs",
4896 {"nsr-id-ref": nsr_id},
4897 {"_admin.nsState": "NOT_INSTANTIATED"},
4898 )
lloretgalleg6d488782020-07-22 10:13:46 +00004899 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004900 self.logger.warn(
4901 logging_text
4902 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4903 nsr_id, e
4904 )
4905 )
tiernoa17d4f42020-04-28 09:59:23 +00004906 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004907 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004908 if nslcmop_operation_state:
4909 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004910 await self.msg.aiowrite(
4911 "ns",
4912 "terminated",
4913 {
4914 "nsr_id": nsr_id,
4915 "nslcmop_id": nslcmop_id,
4916 "operationState": nslcmop_operation_state,
4917 "autoremove": autoremove,
4918 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004919 )
tierno59d22d22018-09-25 18:10:19 +02004920 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004921 self.logger.error(
4922 logging_text + "kafka_write notification Exception {}".format(e)
4923 )
aguilard1ae3c562023-02-16 17:24:35 +00004924 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4925 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004926
tierno59d22d22018-09-25 18:10:19 +02004927 self.logger.debug(logging_text + "Exit")
4928 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4929
garciadeblas5697b8b2021-03-24 09:17:02 +01004930 async def _wait_for_tasks(
4931 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4932 ):
tiernoe876f672020-02-13 14:34:48 +00004933 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004934 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004935 error_list = []
4936 pending_tasks = list(created_tasks_info.keys())
4937 num_tasks = len(pending_tasks)
4938 num_done = 0
4939 stage[1] = "{}/{}.".format(num_done, num_tasks)
4940 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004941 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004942 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004943 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004944 done, pending_tasks = await asyncio.wait(
4945 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4946 )
tiernoe876f672020-02-13 14:34:48 +00004947 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004948 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004949 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004950 new_error = created_tasks_info[task] + ": Timeout"
4951 error_detail_list.append(new_error)
4952 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004953 break
4954 for task in done:
4955 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004956 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004957 else:
4958 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004959 if exc:
4960 if isinstance(exc, asyncio.TimeoutError):
4961 exc = "Timeout"
4962 new_error = created_tasks_info[task] + ": {}".format(exc)
4963 error_list.append(created_tasks_info[task])
4964 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004965 if isinstance(
4966 exc,
4967 (
4968 str,
4969 DbException,
4970 N2VCException,
4971 ROclient.ROClientException,
4972 LcmException,
4973 K8sException,
4974 NgRoException,
4975 ),
4976 ):
tierno067e04a2020-03-31 12:53:13 +00004977 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004978 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004979 exc_traceback = "".join(
4980 traceback.format_exception(None, exc, exc.__traceback__)
4981 )
4982 self.logger.error(
4983 logging_text
4984 + created_tasks_info[task]
4985 + " "
4986 + exc_traceback
4987 )
tierno067e04a2020-03-31 12:53:13 +00004988 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004989 self.logger.debug(
4990 logging_text + created_tasks_info[task] + ": Done"
4991 )
tiernoe876f672020-02-13 14:34:48 +00004992 stage[1] = "{}/{}.".format(num_done, num_tasks)
4993 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004994 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004995 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004996 self.update_db_2(
4997 "nsrs",
4998 nsr_id,
4999 {
5000 "errorDescription": "Error at: " + ", ".join(error_list),
5001 "errorDetail": ". ".join(error_detail_list),
5002 },
5003 )
tiernoe876f672020-02-13 14:34:48 +00005004 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00005005 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00005006
tiernoda1ff8c2020-10-22 14:12:46 +00005007 @staticmethod
5008 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00005009 """
5010 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
5011 The default-value is used. If it is between < > it look for a value at instantiation_params
5012 :param primitive_desc: portion of VNFD/NSD that describes primitive
5013 :param params: Params provided by user
5014 :param instantiation_params: Instantiation params provided by user
5015 :return: a dictionary with the calculated params
5016 """
5017 calculated_params = {}
5018 for parameter in primitive_desc.get("parameter", ()):
5019 param_name = parameter["name"]
5020 if param_name in params:
5021 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00005022 elif "default-value" in parameter or "value" in parameter:
5023 if "value" in parameter:
5024 calculated_params[param_name] = parameter["value"]
5025 else:
5026 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005027 if (
5028 isinstance(calculated_params[param_name], str)
5029 and calculated_params[param_name].startswith("<")
5030 and calculated_params[param_name].endswith(">")
5031 ):
tierno98ad6ea2019-05-30 17:16:28 +00005032 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01005033 calculated_params[param_name] = instantiation_params[
5034 calculated_params[param_name][1:-1]
5035 ]
tiernoda964822019-01-14 15:53:47 +00005036 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005037 raise LcmException(
5038 "Parameter {} needed to execute primitive {} not provided".format(
5039 calculated_params[param_name], primitive_desc["name"]
5040 )
5041 )
tiernoda964822019-01-14 15:53:47 +00005042 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005043 raise LcmException(
5044 "Parameter {} needed to execute primitive {} not provided".format(
5045 param_name, primitive_desc["name"]
5046 )
5047 )
tierno59d22d22018-09-25 18:10:19 +02005048
tiernoda964822019-01-14 15:53:47 +00005049 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01005050 calculated_params[param_name] = yaml.safe_dump(
5051 calculated_params[param_name], default_flow_style=True, width=256
5052 )
5053 elif isinstance(calculated_params[param_name], str) and calculated_params[
5054 param_name
5055 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00005056 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00005057 if parameter.get("data-type") == "INTEGER":
5058 try:
5059 calculated_params[param_name] = int(calculated_params[param_name])
5060 except ValueError: # error converting string to int
5061 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01005062 "Parameter {} of primitive {} must be integer".format(
5063 param_name, primitive_desc["name"]
5064 )
5065 )
tiernofa40e692020-10-14 14:59:36 +00005066 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01005067 calculated_params[param_name] = not (
5068 (str(calculated_params[param_name])).lower() == "false"
5069 )
tiernoc3f2a822019-11-05 13:45:04 +00005070
5071 # add always ns_config_info if primitive name is config
5072 if primitive_desc["name"] == "config":
5073 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01005074 calculated_params["ns_config_info"] = instantiation_params[
5075 "ns_config_info"
5076 ]
tiernoda964822019-01-14 15:53:47 +00005077 return calculated_params
5078
garciadeblas5697b8b2021-03-24 09:17:02 +01005079 def _look_for_deployed_vca(
5080 self,
5081 deployed_vca,
5082 member_vnf_index,
5083 vdu_id,
5084 vdu_count_index,
5085 kdu_name=None,
5086 ee_descriptor_id=None,
5087 ):
tiernoe876f672020-02-13 14:34:48 +00005088 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
5089 for vca in deployed_vca:
5090 if not vca:
5091 continue
5092 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
5093 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01005094 if (
5095 vdu_count_index is not None
5096 and vdu_count_index != vca["vdu_count_index"]
5097 ):
tiernoe876f672020-02-13 14:34:48 +00005098 continue
5099 if kdu_name and kdu_name != vca["kdu_name"]:
5100 continue
tiernoa278b842020-07-08 15:33:55 +00005101 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
5102 continue
tiernoe876f672020-02-13 14:34:48 +00005103 break
5104 else:
5105 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01005106 raise LcmException(
5107 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
5108 " is not deployed".format(
5109 member_vnf_index,
5110 vdu_id,
5111 vdu_count_index,
5112 kdu_name,
5113 ee_descriptor_id,
5114 )
5115 )
tiernoe876f672020-02-13 14:34:48 +00005116 # get ee_id
5117 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01005118 vca_type = vca.get(
5119 "type", "lxc_proxy_charm"
5120 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00005121 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005122 raise LcmException(
5123 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
5124 "execution environment".format(
5125 member_vnf_index, vdu_id, kdu_name, vdu_count_index
5126 )
5127 )
tierno588547c2020-07-01 15:30:20 +00005128 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00005129
David Garciac1fe90a2021-03-31 19:12:02 +02005130 async def _ns_execute_primitive(
5131 self,
5132 ee_id,
5133 primitive,
5134 primitive_params,
5135 retries=0,
5136 retries_interval=30,
5137 timeout=None,
5138 vca_type=None,
5139 db_dict=None,
5140 vca_id: str = None,
5141 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005142 try:
tierno98ad6ea2019-05-30 17:16:28 +00005143 if primitive == "config":
5144 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005145
tierno588547c2020-07-01 15:30:20 +00005146 vca_type = vca_type or "lxc_proxy_charm"
5147
quilesj7e13aeb2019-10-08 13:34:55 +02005148 while retries >= 0:
5149 try:
tierno067e04a2020-03-31 12:53:13 +00005150 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005151 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005152 ee_id=ee_id,
5153 primitive_name=primitive,
5154 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005155 progress_timeout=self.timeout.progress_primitive,
5156 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005157 db_dict=db_dict,
5158 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005159 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005160 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005161 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005162 )
quilesj7e13aeb2019-10-08 13:34:55 +02005163 # execution was OK
5164 break
tierno067e04a2020-03-31 12:53:13 +00005165 except asyncio.CancelledError:
5166 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005167 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005168 retries -= 1
5169 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005170 self.logger.debug(
5171 "Error executing action {} on {} -> {}".format(
5172 primitive, ee_id, e
5173 )
5174 )
quilesj7e13aeb2019-10-08 13:34:55 +02005175 # wait and retry
Gabriel Cubae7898982023-05-11 01:57:21 -05005176 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005177 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005178 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005179 e = N2VCException(
5180 message="Timed out waiting for action to complete"
5181 )
5182 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005183
garciadeblas5697b8b2021-03-24 09:17:02 +01005184 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005185
tierno067e04a2020-03-31 12:53:13 +00005186 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005187 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005188 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005189 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005190
ksaikiranr3fde2c72021-03-15 10:39:06 +05305191 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5192 """
5193 Updating the vca_status with latest juju information in nsrs record
5194 :param: nsr_id: Id of the nsr
5195 :param: nslcmop_id: Id of the nslcmop
5196 :return: None
5197 """
5198
5199 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5200 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005201 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005202 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005203 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5204 cluster_uuid, kdu_instance, cluster_type = (
5205 k8s["k8scluster-uuid"],
5206 k8s["kdu-instance"],
5207 k8s["k8scluster-type"],
5208 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005209 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005210 cluster_uuid=cluster_uuid,
5211 kdu_instance=kdu_instance,
5212 filter={"_id": nsr_id},
5213 vca_id=vca_id,
5214 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005215 )
ksaikiranr656b6dd2021-02-19 10:25:18 +05305216 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005217 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305218 table, filter = "nsrs", {"_id": nsr_id}
5219 path = "_admin.deployed.VCA.{}.".format(vca_index)
5220 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305221
5222 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5223 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5224
tierno59d22d22018-09-25 18:10:19 +02005225 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005226 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005227 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005228 if not task_is_locked_by_me:
5229 return
5230
tierno59d22d22018-09-25 18:10:19 +02005231 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5232 self.logger.debug(logging_text + "Enter")
5233 # get all needed from database
5234 db_nsr = None
5235 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005236 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005237 db_nslcmop_update = {}
5238 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005239 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005240 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005241 step = ""
tierno59d22d22018-09-25 18:10:19 +02005242 try:
kuused124bfe2019-06-18 12:09:24 +02005243 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005244 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005245 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005246
quilesj4cda56b2019-12-05 10:02:20 +00005247 self._write_ns_status(
5248 nsr_id=nsr_id,
5249 ns_state=None,
5250 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005251 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005252 )
5253
tierno59d22d22018-09-25 18:10:19 +02005254 step = "Getting information from database"
5255 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5256 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005257 if db_nslcmop["operationParams"].get("primitive_params"):
5258 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5259 db_nslcmop["operationParams"]["primitive_params"]
5260 )
tiernoda964822019-01-14 15:53:47 +00005261
tiernoe4f7e6c2018-11-27 14:55:30 +00005262 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005263 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005264 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005265 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005266 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005267 primitive = db_nslcmop["operationParams"]["primitive"]
5268 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005269 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005270 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005271 )
tierno59d22d22018-09-25 18:10:19 +02005272
tierno1b633412019-02-25 16:48:23 +00005273 if vnf_index:
5274 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005275 db_vnfr = self.db.get_one(
5276 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5277 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005278 if db_vnfr.get("kdur"):
5279 kdur_list = []
5280 for kdur in db_vnfr["kdur"]:
5281 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005282 kdur["additionalParams"] = json.loads(
5283 kdur["additionalParams"]
5284 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005285 kdur_list.append(kdur)
5286 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005287 step = "Getting vnfd from database"
5288 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005289
5290 # Sync filesystem before running a primitive
5291 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005292 else:
tierno067e04a2020-03-31 12:53:13 +00005293 step = "Getting nsd from database"
5294 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005295
David Garciac1fe90a2021-03-31 19:12:02 +02005296 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005297 # for backward compatibility
5298 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5299 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5300 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5301 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5302
tiernoda964822019-01-14 15:53:47 +00005303 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005304 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005305 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005306 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005307 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005308 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005309 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005310 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005311 else:
tiernoa278b842020-07-08 15:33:55 +00005312 descriptor_configuration = db_nsd.get("ns-configuration")
5313
garciadeblas5697b8b2021-03-24 09:17:02 +01005314 if descriptor_configuration and descriptor_configuration.get(
5315 "config-primitive"
5316 ):
tiernoa278b842020-07-08 15:33:55 +00005317 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005318 if config_primitive["name"] == primitive:
5319 config_primitive_desc = config_primitive
5320 break
tiernoda964822019-01-14 15:53:47 +00005321
garciadeblas6bed6b32020-07-20 11:05:42 +00005322 if not config_primitive_desc:
5323 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005324 raise LcmException(
5325 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5326 primitive
5327 )
5328 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005329 primitive_name = primitive
5330 ee_descriptor_id = None
5331 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005332 primitive_name = config_primitive_desc.get(
5333 "execution-environment-primitive", primitive
5334 )
5335 ee_descriptor_id = config_primitive_desc.get(
5336 "execution-environment-ref"
5337 )
tierno1b633412019-02-25 16:48:23 +00005338
tierno1b633412019-02-25 16:48:23 +00005339 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005340 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005341 vdur = next(
5342 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5343 )
bravof922c4172020-11-24 21:21:43 -03005344 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005345 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005346 kdur = next(
5347 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5348 )
bravof922c4172020-11-24 21:21:43 -03005349 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005350 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005351 desc_params = parse_yaml_strings(
5352 db_vnfr.get("additionalParamsForVnf")
5353 )
tierno1b633412019-02-25 16:48:23 +00005354 else:
bravof922c4172020-11-24 21:21:43 -03005355 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005356 if kdu_name and get_configuration(db_vnfd, kdu_name):
5357 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005358 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005359 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005360 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005361 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005362 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005363 kdu = find_in_list(
5364 nsr_deployed["K8s"],
5365 lambda kdu: kdu_name == kdu["kdu-name"]
5366 and kdu["member-vnf-index"] == vnf_index,
5367 )
5368 kdu_action = (
5369 True
5370 if primitive_name in actions
5371 and kdu["k8scluster-type"] not in ("helm-chart", "helm-chart-v3")
5372 else False
5373 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005374
tiernoda964822019-01-14 15:53:47 +00005375 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005376 if kdu_name and (
5377 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5378 ):
tierno067e04a2020-03-31 12:53:13 +00005379 # kdur and desc_params already set from before
5380 if primitive_params:
5381 desc_params.update(primitive_params)
5382 # TODO Check if we will need something at vnf level
5383 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005384 if (
5385 kdu_name == kdu["kdu-name"]
5386 and kdu["member-vnf-index"] == vnf_index
5387 ):
tierno067e04a2020-03-31 12:53:13 +00005388 break
5389 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005390 raise LcmException(
5391 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5392 )
quilesj7e13aeb2019-10-08 13:34:55 +02005393
tierno067e04a2020-03-31 12:53:13 +00005394 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005395 msg = "unknown k8scluster-type '{}'".format(
5396 kdu.get("k8scluster-type")
5397 )
tierno067e04a2020-03-31 12:53:13 +00005398 raise LcmException(msg)
5399
garciadeblas5697b8b2021-03-24 09:17:02 +01005400 db_dict = {
5401 "collection": "nsrs",
5402 "filter": {"_id": nsr_id},
5403 "path": "_admin.deployed.K8s.{}".format(index),
5404 }
5405 self.logger.debug(
5406 logging_text
5407 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5408 )
tiernoa278b842020-07-08 15:33:55 +00005409 step = "Executing kdu {}".format(primitive_name)
5410 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00005411 if desc_params.get("kdu_model"):
5412 kdu_model = desc_params.get("kdu_model")
5413 del desc_params["kdu_model"]
5414 else:
5415 kdu_model = kdu.get("kdu-model")
Gabriel Cuba0ceae9a2023-04-26 10:50:30 -05005416 if kdu_model.count("/") < 2: # helm chart is not embedded
5417 parts = kdu_model.split(sep=":")
5418 if len(parts) == 2:
5419 kdu_model = parts[0]
limondd8b0a62022-10-28 10:39:16 +02005420 if desc_params.get("kdu_atomic_upgrade"):
garciadeblasfb1e25f2022-11-18 14:36:22 +01005421 atomic_upgrade = desc_params.get(
5422 "kdu_atomic_upgrade"
5423 ).lower() in ("yes", "true", "1")
limondd8b0a62022-10-28 10:39:16 +02005424 del desc_params["kdu_atomic_upgrade"]
5425 else:
5426 atomic_upgrade = True
tierno067e04a2020-03-31 12:53:13 +00005427
5428 detailed_status = await asyncio.wait_for(
5429 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5430 cluster_uuid=kdu.get("k8scluster-uuid"),
5431 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005432 atomic=atomic_upgrade,
garciadeblas5697b8b2021-03-24 09:17:02 +01005433 kdu_model=kdu_model,
5434 params=desc_params,
5435 db_dict=db_dict,
5436 timeout=timeout_ns_action,
5437 ),
5438 timeout=timeout_ns_action + 10,
5439 )
5440 self.logger.debug(
5441 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5442 )
tiernoa278b842020-07-08 15:33:55 +00005443 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005444 detailed_status = await asyncio.wait_for(
5445 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5446 cluster_uuid=kdu.get("k8scluster-uuid"),
5447 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005448 db_dict=db_dict,
5449 ),
5450 timeout=timeout_ns_action,
5451 )
tiernoa278b842020-07-08 15:33:55 +00005452 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005453 detailed_status = await asyncio.wait_for(
5454 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5455 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005456 kdu_instance=kdu.get("kdu-instance"),
5457 vca_id=vca_id,
5458 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005459 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005460 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005461 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005462 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5463 kdu["kdu-name"], nsr_id
5464 )
5465 params = self._map_primitive_params(
5466 config_primitive_desc, primitive_params, desc_params
5467 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005468
5469 detailed_status = await asyncio.wait_for(
5470 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5471 cluster_uuid=kdu.get("k8scluster-uuid"),
5472 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005473 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005474 params=params,
5475 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005476 timeout=timeout_ns_action,
5477 vca_id=vca_id,
5478 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005479 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005480 )
tierno067e04a2020-03-31 12:53:13 +00005481
5482 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005483 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005484 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005485 detailed_status = ""
5486 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005487 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005488 ee_id, vca_type = self._look_for_deployed_vca(
5489 nsr_deployed["VCA"],
5490 member_vnf_index=vnf_index,
5491 vdu_id=vdu_id,
5492 vdu_count_index=vdu_count_index,
5493 ee_descriptor_id=ee_descriptor_id,
5494 )
5495 for vca_index, vca_deployed in enumerate(
5496 db_nsr["_admin"]["deployed"]["VCA"]
5497 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305498 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005499 db_dict = {
5500 "collection": "nsrs",
5501 "filter": {"_id": nsr_id},
5502 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5503 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305504 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005505 (
5506 nslcmop_operation_state,
5507 detailed_status,
5508 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005509 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005510 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005511 primitive_params=self._map_primitive_params(
5512 config_primitive_desc, primitive_params, desc_params
5513 ),
tierno588547c2020-07-01 15:30:20 +00005514 timeout=timeout_ns_action,
5515 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005516 db_dict=db_dict,
5517 vca_id=vca_id,
5518 )
tierno067e04a2020-03-31 12:53:13 +00005519
5520 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005521 error_description_nslcmop = (
5522 detailed_status if nslcmop_operation_state == "FAILED" else ""
5523 )
5524 self.logger.debug(
5525 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005526 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005527 nslcmop_operation_state, detailed_status
5528 )
5529 )
tierno59d22d22018-09-25 18:10:19 +02005530 return # database update is called inside finally
5531
tiernof59ad6c2020-04-08 12:50:52 +00005532 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005533 self.logger.error(logging_text + "Exit Exception {}".format(e))
5534 exc = e
5535 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005536 self.logger.error(
5537 logging_text + "Cancelled Exception while '{}'".format(step)
5538 )
tierno59d22d22018-09-25 18:10:19 +02005539 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005540 except asyncio.TimeoutError:
5541 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5542 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005543 except Exception as e:
5544 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005545 self.logger.critical(
5546 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5547 exc_info=True,
5548 )
tierno59d22d22018-09-25 18:10:19 +02005549 finally:
tierno067e04a2020-03-31 12:53:13 +00005550 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005551 db_nslcmop_update[
5552 "detailed-status"
5553 ] = (
5554 detailed_status
5555 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005556 nslcmop_operation_state = "FAILED"
5557 if db_nsr:
5558 self._write_ns_status(
5559 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005560 ns_state=db_nsr[
5561 "nsState"
5562 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005563 current_operation="IDLE",
5564 current_operation_id=None,
5565 # error_description=error_description_nsr,
5566 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005567 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005568 )
5569
garciadeblas5697b8b2021-03-24 09:17:02 +01005570 self._write_op_status(
5571 op_id=nslcmop_id,
5572 stage="",
5573 error_message=error_description_nslcmop,
5574 operation_state=nslcmop_operation_state,
5575 other_update=db_nslcmop_update,
5576 )
tierno067e04a2020-03-31 12:53:13 +00005577
tierno59d22d22018-09-25 18:10:19 +02005578 if nslcmop_operation_state:
5579 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005580 await self.msg.aiowrite(
5581 "ns",
5582 "actioned",
5583 {
5584 "nsr_id": nsr_id,
5585 "nslcmop_id": nslcmop_id,
5586 "operationState": nslcmop_operation_state,
5587 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005588 )
tierno59d22d22018-09-25 18:10:19 +02005589 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005590 self.logger.error(
5591 logging_text + "kafka_write notification Exception {}".format(e)
5592 )
tierno59d22d22018-09-25 18:10:19 +02005593 self.logger.debug(logging_text + "Exit")
5594 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005595 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005596
elumalaica7ece02022-04-12 12:47:32 +05305597 async def terminate_vdus(
5598 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5599 ):
5600 """This method terminates VDUs
5601
5602 Args:
5603 db_vnfr: VNF instance record
5604 member_vnf_index: VNF index to identify the VDUs to be removed
5605 db_nsr: NS instance record
5606 update_db_nslcmops: Nslcmop update record
5607 """
5608 vca_scaling_info = []
5609 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5610 scaling_info["scaling_direction"] = "IN"
5611 scaling_info["vdu-delete"] = {}
5612 scaling_info["kdu-delete"] = {}
5613 db_vdur = db_vnfr.get("vdur")
5614 vdur_list = copy(db_vdur)
5615 count_index = 0
5616 for index, vdu in enumerate(vdur_list):
5617 vca_scaling_info.append(
5618 {
5619 "osm_vdu_id": vdu["vdu-id-ref"],
5620 "member-vnf-index": member_vnf_index,
5621 "type": "delete",
5622 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005623 }
5624 )
elumalaica7ece02022-04-12 12:47:32 +05305625 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5626 scaling_info["vdu"].append(
5627 {
5628 "name": vdu.get("name") or vdu.get("vdu-name"),
5629 "vdu_id": vdu["vdu-id-ref"],
5630 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005631 }
5632 )
elumalaica7ece02022-04-12 12:47:32 +05305633 for interface in vdu["interfaces"]:
5634 scaling_info["vdu"][index]["interface"].append(
5635 {
5636 "name": interface["name"],
5637 "ip_address": interface["ip-address"],
5638 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005639 }
5640 )
elumalaica7ece02022-04-12 12:47:32 +05305641 self.logger.info("NS update scaling info{}".format(scaling_info))
5642 stage[2] = "Terminating VDUs"
5643 if scaling_info.get("vdu-delete"):
5644 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005645 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305646 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005647 logging_text,
5648 db_nsr,
5649 update_db_nslcmops,
5650 db_vnfr,
5651 scaling_info,
5652 stage,
elumalaica7ece02022-04-12 12:47:32 +05305653 )
5654
preethika.p28b0bf82022-09-23 07:36:28 +00005655 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305656 """This method is to Remove VNF instances from NS.
5657
5658 Args:
5659 nsr_id: NS instance id
5660 nslcmop_id: nslcmop id of update
5661 vnf_instance_id: id of the VNF instance to be removed
5662
5663 Returns:
5664 result: (str, str) COMPLETED/FAILED, details
5665 """
5666 try:
5667 db_nsr_update = {}
5668 logging_text = "Task ns={} update ".format(nsr_id)
5669 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5670 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5671 if check_vnfr_count > 1:
5672 stage = ["", "", ""]
5673 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005674 self.logger.debug(
5675 step + " after having waited for previous tasks to be completed"
5676 )
elumalaica7ece02022-04-12 12:47:32 +05305677 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5678 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5679 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5680 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5681 """ db_vnfr = self.db.get_one(
5682 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5683
5684 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005685 await self.terminate_vdus(
5686 db_vnfr,
5687 member_vnf_index,
5688 db_nsr,
5689 update_db_nslcmops,
5690 stage,
5691 logging_text,
5692 )
elumalaica7ece02022-04-12 12:47:32 +05305693
5694 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5695 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005696 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5697 "constituent-vnfr-ref"
5698 )
elumalaica7ece02022-04-12 12:47:32 +05305699 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5700 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5701 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5702 return "COMPLETED", "Done"
5703 else:
5704 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005705 raise LcmException(
5706 "{} Cannot terminate the last VNF in this NS.".format(
5707 vnf_instance_id
5708 )
5709 )
elumalaica7ece02022-04-12 12:47:32 +05305710 except (LcmException, asyncio.CancelledError):
5711 raise
5712 except Exception as e:
5713 self.logger.debug("Error removing VNF {}".format(e))
5714 return "FAILED", "Error removing VNF {}".format(e)
5715
elumalaib9e357c2022-04-27 09:58:38 +05305716 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005717 self,
5718 nsr_id,
5719 nslcmop_id,
5720 db_vnfd,
5721 db_vnfr,
5722 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305723 ):
5724 """This method updates and redeploys VNF instances
5725
5726 Args:
5727 nsr_id: NS instance id
5728 nslcmop_id: nslcmop id
5729 db_vnfd: VNF descriptor
5730 db_vnfr: VNF instance record
5731 db_nsr: NS instance record
5732
5733 Returns:
5734 result: (str, str) COMPLETED/FAILED, details
5735 """
5736 try:
5737 count_index = 0
5738 stage = ["", "", ""]
5739 logging_text = "Task ns={} update ".format(nsr_id)
5740 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5741 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5742
5743 # Terminate old VNF resources
5744 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005745 await self.terminate_vdus(
5746 db_vnfr,
5747 member_vnf_index,
5748 db_nsr,
5749 update_db_nslcmops,
5750 stage,
5751 logging_text,
5752 )
elumalaib9e357c2022-04-27 09:58:38 +05305753
5754 # old_vnfd_id = db_vnfr["vnfd-id"]
5755 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5756 new_db_vnfd = db_vnfd
5757 # new_vnfd_ref = new_db_vnfd["id"]
5758 # new_vnfd_id = vnfd_id
5759
5760 # Create VDUR
5761 new_vnfr_cp = []
5762 for cp in new_db_vnfd.get("ext-cpd", ()):
5763 vnf_cp = {
5764 "name": cp.get("id"),
5765 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5766 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5767 "id": cp.get("id"),
5768 }
5769 new_vnfr_cp.append(vnf_cp)
5770 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5771 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5772 # 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 +00005773 new_vnfr_update = {
5774 "revision": latest_vnfd_revision,
5775 "connection-point": new_vnfr_cp,
5776 "vdur": new_vdur,
5777 "ip-address": "",
5778 }
elumalaib9e357c2022-04-27 09:58:38 +05305779 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5780 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005781 "vnfrs",
5782 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305783 )
5784
5785 # Instantiate new VNF resources
5786 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5787 vca_scaling_info = []
5788 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5789 scaling_info["scaling_direction"] = "OUT"
5790 scaling_info["vdu-create"] = {}
5791 scaling_info["kdu-create"] = {}
5792 vdud_instantiate_list = db_vnfd["vdu"]
5793 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005794 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305795 if cloud_init_text:
5796 additional_params = (
5797 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5798 or {}
5799 )
5800 cloud_init_list = []
5801 if cloud_init_text:
5802 # TODO Information of its own ip is not available because db_vnfr is not updated.
5803 additional_params["OSM"] = get_osm_params(
5804 updated_db_vnfr, vdud["id"], 1
5805 )
5806 cloud_init_list.append(
5807 self._parse_cloud_init(
5808 cloud_init_text,
5809 additional_params,
5810 db_vnfd["id"],
5811 vdud["id"],
5812 )
5813 )
5814 vca_scaling_info.append(
5815 {
5816 "osm_vdu_id": vdud["id"],
5817 "member-vnf-index": member_vnf_index,
5818 "type": "create",
5819 "vdu_index": count_index,
5820 }
5821 )
5822 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005823 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305824 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005825 "New Resources to be deployed: {}".format(scaling_info)
5826 )
elumalaib9e357c2022-04-27 09:58:38 +05305827 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005828 logging_text,
5829 db_nsr,
5830 update_db_nslcmops,
5831 updated_db_vnfr,
5832 scaling_info,
5833 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305834 )
5835 return "COMPLETED", "Done"
5836 except (LcmException, asyncio.CancelledError):
5837 raise
5838 except Exception as e:
5839 self.logger.debug("Error updating VNF {}".format(e))
5840 return "FAILED", "Error updating VNF {}".format(e)
5841
aticigdffa6212022-04-12 15:27:53 +03005842 async def _ns_charm_upgrade(
5843 self,
5844 ee_id,
5845 charm_id,
5846 charm_type,
5847 path,
5848 timeout: float = None,
5849 ) -> (str, str):
5850 """This method upgrade charms in VNF instances
5851
5852 Args:
5853 ee_id: Execution environment id
5854 path: Local path to the charm
5855 charm_id: charm-id
5856 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5857 timeout: (Float) Timeout for the ns update operation
5858
5859 Returns:
5860 result: (str, str) COMPLETED/FAILED, details
5861 """
5862 try:
5863 charm_type = charm_type or "lxc_proxy_charm"
5864 output = await self.vca_map[charm_type].upgrade_charm(
5865 ee_id=ee_id,
5866 path=path,
5867 charm_id=charm_id,
5868 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005869 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005870 )
5871
5872 if output:
5873 return "COMPLETED", output
5874
5875 except (LcmException, asyncio.CancelledError):
5876 raise
5877
5878 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005879 self.logger.debug("Error upgrading charm {}".format(path))
5880
5881 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5882
5883 async def update(self, nsr_id, nslcmop_id):
5884 """Update NS according to different update types
5885
5886 This method performs upgrade of VNF instances then updates the revision
5887 number in VNF record
5888
5889 Args:
5890 nsr_id: Network service will be updated
5891 nslcmop_id: ns lcm operation id
5892
5893 Returns:
5894 It may raise DbException, LcmException, N2VCException, K8sException
5895
5896 """
5897 # Try to lock HA task here
5898 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5899 if not task_is_locked_by_me:
5900 return
5901
5902 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5903 self.logger.debug(logging_text + "Enter")
5904
5905 # Set the required variables to be filled up later
5906 db_nsr = None
5907 db_nslcmop_update = {}
5908 vnfr_update = {}
5909 nslcmop_operation_state = None
5910 db_nsr_update = {}
5911 error_description_nslcmop = ""
5912 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305913 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005914 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005915 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005916
5917 try:
5918 # wait for any previous tasks in process
5919 step = "Waiting for previous operations to terminate"
5920 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5921 self._write_ns_status(
5922 nsr_id=nsr_id,
5923 ns_state=None,
5924 current_operation="UPDATING",
5925 current_operation_id=nslcmop_id,
5926 )
5927
5928 step = "Getting nslcmop from database"
5929 db_nslcmop = self.db.get_one(
5930 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5931 )
5932 update_type = db_nslcmop["operationParams"]["updateType"]
5933
5934 step = "Getting nsr from database"
5935 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5936 old_operational_status = db_nsr["operational-status"]
5937 db_nsr_update["operational-status"] = "updating"
5938 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5939 nsr_deployed = db_nsr["_admin"].get("deployed")
5940
5941 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005942 # Get the input parameters given through update request
5943 vnf_instance_id = db_nslcmop["operationParams"][
5944 "changeVnfPackageData"
5945 ].get("vnfInstanceId")
5946
5947 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5948 "vnfdId"
5949 )
5950 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5951
5952 step = "Getting vnfr from database"
5953 db_vnfr = self.db.get_one(
5954 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5955 )
5956
5957 step = "Getting vnfds from database"
5958 # Latest VNFD
5959 latest_vnfd = self.db.get_one(
5960 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5961 )
5962 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5963
5964 # Current VNFD
5965 current_vnf_revision = db_vnfr.get("revision", 1)
5966 current_vnfd = self.db.get_one(
5967 "vnfds_revisions",
5968 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5969 fail_on_empty=False,
5970 )
5971 # Charm artifact paths will be filled up later
5972 (
5973 current_charm_artifact_path,
5974 target_charm_artifact_path,
5975 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005976 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005977 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005978
5979 step = "Checking if revision has changed in VNFD"
5980 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305981 change_type = "policy_updated"
5982
aticigdffa6212022-04-12 15:27:53 +03005983 # There is new revision of VNFD, update operation is required
5984 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005985 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005986
5987 step = "Removing the VNFD packages if they exist in the local path"
5988 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5989 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5990
5991 step = "Get the VNFD packages from FSMongo"
5992 self.fs.sync(from_path=latest_vnfd_path)
5993 self.fs.sync(from_path=current_vnfd_path)
5994
5995 step = (
5996 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5997 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005998 current_base_folder = current_vnfd["_admin"]["storage"]
5999 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03006000
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006001 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03006002 get_iterable(nsr_deployed, "VCA")
6003 ):
6004 vnf_index = db_vnfr.get("member-vnf-index-ref")
6005
6006 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006007 if vca_deployed.get("member-vnf-index") == vnf_index:
6008 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6009 vca_type = vca_deployed.get("type")
6010 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03006011
6012 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006013 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03006014
6015 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03006016 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03006017 search_key = "kdu_name"
6018 else:
6019 search_key = "vnfd_id"
6020
6021 entity_id = vca_deployed.get(search_key)
6022
aticigdffa6212022-04-12 15:27:53 +03006023 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03006024 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03006025 )
6026
6027 if "execution-environment-list" in descriptor_config:
6028 ee_list = descriptor_config.get(
6029 "execution-environment-list", []
6030 )
6031 else:
6032 ee_list = []
6033
6034 # There could be several charm used in the same VNF
6035 for ee_item in ee_list:
6036 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03006037 step = "Getting charm name"
6038 charm_name = ee_item["juju"].get("charm")
6039
6040 step = "Setting Charm artifact paths"
6041 current_charm_artifact_path.append(
6042 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006043 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03006044 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006045 vca_type,
aticigdffa6212022-04-12 15:27:53 +03006046 current_vnf_revision,
6047 )
6048 )
6049 target_charm_artifact_path.append(
6050 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006051 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03006052 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006053 vca_type,
aticigd7083542022-05-30 20:45:55 +03006054 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03006055 )
6056 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006057 elif ee_item.get("helm-chart"):
6058 # add chart to list and all parameters
6059 step = "Getting helm chart name"
6060 chart_name = ee_item.get("helm-chart")
garciadeblasfb1e25f2022-11-18 14:36:22 +01006061 if (
6062 ee_item.get("helm-version")
6063 and ee_item.get("helm-version") == "v2"
6064 ):
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006065 vca_type = "helm"
6066 else:
6067 vca_type = "helm-v3"
6068 step = "Setting Helm chart artifact paths"
6069
garciadeblasfb1e25f2022-11-18 14:36:22 +01006070 helm_artifacts.append(
6071 {
6072 "current_artifact_path": get_charm_artifact_path(
6073 current_base_folder,
6074 chart_name,
6075 vca_type,
6076 current_vnf_revision,
6077 ),
6078 "target_artifact_path": get_charm_artifact_path(
6079 latest_base_folder,
6080 chart_name,
6081 vca_type,
6082 latest_vnfd_revision,
6083 ),
6084 "ee_id": ee_id,
6085 "vca_index": vca_index,
6086 "vdu_index": vdu_count_index,
6087 }
6088 )
aticigdffa6212022-04-12 15:27:53 +03006089
6090 charm_artifact_paths = zip(
6091 current_charm_artifact_path, target_charm_artifact_path
6092 )
6093
6094 step = "Checking if software version has changed in VNFD"
6095 if find_software_version(current_vnfd) != find_software_version(
6096 latest_vnfd
6097 ):
aticigdffa6212022-04-12 15:27:53 +03006098 step = "Checking if existing VNF has charm"
6099 for current_charm_path, target_charm_path in list(
6100 charm_artifact_paths
6101 ):
6102 if current_charm_path:
6103 raise LcmException(
6104 "Software version change is not supported as VNF instance {} has charm.".format(
6105 vnf_instance_id
6106 )
6107 )
6108
6109 # There is no change in the charm package, then redeploy the VNF
6110 # based on new descriptor
6111 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306112 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006113 (result, detailed_status) = await self._ns_redeploy_vnf(
6114 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306115 )
6116 if result == "FAILED":
6117 nslcmop_operation_state = result
6118 error_description_nslcmop = detailed_status
6119 db_nslcmop_update["detailed-status"] = detailed_status
6120 self.logger.debug(
6121 logging_text
6122 + " step {} Done with result {} {}".format(
6123 step, nslcmop_operation_state, detailed_status
6124 )
6125 )
aticigdffa6212022-04-12 15:27:53 +03006126
6127 else:
6128 step = "Checking if any charm package has changed or not"
6129 for current_charm_path, target_charm_path in list(
6130 charm_artifact_paths
6131 ):
6132 if (
6133 current_charm_path
6134 and target_charm_path
6135 and self.check_charm_hash_changed(
6136 current_charm_path, target_charm_path
6137 )
6138 ):
aticigdffa6212022-04-12 15:27:53 +03006139 step = "Checking whether VNF uses juju bundle"
6140 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006141 raise LcmException(
6142 "Charm upgrade is not supported for the instance which"
6143 " uses juju-bundle: {}".format(
6144 check_juju_bundle_existence(current_vnfd)
6145 )
6146 )
6147
6148 step = "Upgrading Charm"
6149 (
6150 result,
6151 detailed_status,
6152 ) = await self._ns_charm_upgrade(
6153 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006154 charm_id=vca_id,
6155 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006156 path=self.fs.path + target_charm_path,
6157 timeout=timeout_seconds,
6158 )
6159
6160 if result == "FAILED":
6161 nslcmop_operation_state = result
6162 error_description_nslcmop = detailed_status
6163
6164 db_nslcmop_update["detailed-status"] = detailed_status
6165 self.logger.debug(
6166 logging_text
6167 + " step {} Done with result {} {}".format(
6168 step, nslcmop_operation_state, detailed_status
6169 )
6170 )
6171
6172 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306173 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6174 result = "COMPLETED"
6175 detailed_status = "Done"
6176 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006177
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006178 # helm base EE
6179 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006180 if not (
6181 item["current_artifact_path"]
6182 and item["target_artifact_path"]
6183 and self.check_charm_hash_changed(
6184 item["current_artifact_path"],
6185 item["target_artifact_path"],
6186 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006187 ):
6188 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006189 db_update_entry = "_admin.deployed.VCA.{}.".format(
6190 item["vca_index"]
6191 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006192 vnfr_id = db_vnfr["_id"]
6193 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6194 db_dict = {
6195 "collection": "nsrs",
6196 "filter": {"_id": nsr_id},
6197 "path": db_update_entry,
6198 }
6199 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006200 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006201 namespace=namespace,
6202 helm_id=helm_id,
6203 db_dict=db_dict,
6204 config=osm_config,
6205 artifact_path=item["target_artifact_path"],
6206 vca_type=vca_type,
6207 )
6208 vnf_id = db_vnfr.get("vnfd-ref")
6209 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6210 self.logger.debug("get ssh key block")
6211 rw_mgmt_ip = None
6212 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006213 config_descriptor,
6214 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006215 ):
6216 # Needed to inject a ssh key
6217 user = deep_get(
6218 config_descriptor,
6219 ("config-access", "ssh-access", "default-user"),
6220 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006221 step = (
6222 "Install configuration Software, getting public ssh key"
6223 )
6224 pub_key = await self.vca_map[
6225 vca_type
6226 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006227 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6228 )
6229
garciadeblasfb1e25f2022-11-18 14:36:22 +01006230 step = (
6231 "Insert public key into VM user={} ssh_key={}".format(
6232 user, pub_key
6233 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006234 )
6235 self.logger.debug(logging_text + step)
6236
6237 # wait for RO (ip-address) Insert pub_key into VM
6238 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6239 logging_text,
6240 nsr_id,
6241 vnfr_id,
6242 None,
6243 item["vdu_index"],
6244 user=user,
6245 pub_key=pub_key,
6246 )
6247
6248 initial_config_primitive_list = config_descriptor.get(
6249 "initial-config-primitive"
6250 )
6251 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006252 (
6253 p
6254 for p in initial_config_primitive_list
6255 if p["name"] == "config"
6256 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006257 None,
6258 )
6259 if not config_primitive:
6260 continue
6261
6262 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6263 if rw_mgmt_ip:
6264 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6265 if db_vnfr.get("additionalParamsForVnf"):
6266 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006267 parse_yaml_strings(
6268 db_vnfr["additionalParamsForVnf"].copy()
6269 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006270 )
6271 primitive_params_ = self._map_primitive_params(
6272 config_primitive, {}, deploy_params
6273 )
6274
6275 step = "execute primitive '{}' params '{}'".format(
6276 config_primitive["name"], primitive_params_
6277 )
6278 self.logger.debug(logging_text + step)
6279 await self.vca_map[vca_type].exec_primitive(
6280 ee_id=ee_id,
6281 primitive_name=config_primitive["name"],
6282 params_dict=primitive_params_,
6283 db_dict=db_dict,
6284 vca_id=vca_id,
6285 vca_type=vca_type,
6286 )
6287
6288 step = "Updating policies"
6289 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6290 detailed_status = "Done"
6291 db_nslcmop_update["detailed-status"] = "Done"
6292
aticigdffa6212022-04-12 15:27:53 +03006293 # If nslcmop_operation_state is None, so any operation is not failed.
6294 if not nslcmop_operation_state:
6295 nslcmop_operation_state = "COMPLETED"
6296
6297 # If update CHANGE_VNFPKG nslcmop_operation is successful
6298 # vnf revision need to be updated
6299 vnfr_update["revision"] = latest_vnfd_revision
6300 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6301
6302 self.logger.debug(
6303 logging_text
6304 + " task Done with result {} {}".format(
6305 nslcmop_operation_state, detailed_status
6306 )
6307 )
6308 elif update_type == "REMOVE_VNF":
6309 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306310 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6311 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6312 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6313 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006314 (result, detailed_status) = await self.remove_vnf(
6315 nsr_id, nslcmop_id, vnf_instance_id
6316 )
elumalaica7ece02022-04-12 12:47:32 +05306317 if result == "FAILED":
6318 nslcmop_operation_state = result
6319 error_description_nslcmop = detailed_status
6320 db_nslcmop_update["detailed-status"] = detailed_status
6321 change_type = "vnf_terminated"
6322 if not nslcmop_operation_state:
6323 nslcmop_operation_state = "COMPLETED"
6324 self.logger.debug(
6325 logging_text
6326 + " task Done with result {} {}".format(
6327 nslcmop_operation_state, detailed_status
6328 )
6329 )
aticigdffa6212022-04-12 15:27:53 +03006330
k4.rahulb827de92022-05-02 16:35:02 +00006331 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006332 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6333 "vnfInstanceId"
6334 ]
6335 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6336 "changeStateTo"
6337 ]
6338 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6339 "additionalParam"
6340 ]
k4.rahulb827de92022-05-02 16:35:02 +00006341 (result, detailed_status) = await self.rebuild_start_stop(
6342 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006343 )
k4.rahulb827de92022-05-02 16:35:02 +00006344 if result == "FAILED":
6345 nslcmop_operation_state = result
6346 error_description_nslcmop = detailed_status
6347 db_nslcmop_update["detailed-status"] = detailed_status
6348 if not nslcmop_operation_state:
6349 nslcmop_operation_state = "COMPLETED"
6350 self.logger.debug(
6351 logging_text
6352 + " task Done with result {} {}".format(
6353 nslcmop_operation_state, detailed_status
6354 )
6355 )
6356
aticigdffa6212022-04-12 15:27:53 +03006357 # If nslcmop_operation_state is None, so any operation is not failed.
6358 # All operations are executed in overall.
6359 if not nslcmop_operation_state:
6360 nslcmop_operation_state = "COMPLETED"
6361 db_nsr_update["operational-status"] = old_operational_status
6362
6363 except (DbException, LcmException, N2VCException, K8sException) as e:
6364 self.logger.error(logging_text + "Exit Exception {}".format(e))
6365 exc = e
6366 except asyncio.CancelledError:
6367 self.logger.error(
6368 logging_text + "Cancelled Exception while '{}'".format(step)
6369 )
6370 exc = "Operation was cancelled"
6371 except asyncio.TimeoutError:
6372 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6373 exc = "Timeout"
6374 except Exception as e:
6375 exc = traceback.format_exc()
6376 self.logger.critical(
6377 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6378 exc_info=True,
6379 )
6380 finally:
6381 if exc:
6382 db_nslcmop_update[
6383 "detailed-status"
6384 ] = (
6385 detailed_status
6386 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6387 nslcmop_operation_state = "FAILED"
6388 db_nsr_update["operational-status"] = old_operational_status
6389 if db_nsr:
6390 self._write_ns_status(
6391 nsr_id=nsr_id,
6392 ns_state=db_nsr["nsState"],
6393 current_operation="IDLE",
6394 current_operation_id=None,
6395 other_update=db_nsr_update,
6396 )
6397
6398 self._write_op_status(
6399 op_id=nslcmop_id,
6400 stage="",
6401 error_message=error_description_nslcmop,
6402 operation_state=nslcmop_operation_state,
6403 other_update=db_nslcmop_update,
6404 )
6405
6406 if nslcmop_operation_state:
6407 try:
elumalaica7ece02022-04-12 12:47:32 +05306408 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306409 "nsr_id": nsr_id,
6410 "nslcmop_id": nslcmop_id,
6411 "operationState": nslcmop_operation_state,
6412 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006413 if (
6414 change_type in ("vnf_terminated", "policy_updated")
6415 and member_vnf_index
6416 ):
elumalaica7ece02022-04-12 12:47:32 +05306417 msg.update({"vnf_member_index": member_vnf_index})
Gabriel Cubae7898982023-05-11 01:57:21 -05006418 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006419 except Exception as e:
6420 self.logger.error(
6421 logging_text + "kafka_write notification Exception {}".format(e)
6422 )
6423 self.logger.debug(logging_text + "Exit")
6424 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6425 return nslcmop_operation_state, detailed_status
6426
tierno59d22d22018-09-25 18:10:19 +02006427 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006428 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006429 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006430 if not task_is_locked_by_me:
6431 return
6432
tierno59d22d22018-09-25 18:10:19 +02006433 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006434 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006435 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006436 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006437 self.logger.debug(logging_text + "Enter")
6438 # get all needed from database
6439 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006440 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006441 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006442 exc = None
tierno9ab95942018-10-10 16:44:22 +02006443 # in case of error, indicates what part of scale was failed to put nsr at error status
6444 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006445 old_operational_status = ""
6446 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006447 nsi_id = None
tierno59d22d22018-09-25 18:10:19 +02006448 try:
kuused124bfe2019-06-18 12:09:24 +02006449 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006450 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006451 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6452 self._write_ns_status(
6453 nsr_id=nsr_id,
6454 ns_state=None,
6455 current_operation="SCALING",
6456 current_operation_id=nslcmop_id,
6457 )
quilesj4cda56b2019-12-05 10:02:20 +00006458
ikalyvas02d9e7b2019-05-27 18:16:01 +03006459 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006460 self.logger.debug(
6461 step + " after having waited for previous tasks to be completed"
6462 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006463 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006464
ikalyvas02d9e7b2019-05-27 18:16:01 +03006465 step = "Getting nsr from database"
6466 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006467 old_operational_status = db_nsr["operational-status"]
6468 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006469
tierno59d22d22018-09-25 18:10:19 +02006470 step = "Parsing scaling parameters"
6471 db_nsr_update["operational-status"] = "scaling"
6472 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006473 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006474
garciadeblas5697b8b2021-03-24 09:17:02 +01006475 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6476 "scaleByStepData"
6477 ]["member-vnf-index"]
6478 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6479 "scaleByStepData"
6480 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006481 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006482 # for backward compatibility
6483 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6484 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6485 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6486 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6487
tierno59d22d22018-09-25 18:10:19 +02006488 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006489 db_vnfr = self.db.get_one(
6490 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6491 )
bravof922c4172020-11-24 21:21:43 -03006492
David Garciac1fe90a2021-03-31 19:12:02 +02006493 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6494
tierno59d22d22018-09-25 18:10:19 +02006495 step = "Getting vnfd from database"
6496 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006497
aktas13251562021-02-12 22:19:10 +03006498 base_folder = db_vnfd["_admin"]["storage"]
6499
tierno59d22d22018-09-25 18:10:19 +02006500 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006501 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006502 get_scaling_aspect(db_vnfd),
6503 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006504 )
6505 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006506 raise LcmException(
6507 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6508 "at vnfd:scaling-group-descriptor".format(scaling_group)
6509 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006510
tierno15b1cf12019-08-29 13:21:40 +00006511 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006512 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006513 nb_scale_op = 0
6514 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006515 self.update_db_2(
6516 "nsrs",
6517 nsr_id,
6518 {
6519 "_admin.scaling-group": [
6520 {"name": scaling_group, "nb-scale-op": 0}
6521 ]
6522 },
6523 )
tierno59d22d22018-09-25 18:10:19 +02006524 admin_scale_index = 0
6525 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006526 for admin_scale_index, admin_scale_info in enumerate(
6527 db_nsr["_admin"]["scaling-group"]
6528 ):
tierno59d22d22018-09-25 18:10:19 +02006529 if admin_scale_info["name"] == scaling_group:
6530 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6531 break
tierno9ab95942018-10-10 16:44:22 +02006532 else: # not found, set index one plus last element and add new entry with the name
6533 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006534 db_nsr_update[
6535 "_admin.scaling-group.{}.name".format(admin_scale_index)
6536 ] = scaling_group
aktas5f75f102021-03-15 11:26:10 +03006537
6538 vca_scaling_info = []
6539 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006540 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006541 if "aspect-delta-details" not in scaling_descriptor:
6542 raise LcmException(
6543 "Aspect delta details not fount in scaling descriptor {}".format(
6544 scaling_descriptor["name"]
6545 )
6546 )
tierno59d22d22018-09-25 18:10:19 +02006547 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006548 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006549
aktas5f75f102021-03-15 11:26:10 +03006550 scaling_info["scaling_direction"] = "OUT"
6551 scaling_info["vdu-create"] = {}
6552 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006553 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006554 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006555 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006556 # vdu_index also provides the number of instance of the targeted vdu
6557 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
garciadeblas5697b8b2021-03-24 09:17:02 +01006558 cloud_init_text = self._get_vdu_cloud_init_content(
6559 vdud, db_vnfd
6560 )
tierno72ef84f2020-10-06 08:22:07 +00006561 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006562 additional_params = (
6563 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6564 or {}
6565 )
bravof832f8992020-12-07 12:57:31 -03006566 cloud_init_list = []
6567
6568 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6569 max_instance_count = 10
6570 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006571 max_instance_count = vdu_profile.get(
6572 "max-number-of-instances", 10
6573 )
6574
6575 default_instance_num = get_number_of_instances(
6576 db_vnfd, vdud["id"]
6577 )
aktas5f75f102021-03-15 11:26:10 +03006578 instances_number = vdu_delta.get("number-of-instances", 1)
6579 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006580
aktas5f75f102021-03-15 11:26:10 +03006581 new_instance_count = nb_scale_op + default_instance_num
6582 # Control if new count is over max and vdu count is less than max.
6583 # Then assign new instance count
6584 if new_instance_count > max_instance_count > vdu_count:
6585 instances_number = new_instance_count - max_instance_count
6586 else:
6587 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006588
aktas5f75f102021-03-15 11:26:10 +03006589 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006590 raise LcmException(
6591 "reached the limit of {} (max-instance-count) "
6592 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006593 "scaling-group-descriptor '{}'".format(
6594 nb_scale_op, scaling_group
6595 )
bravof922c4172020-11-24 21:21:43 -03006596 )
bravof832f8992020-12-07 12:57:31 -03006597 for x in range(vdu_delta.get("number-of-instances", 1)):
6598 if cloud_init_text:
6599 # TODO Information of its own ip is not available because db_vnfr is not updated.
6600 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006601 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006602 )
bravof832f8992020-12-07 12:57:31 -03006603 cloud_init_list.append(
6604 self._parse_cloud_init(
6605 cloud_init_text,
6606 additional_params,
6607 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006608 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006609 )
6610 )
aktas5f75f102021-03-15 11:26:10 +03006611 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006612 {
6613 "osm_vdu_id": vdu_delta["id"],
6614 "member-vnf-index": vnf_index,
6615 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006616 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006617 }
6618 )
aktas5f75f102021-03-15 11:26:10 +03006619 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6620 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006621 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006622 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006623 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006624
6625 # Might have different kdus in the same delta
6626 # Should have list for each kdu
6627 if not scaling_info["kdu-create"].get(kdu_name, None):
6628 scaling_info["kdu-create"][kdu_name] = []
6629
6630 kdur = get_kdur(db_vnfr, kdu_name)
6631 if kdur.get("helm-chart"):
6632 k8s_cluster_type = "helm-chart-v3"
6633 self.logger.debug("kdur: {}".format(kdur))
6634 if (
6635 kdur.get("helm-version")
6636 and kdur.get("helm-version") == "v2"
6637 ):
6638 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006639 elif kdur.get("juju-bundle"):
6640 k8s_cluster_type = "juju-bundle"
6641 else:
6642 raise LcmException(
6643 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6644 "juju-bundle. Maybe an old NBI version is running".format(
6645 db_vnfr["member-vnf-index-ref"], kdu_name
6646 )
6647 )
6648
6649 max_instance_count = 10
6650 if kdu_profile and "max-number-of-instances" in kdu_profile:
6651 max_instance_count = kdu_profile.get(
6652 "max-number-of-instances", 10
6653 )
6654
6655 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6656 deployed_kdu, _ = get_deployed_kdu(
6657 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006658 )
aktas5f75f102021-03-15 11:26:10 +03006659 if deployed_kdu is None:
6660 raise LcmException(
6661 "KDU '{}' for vnf '{}' not deployed".format(
6662 kdu_name, vnf_index
6663 )
6664 )
6665 kdu_instance = deployed_kdu.get("kdu-instance")
6666 instance_num = await self.k8scluster_map[
6667 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006668 ].get_scale_count(
6669 resource_name,
6670 kdu_instance,
6671 vca_id=vca_id,
6672 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6673 kdu_model=deployed_kdu.get("kdu-model"),
6674 )
aktas5f75f102021-03-15 11:26:10 +03006675 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006676 "number-of-instances", 1
6677 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006678
aktas5f75f102021-03-15 11:26:10 +03006679 # Control if new count is over max and instance_num is less than max.
6680 # Then assign max instance number to kdu replica count
6681 if kdu_replica_count > max_instance_count > instance_num:
6682 kdu_replica_count = max_instance_count
6683 if kdu_replica_count > max_instance_count:
6684 raise LcmException(
6685 "reached the limit of {} (max-instance-count) "
6686 "scaling-out operations for the "
6687 "scaling-group-descriptor '{}'".format(
6688 instance_num, scaling_group
6689 )
6690 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006691
aktas5f75f102021-03-15 11:26:10 +03006692 for x in range(kdu_delta.get("number-of-instances", 1)):
6693 vca_scaling_info.append(
6694 {
6695 "osm_kdu_id": kdu_name,
6696 "member-vnf-index": vnf_index,
6697 "type": "create",
6698 "kdu_index": instance_num + x - 1,
6699 }
6700 )
6701 scaling_info["kdu-create"][kdu_name].append(
6702 {
6703 "member-vnf-index": vnf_index,
6704 "type": "create",
6705 "k8s-cluster-type": k8s_cluster_type,
6706 "resource-name": resource_name,
6707 "scale": kdu_replica_count,
6708 }
6709 )
6710 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006711 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006712
6713 scaling_info["scaling_direction"] = "IN"
6714 scaling_info["vdu-delete"] = {}
6715 scaling_info["kdu-delete"] = {}
6716
bravof832f8992020-12-07 12:57:31 -03006717 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006718 for vdu_delta in delta.get("vdu-delta", {}):
6719 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006720 min_instance_count = 0
6721 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6722 if vdu_profile and "min-number-of-instances" in vdu_profile:
6723 min_instance_count = vdu_profile["min-number-of-instances"]
6724
garciadeblas5697b8b2021-03-24 09:17:02 +01006725 default_instance_num = get_number_of_instances(
6726 db_vnfd, vdu_delta["id"]
6727 )
aktas5f75f102021-03-15 11:26:10 +03006728 instance_num = vdu_delta.get("number-of-instances", 1)
6729 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006730
aktas5f75f102021-03-15 11:26:10 +03006731 new_instance_count = nb_scale_op + default_instance_num
6732
6733 if new_instance_count < min_instance_count < vdu_count:
6734 instances_number = min_instance_count - new_instance_count
6735 else:
6736 instances_number = instance_num
6737
6738 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006739 raise LcmException(
6740 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006741 "scaling-group-descriptor '{}'".format(
6742 nb_scale_op, scaling_group
6743 )
bravof832f8992020-12-07 12:57:31 -03006744 )
aktas13251562021-02-12 22:19:10 +03006745 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006746 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006747 {
6748 "osm_vdu_id": vdu_delta["id"],
6749 "member-vnf-index": vnf_index,
6750 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006751 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006752 }
6753 )
aktas5f75f102021-03-15 11:26:10 +03006754 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6755 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006756 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006757 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006758 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006759
6760 if not scaling_info["kdu-delete"].get(kdu_name, None):
6761 scaling_info["kdu-delete"][kdu_name] = []
6762
6763 kdur = get_kdur(db_vnfr, kdu_name)
6764 if kdur.get("helm-chart"):
6765 k8s_cluster_type = "helm-chart-v3"
6766 self.logger.debug("kdur: {}".format(kdur))
6767 if (
6768 kdur.get("helm-version")
6769 and kdur.get("helm-version") == "v2"
6770 ):
6771 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006772 elif kdur.get("juju-bundle"):
6773 k8s_cluster_type = "juju-bundle"
6774 else:
6775 raise LcmException(
6776 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6777 "juju-bundle. Maybe an old NBI version is running".format(
6778 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6779 )
6780 )
6781
6782 min_instance_count = 0
6783 if kdu_profile and "min-number-of-instances" in kdu_profile:
6784 min_instance_count = kdu_profile["min-number-of-instances"]
6785
6786 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6787 deployed_kdu, _ = get_deployed_kdu(
6788 nsr_deployed, kdu_name, vnf_index
6789 )
6790 if deployed_kdu is None:
6791 raise LcmException(
6792 "KDU '{}' for vnf '{}' not deployed".format(
6793 kdu_name, vnf_index
6794 )
6795 )
6796 kdu_instance = deployed_kdu.get("kdu-instance")
6797 instance_num = await self.k8scluster_map[
6798 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006799 ].get_scale_count(
6800 resource_name,
6801 kdu_instance,
6802 vca_id=vca_id,
6803 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6804 kdu_model=deployed_kdu.get("kdu-model"),
6805 )
aktas5f75f102021-03-15 11:26:10 +03006806 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006807 "number-of-instances", 1
6808 )
tierno59d22d22018-09-25 18:10:19 +02006809
aktas5f75f102021-03-15 11:26:10 +03006810 if kdu_replica_count < min_instance_count < instance_num:
6811 kdu_replica_count = min_instance_count
6812 if kdu_replica_count < min_instance_count:
6813 raise LcmException(
6814 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6815 "scaling-group-descriptor '{}'".format(
6816 instance_num, scaling_group
6817 )
6818 )
6819
6820 for x in range(kdu_delta.get("number-of-instances", 1)):
6821 vca_scaling_info.append(
6822 {
6823 "osm_kdu_id": kdu_name,
6824 "member-vnf-index": vnf_index,
6825 "type": "delete",
6826 "kdu_index": instance_num - x - 1,
6827 }
6828 )
6829 scaling_info["kdu-delete"][kdu_name].append(
6830 {
6831 "member-vnf-index": vnf_index,
6832 "type": "delete",
6833 "k8s-cluster-type": k8s_cluster_type,
6834 "resource-name": resource_name,
6835 "scale": kdu_replica_count,
6836 }
6837 )
6838
tierno59d22d22018-09-25 18:10:19 +02006839 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006840 vdu_delete = copy(scaling_info.get("vdu-delete"))
6841 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006842 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006843 if vdu_delete.get(vdur["vdu-id-ref"]):
6844 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006845 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006846 {
6847 "name": vdur.get("name") or vdur.get("vdu-name"),
6848 "vdu_id": vdur["vdu-id-ref"],
6849 "interface": [],
6850 }
6851 )
tierno59d22d22018-09-25 18:10:19 +02006852 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006853 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006854 {
6855 "name": interface["name"],
6856 "ip_address": interface["ip-address"],
6857 "mac_address": interface.get("mac-address"),
6858 }
6859 )
tierno2357f4e2020-10-19 16:38:59 +00006860 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006861
kuuseac3a8882019-10-03 10:48:06 +02006862 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006863 step = "Executing pre-scale vnf-config-primitive"
6864 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006865 for scaling_config_action in scaling_descriptor[
6866 "scaling-config-action"
6867 ]:
6868 if (
6869 scaling_config_action.get("trigger") == "pre-scale-in"
6870 and scaling_type == "SCALE_IN"
6871 ) or (
6872 scaling_config_action.get("trigger") == "pre-scale-out"
6873 and scaling_type == "SCALE_OUT"
6874 ):
6875 vnf_config_primitive = scaling_config_action[
6876 "vnf-config-primitive-name-ref"
6877 ]
6878 step = db_nslcmop_update[
6879 "detailed-status"
6880 ] = "executing pre-scale scaling-config-action '{}'".format(
6881 vnf_config_primitive
6882 )
tiernoda964822019-01-14 15:53:47 +00006883
tierno59d22d22018-09-25 18:10:19 +02006884 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006885 for config_primitive in (
6886 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6887 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006888 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006889 break
6890 else:
6891 raise LcmException(
6892 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006893 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006894 "primitive".format(scaling_group, vnf_config_primitive)
6895 )
tiernoda964822019-01-14 15:53:47 +00006896
aktas5f75f102021-03-15 11:26:10 +03006897 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006898 if db_vnfr.get("additionalParamsForVnf"):
6899 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006900
tierno9ab95942018-10-10 16:44:22 +02006901 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006902 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006903 primitive_params = self._map_primitive_params(
6904 config_primitive, {}, vnfr_params
6905 )
kuuseac3a8882019-10-03 10:48:06 +02006906
tierno7c4e24c2020-05-13 08:41:35 +00006907 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006908 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006909 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006910 vnf_index,
6911 vnf_config_primitive,
6912 primitive_params,
6913 "PRE-SCALE",
6914 )
tierno7c4e24c2020-05-13 08:41:35 +00006915 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006916 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006917 result = "COMPLETED"
6918 result_detail = "Done"
6919 self.logger.debug(
6920 logging_text
6921 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6922 vnf_config_primitive, result, result_detail
6923 )
6924 )
kuuseac3a8882019-10-03 10:48:06 +02006925 else:
tierno7c4e24c2020-05-13 08:41:35 +00006926 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006927 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006928 op_index = (
6929 len(db_nslcmop.get("_admin", {}).get("operations"))
6930 - 1
6931 )
6932 self.logger.debug(
6933 logging_text
6934 + "vnf_config_primitive={} New sub-operation".format(
6935 vnf_config_primitive
6936 )
6937 )
kuuseac3a8882019-10-03 10:48:06 +02006938 else:
tierno7c4e24c2020-05-13 08:41:35 +00006939 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006940 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6941 op_index
6942 ]
6943 vnf_index = op.get("member_vnf_index")
6944 vnf_config_primitive = op.get("primitive")
6945 primitive_params = op.get("primitive_params")
6946 self.logger.debug(
6947 logging_text
6948 + "vnf_config_primitive={} Sub-operation retry".format(
6949 vnf_config_primitive
6950 )
6951 )
tierno588547c2020-07-01 15:30:20 +00006952 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006953 ee_descriptor_id = config_primitive.get(
6954 "execution-environment-ref"
6955 )
6956 primitive_name = config_primitive.get(
6957 "execution-environment-primitive", vnf_config_primitive
6958 )
6959 ee_id, vca_type = self._look_for_deployed_vca(
6960 nsr_deployed["VCA"],
6961 member_vnf_index=vnf_index,
6962 vdu_id=None,
6963 vdu_count_index=None,
6964 ee_descriptor_id=ee_descriptor_id,
6965 )
kuuseac3a8882019-10-03 10:48:06 +02006966 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006967 ee_id,
6968 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006969 primitive_params,
6970 vca_type=vca_type,
6971 vca_id=vca_id,
6972 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006973 self.logger.debug(
6974 logging_text
6975 + "vnf_config_primitive={} Done with result {} {}".format(
6976 vnf_config_primitive, result, result_detail
6977 )
6978 )
kuuseac3a8882019-10-03 10:48:06 +02006979 # Update operationState = COMPLETED | FAILED
6980 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006981 db_nslcmop, op_index, result, result_detail
6982 )
kuuseac3a8882019-10-03 10:48:06 +02006983
tierno59d22d22018-09-25 18:10:19 +02006984 if result == "FAILED":
6985 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006986 db_nsr_update["config-status"] = old_config_status
6987 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006988 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006989
garciadeblas5697b8b2021-03-24 09:17:02 +01006990 db_nsr_update[
6991 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6992 ] = nb_scale_op
6993 db_nsr_update[
6994 "_admin.scaling-group.{}.time".format(admin_scale_index)
6995 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006996
aktas13251562021-02-12 22:19:10 +03006997 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006998 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006999 step = db_nslcmop_update[
7000 "detailed-status"
7001 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03007002 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007003 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007004 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007005 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007006 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007007 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007008 )
aktas5f75f102021-03-15 11:26:10 +03007009 if vca_info.get("osm_vdu_id"):
7010 vdu_id = vca_info["osm_vdu_id"]
7011 vdu_index = int(vca_info["vdu_index"])
7012 stage[
7013 1
7014 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7015 member_vnf_index, vdu_id, vdu_index
7016 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007017 stage[2] = step = "Scaling in VCA"
7018 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007019 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7020 config_update = db_nsr["configurationStatus"]
7021 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007022 if (
7023 (vca or vca.get("ee_id"))
7024 and vca["member-vnf-index"] == member_vnf_index
7025 and vca["vdu_count_index"] == vdu_index
7026 ):
aktas13251562021-02-12 22:19:10 +03007027 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007028 config_descriptor = get_configuration(
7029 db_vnfd, vca.get("vdu_id")
7030 )
aktas13251562021-02-12 22:19:10 +03007031 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007032 config_descriptor = get_configuration(
7033 db_vnfd, vca.get("kdu_name")
7034 )
aktas13251562021-02-12 22:19:10 +03007035 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007036 config_descriptor = get_configuration(
7037 db_vnfd, db_vnfd["id"]
7038 )
7039 operation_params = (
7040 db_nslcmop.get("operationParams") or {}
7041 )
7042 exec_terminate_primitives = not operation_params.get(
7043 "skip_terminate_primitives"
7044 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007045 task = asyncio.ensure_future(
7046 asyncio.wait_for(
7047 self.destroy_N2VC(
7048 logging_text,
7049 db_nslcmop,
7050 vca,
7051 config_descriptor,
7052 vca_index,
7053 destroy_ee=True,
7054 exec_primitives=exec_terminate_primitives,
7055 scaling_in=True,
7056 vca_id=vca_id,
7057 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007058 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007059 )
7060 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007061 tasks_dict_info[task] = "Terminating VCA {}".format(
7062 vca.get("ee_id")
7063 )
aktas13251562021-02-12 22:19:10 +03007064 del vca_update[vca_index]
7065 del config_update[vca_index]
7066 # wait for pending tasks of terminate primitives
7067 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007068 self.logger.debug(
7069 logging_text
7070 + "Waiting for tasks {}".format(
7071 list(tasks_dict_info.keys())
7072 )
7073 )
7074 error_list = await self._wait_for_tasks(
7075 logging_text,
7076 tasks_dict_info,
7077 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007078 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007079 ),
7080 stage,
7081 nslcmop_id,
7082 )
aktas13251562021-02-12 22:19:10 +03007083 tasks_dict_info.clear()
7084 if error_list:
7085 raise LcmException("; ".join(error_list))
7086
7087 db_vca_and_config_update = {
7088 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007089 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007090 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007091 self.update_db_2(
7092 "nsrs", db_nsr["_id"], db_vca_and_config_update
7093 )
aktas13251562021-02-12 22:19:10 +03007094 scale_process = None
7095 # SCALE-IN VCA - END
7096
kuuseac3a8882019-10-03 10:48:06 +02007097 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007098 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007099 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007100 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007101 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007102 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007103 )
aktas5f75f102021-03-15 11:26:10 +03007104 scaling_info.pop("vdu-create", None)
7105 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007106
tierno9ab95942018-10-10 16:44:22 +02007107 scale_process = None
aktas13251562021-02-12 22:19:10 +03007108 # SCALE RO - END
7109
aktas5f75f102021-03-15 11:26:10 +03007110 # SCALE KDU - BEGIN
7111 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7112 scale_process = "KDU"
7113 await self._scale_kdu(
7114 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7115 )
7116 scaling_info.pop("kdu-create", None)
7117 scaling_info.pop("kdu-delete", None)
7118
7119 scale_process = None
7120 # SCALE KDU - END
7121
7122 if db_nsr_update:
7123 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7124
aktas13251562021-02-12 22:19:10 +03007125 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007126 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007127 step = db_nslcmop_update[
7128 "detailed-status"
7129 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007130 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007131 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007132 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007133 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007134 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007135 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007136 )
aktas13251562021-02-12 22:19:10 +03007137 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007138 if vca_info.get("osm_vdu_id"):
7139 vdu_index = int(vca_info["vdu_index"])
7140 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7141 if db_vnfr.get("additionalParamsForVnf"):
7142 deploy_params.update(
7143 parse_yaml_strings(
7144 db_vnfr["additionalParamsForVnf"].copy()
7145 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007146 )
aktas5f75f102021-03-15 11:26:10 +03007147 descriptor_config = get_configuration(
7148 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007149 )
aktas5f75f102021-03-15 11:26:10 +03007150 if descriptor_config:
7151 vdu_id = None
7152 vdu_name = None
7153 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007154 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007155 self._deploy_n2vc(
7156 logging_text=logging_text
7157 + "member_vnf_index={} ".format(member_vnf_index),
7158 db_nsr=db_nsr,
7159 db_vnfr=db_vnfr,
7160 nslcmop_id=nslcmop_id,
7161 nsr_id=nsr_id,
7162 nsi_id=nsi_id,
7163 vnfd_id=vnfd_id,
7164 vdu_id=vdu_id,
7165 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007166 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007167 member_vnf_index=member_vnf_index,
7168 vdu_index=vdu_index,
7169 vdu_name=vdu_name,
7170 deploy_params=deploy_params,
7171 descriptor_config=descriptor_config,
7172 base_folder=base_folder,
7173 task_instantiation_info=tasks_dict_info,
7174 stage=stage,
7175 )
7176 vdu_id = vca_info["osm_vdu_id"]
7177 vdur = find_in_list(
7178 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007179 )
aktas5f75f102021-03-15 11:26:10 +03007180 descriptor_config = get_configuration(db_vnfd, vdu_id)
7181 if vdur.get("additionalParams"):
7182 deploy_params_vdu = parse_yaml_strings(
7183 vdur["additionalParams"]
7184 )
7185 else:
7186 deploy_params_vdu = deploy_params
7187 deploy_params_vdu["OSM"] = get_osm_params(
7188 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007189 )
aktas5f75f102021-03-15 11:26:10 +03007190 if descriptor_config:
7191 vdu_name = None
7192 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007193 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007194 stage[
7195 1
7196 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007197 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007198 )
7199 stage[2] = step = "Scaling out VCA"
7200 self._write_op_status(op_id=nslcmop_id, stage=stage)
7201 self._deploy_n2vc(
7202 logging_text=logging_text
7203 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7204 member_vnf_index, vdu_id, vdu_index
7205 ),
7206 db_nsr=db_nsr,
7207 db_vnfr=db_vnfr,
7208 nslcmop_id=nslcmop_id,
7209 nsr_id=nsr_id,
7210 nsi_id=nsi_id,
7211 vnfd_id=vnfd_id,
7212 vdu_id=vdu_id,
7213 kdu_name=kdu_name,
7214 member_vnf_index=member_vnf_index,
7215 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007216 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007217 vdu_name=vdu_name,
7218 deploy_params=deploy_params_vdu,
7219 descriptor_config=descriptor_config,
7220 base_folder=base_folder,
7221 task_instantiation_info=tasks_dict_info,
7222 stage=stage,
7223 )
aktas13251562021-02-12 22:19:10 +03007224 # SCALE-UP VCA - END
7225 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007226
kuuseac3a8882019-10-03 10:48:06 +02007227 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007228 # execute primitive service POST-SCALING
7229 step = "Executing post-scale vnf-config-primitive"
7230 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007231 for scaling_config_action in scaling_descriptor[
7232 "scaling-config-action"
7233 ]:
7234 if (
7235 scaling_config_action.get("trigger") == "post-scale-in"
7236 and scaling_type == "SCALE_IN"
7237 ) or (
7238 scaling_config_action.get("trigger") == "post-scale-out"
7239 and scaling_type == "SCALE_OUT"
7240 ):
7241 vnf_config_primitive = scaling_config_action[
7242 "vnf-config-primitive-name-ref"
7243 ]
7244 step = db_nslcmop_update[
7245 "detailed-status"
7246 ] = "executing post-scale scaling-config-action '{}'".format(
7247 vnf_config_primitive
7248 )
tiernoda964822019-01-14 15:53:47 +00007249
aktas5f75f102021-03-15 11:26:10 +03007250 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007251 if db_vnfr.get("additionalParamsForVnf"):
7252 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7253
tierno59d22d22018-09-25 18:10:19 +02007254 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007255 for config_primitive in (
7256 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7257 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007258 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007259 break
7260 else:
tiernoa278b842020-07-08 15:33:55 +00007261 raise LcmException(
7262 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7263 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007264 "config-primitive".format(
7265 scaling_group, vnf_config_primitive
7266 )
7267 )
tierno9ab95942018-10-10 16:44:22 +02007268 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007269 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007270 primitive_params = self._map_primitive_params(
7271 config_primitive, {}, vnfr_params
7272 )
tiernod6de1992018-10-11 13:05:52 +02007273
tierno7c4e24c2020-05-13 08:41:35 +00007274 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007275 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007276 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007277 vnf_index,
7278 vnf_config_primitive,
7279 primitive_params,
7280 "POST-SCALE",
7281 )
quilesj4cda56b2019-12-05 10:02:20 +00007282 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007283 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007284 result = "COMPLETED"
7285 result_detail = "Done"
7286 self.logger.debug(
7287 logging_text
7288 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7289 vnf_config_primitive, result, result_detail
7290 )
7291 )
kuuseac3a8882019-10-03 10:48:06 +02007292 else:
quilesj4cda56b2019-12-05 10:02:20 +00007293 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007294 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007295 op_index = (
7296 len(db_nslcmop.get("_admin", {}).get("operations"))
7297 - 1
7298 )
7299 self.logger.debug(
7300 logging_text
7301 + "vnf_config_primitive={} New sub-operation".format(
7302 vnf_config_primitive
7303 )
7304 )
kuuseac3a8882019-10-03 10:48:06 +02007305 else:
tierno7c4e24c2020-05-13 08:41:35 +00007306 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007307 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7308 op_index
7309 ]
7310 vnf_index = op.get("member_vnf_index")
7311 vnf_config_primitive = op.get("primitive")
7312 primitive_params = op.get("primitive_params")
7313 self.logger.debug(
7314 logging_text
7315 + "vnf_config_primitive={} Sub-operation retry".format(
7316 vnf_config_primitive
7317 )
7318 )
tierno588547c2020-07-01 15:30:20 +00007319 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007320 ee_descriptor_id = config_primitive.get(
7321 "execution-environment-ref"
7322 )
7323 primitive_name = config_primitive.get(
7324 "execution-environment-primitive", vnf_config_primitive
7325 )
7326 ee_id, vca_type = self._look_for_deployed_vca(
7327 nsr_deployed["VCA"],
7328 member_vnf_index=vnf_index,
7329 vdu_id=None,
7330 vdu_count_index=None,
7331 ee_descriptor_id=ee_descriptor_id,
7332 )
kuuseac3a8882019-10-03 10:48:06 +02007333 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007334 ee_id,
7335 primitive_name,
7336 primitive_params,
7337 vca_type=vca_type,
7338 vca_id=vca_id,
7339 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007340 self.logger.debug(
7341 logging_text
7342 + "vnf_config_primitive={} Done with result {} {}".format(
7343 vnf_config_primitive, result, result_detail
7344 )
7345 )
kuuseac3a8882019-10-03 10:48:06 +02007346 # Update operationState = COMPLETED | FAILED
7347 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007348 db_nslcmop, op_index, result, result_detail
7349 )
kuuseac3a8882019-10-03 10:48:06 +02007350
tierno59d22d22018-09-25 18:10:19 +02007351 if result == "FAILED":
7352 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007353 db_nsr_update["config-status"] = old_config_status
7354 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007355 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007356
garciadeblas5697b8b2021-03-24 09:17:02 +01007357 db_nsr_update[
7358 "detailed-status"
7359 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7360 db_nsr_update["operational-status"] = (
7361 "running"
7362 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007363 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007364 )
tiernod6de1992018-10-11 13:05:52 +02007365 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007366 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007367 except (
7368 ROclient.ROClientException,
7369 DbException,
7370 LcmException,
7371 NgRoException,
7372 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007373 self.logger.error(logging_text + "Exit Exception {}".format(e))
7374 exc = e
7375 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007376 self.logger.error(
7377 logging_text + "Cancelled Exception while '{}'".format(step)
7378 )
tierno59d22d22018-09-25 18:10:19 +02007379 exc = "Operation was cancelled"
7380 except Exception as e:
7381 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007382 self.logger.critical(
7383 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7384 exc_info=True,
7385 )
tierno59d22d22018-09-25 18:10:19 +02007386 finally:
garciadeblas5697b8b2021-03-24 09:17:02 +01007387 self._write_ns_status(
7388 nsr_id=nsr_id,
7389 ns_state=None,
7390 current_operation="IDLE",
7391 current_operation_id=None,
7392 )
aktas13251562021-02-12 22:19:10 +03007393 if tasks_dict_info:
7394 stage[1] = "Waiting for instantiate pending tasks."
7395 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01007396 exc = await self._wait_for_tasks(
7397 logging_text,
7398 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007399 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007400 stage,
7401 nslcmop_id,
7402 nsr_id=nsr_id,
7403 )
tierno59d22d22018-09-25 18:10:19 +02007404 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01007405 db_nslcmop_update[
7406 "detailed-status"
7407 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tiernoa17d4f42020-04-28 09:59:23 +00007408 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007409 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007410 db_nsr_update["operational-status"] = old_operational_status
7411 db_nsr_update["config-status"] = old_config_status
7412 db_nsr_update["detailed-status"] = ""
7413 if scale_process:
7414 if "VCA" in scale_process:
7415 db_nsr_update["config-status"] = "failed"
7416 if "RO" in scale_process:
7417 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007418 db_nsr_update[
7419 "detailed-status"
7420 ] = "FAILED scaling nslcmop={} {}: {}".format(
7421 nslcmop_id, step, exc
7422 )
tiernoa17d4f42020-04-28 09:59:23 +00007423 else:
7424 error_description_nslcmop = None
7425 nslcmop_operation_state = "COMPLETED"
7426 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00007427
garciadeblas5697b8b2021-03-24 09:17:02 +01007428 self._write_op_status(
7429 op_id=nslcmop_id,
7430 stage="",
7431 error_message=error_description_nslcmop,
7432 operation_state=nslcmop_operation_state,
7433 other_update=db_nslcmop_update,
7434 )
tiernoa17d4f42020-04-28 09:59:23 +00007435 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007436 self._write_ns_status(
7437 nsr_id=nsr_id,
7438 ns_state=None,
7439 current_operation="IDLE",
7440 current_operation_id=None,
7441 other_update=db_nsr_update,
7442 )
tiernoa17d4f42020-04-28 09:59:23 +00007443
tierno59d22d22018-09-25 18:10:19 +02007444 if nslcmop_operation_state:
7445 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007446 msg = {
7447 "nsr_id": nsr_id,
7448 "nslcmop_id": nslcmop_id,
7449 "operationState": nslcmop_operation_state,
7450 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007451 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007452 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007453 self.logger.error(
7454 logging_text + "kafka_write notification Exception {}".format(e)
7455 )
tierno59d22d22018-09-25 18:10:19 +02007456 self.logger.debug(logging_text + "Exit")
7457 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007458
aktas5f75f102021-03-15 11:26:10 +03007459 async def _scale_kdu(
7460 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7461 ):
7462 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7463 for kdu_name in _scaling_info:
7464 for kdu_scaling_info in _scaling_info[kdu_name]:
7465 deployed_kdu, index = get_deployed_kdu(
7466 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7467 )
7468 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7469 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007470 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007471 scale = int(kdu_scaling_info["scale"])
7472 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7473
7474 db_dict = {
7475 "collection": "nsrs",
7476 "filter": {"_id": nsr_id},
7477 "path": "_admin.deployed.K8s.{}".format(index),
7478 }
7479
7480 step = "scaling application {}".format(
7481 kdu_scaling_info["resource-name"]
7482 )
7483 self.logger.debug(logging_text + step)
7484
7485 if kdu_scaling_info["type"] == "delete":
7486 kdu_config = get_configuration(db_vnfd, kdu_name)
7487 if (
7488 kdu_config
7489 and kdu_config.get("terminate-config-primitive")
7490 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7491 ):
7492 terminate_config_primitive_list = kdu_config.get(
7493 "terminate-config-primitive"
7494 )
7495 terminate_config_primitive_list.sort(
7496 key=lambda val: int(val["seq"])
7497 )
7498
7499 for (
7500 terminate_config_primitive
7501 ) in terminate_config_primitive_list:
7502 primitive_params_ = self._map_primitive_params(
7503 terminate_config_primitive, {}, {}
7504 )
7505 step = "execute terminate config primitive"
7506 self.logger.debug(logging_text + step)
7507 await asyncio.wait_for(
7508 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7509 cluster_uuid=cluster_uuid,
7510 kdu_instance=kdu_instance,
7511 primitive_name=terminate_config_primitive["name"],
7512 params=primitive_params_,
7513 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007514 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007515 vca_id=vca_id,
7516 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007517 timeout=self.timeout.primitive
7518 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007519 )
7520
7521 await asyncio.wait_for(
7522 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007523 kdu_instance=kdu_instance,
7524 scale=scale,
7525 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007526 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007527 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007528 cluster_uuid=cluster_uuid,
7529 kdu_model=kdu_model,
7530 atomic=True,
7531 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007532 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007533 timeout=self.timeout.scale_on_error
7534 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007535 )
7536
7537 if kdu_scaling_info["type"] == "create":
7538 kdu_config = get_configuration(db_vnfd, kdu_name)
7539 if (
7540 kdu_config
7541 and kdu_config.get("initial-config-primitive")
7542 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7543 ):
7544 initial_config_primitive_list = kdu_config.get(
7545 "initial-config-primitive"
7546 )
7547 initial_config_primitive_list.sort(
7548 key=lambda val: int(val["seq"])
7549 )
7550
7551 for initial_config_primitive in initial_config_primitive_list:
7552 primitive_params_ = self._map_primitive_params(
7553 initial_config_primitive, {}, {}
7554 )
7555 step = "execute initial config primitive"
7556 self.logger.debug(logging_text + step)
7557 await asyncio.wait_for(
7558 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7559 cluster_uuid=cluster_uuid,
7560 kdu_instance=kdu_instance,
7561 primitive_name=initial_config_primitive["name"],
7562 params=primitive_params_,
7563 db_dict=db_dict,
7564 vca_id=vca_id,
7565 ),
7566 timeout=600,
7567 )
7568
garciadeblas5697b8b2021-03-24 09:17:02 +01007569 async def _scale_ng_ro(
7570 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7571 ):
tierno2357f4e2020-10-19 16:38:59 +00007572 nsr_id = db_nslcmop["nsInstanceId"]
7573 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7574 db_vnfrs = {}
7575
7576 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007577 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007578
7579 # for each vnf in ns, read vnfd
7580 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7581 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7582 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007583 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007584 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007585 # read from db
7586 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007587 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007588 n2vc_key = self.n2vc.get_public_key()
7589 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007590 self.scale_vnfr(
7591 db_vnfr,
7592 vdu_scaling_info.get("vdu-create"),
7593 vdu_scaling_info.get("vdu-delete"),
7594 mark_delete=True,
7595 )
tierno2357f4e2020-10-19 16:38:59 +00007596 # db_vnfr has been updated, update db_vnfrs to use it
7597 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007598 await self._instantiate_ng_ro(
7599 logging_text,
7600 nsr_id,
7601 db_nsd,
7602 db_nsr,
7603 db_nslcmop,
7604 db_vnfrs,
7605 db_vnfds,
7606 n2vc_key_list,
7607 stage=stage,
7608 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007609 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007610 )
tierno2357f4e2020-10-19 16:38:59 +00007611 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007612 self.scale_vnfr(
7613 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7614 )
tierno2357f4e2020-10-19 16:38:59 +00007615
bravof73bac502021-05-11 07:38:47 -04007616 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007617 self,
7618 ee_id: str,
7619 artifact_path: str,
7620 ee_config_descriptor: dict,
7621 vnfr_id: str,
7622 nsr_id: str,
7623 target_ip: str,
7624 element_type: str,
7625 vnf_member_index: str = "",
7626 vdu_id: str = "",
7627 vdu_index: int = None,
7628 kdu_name: str = "",
7629 kdu_index: int = None,
7630 ) -> dict:
7631 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7632 This method will wait until the corresponding VDU or KDU is fully instantiated
7633
7634 Args:
7635 ee_id (str): Execution Environment ID
7636 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7637 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7638 vnfr_id (str): VNFR ID where this EE applies
7639 nsr_id (str): NSR ID where this EE applies
7640 target_ip (str): VDU/KDU instance IP address
7641 element_type (str): NS or VNF or VDU or KDU
7642 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7643 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7644 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7645 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7646 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7647
7648 Raises:
7649 LcmException: When the VDU or KDU instance was not found in an hour
7650
7651 Returns:
7652 _type_: Prometheus jobs
7653 """
7654 # default the vdur and kdur names to an empty string, to avoid any later
7655 # problem with Prometheus when the element type is not VDU or KDU
7656 vdur_name = ""
7657 kdur_name = ""
7658
tiernob996d942020-07-03 14:52:28 +00007659 # look if exist a file called 'prometheus*.j2' and
7660 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007661 job_file = next(
7662 (
7663 f
7664 for f in artifact_content
7665 if f.startswith("prometheus") and f.endswith(".j2")
7666 ),
7667 None,
7668 )
tiernob996d942020-07-03 14:52:28 +00007669 if not job_file:
7670 return
k4.rahul74944982023-04-19 17:00:52 +05307671 self.logger.debug("Artifact path{}".format(artifact_path))
7672 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007673 with self.fs.file_open((artifact_path, job_file), "r") as f:
7674 job_data = f.read()
7675
Pedro Escaleira120695e2022-06-11 21:17:26 +01007676 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7677 if element_type in ("VDU", "KDU"):
7678 for _ in range(360):
7679 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7680 if vdu_id and vdu_index is not None:
7681 vdur = next(
7682 (
7683 x
7684 for x in get_iterable(db_vnfr, "vdur")
7685 if (
7686 x.get("vdu-id-ref") == vdu_id
7687 and x.get("count-index") == vdu_index
7688 )
7689 ),
7690 {},
7691 )
7692 if vdur.get("name"):
7693 vdur_name = vdur.get("name")
7694 break
7695 if kdu_name and kdu_index is not None:
7696 kdur = next(
7697 (
7698 x
7699 for x in get_iterable(db_vnfr, "kdur")
7700 if (
7701 x.get("kdu-name") == kdu_name
7702 and x.get("count-index") == kdu_index
7703 )
7704 ),
7705 {},
7706 )
7707 if kdur.get("name"):
7708 kdur_name = kdur.get("name")
7709 break
7710
Gabriel Cubae7898982023-05-11 01:57:21 -05007711 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007712 else:
7713 if vdu_id and vdu_index is not None:
7714 raise LcmException(
7715 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7716 )
7717 if kdu_name and kdu_index is not None:
7718 raise LcmException(
7719 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7720 )
7721
k4.rahul74944982023-04-19 17:00:52 +05307722 if ee_id is not None:
Gabriel Cuba7f2a2a92023-06-02 19:27:43 -05007723 _, namespace, helm_id = get_ee_id_parts(
7724 ee_id
7725 ) # get namespace and EE gRPC service name
7726 host_name = f'{helm_id}-{ee_config_descriptor["metric-service"]}.{namespace}.svc' # svc_name.namespace.svc
k4.rahul74944982023-04-19 17:00:52 +05307727 host_port = "80"
7728 vnfr_id = vnfr_id.replace("-", "")
7729 variables = {
7730 "JOB_NAME": vnfr_id,
7731 "TARGET_IP": target_ip,
7732 "EXPORTER_POD_IP": host_name,
7733 "EXPORTER_POD_PORT": host_port,
7734 "NSR_ID": nsr_id,
7735 "VNF_MEMBER_INDEX": vnf_member_index,
7736 "VDUR_NAME": vdur_name,
7737 "KDUR_NAME": kdur_name,
7738 "ELEMENT_TYPE": element_type,
7739 }
7740 else:
7741 metric_path = ee_config_descriptor["metric-path"]
7742 target_port = ee_config_descriptor["metric-port"]
7743 vnfr_id = vnfr_id.replace("-", "")
7744 variables = {
7745 "JOB_NAME": vnfr_id,
7746 "TARGET_IP": target_ip,
7747 "TARGET_PORT": target_port,
7748 "METRIC_PATH": metric_path,
7749 }
7750
bravof73bac502021-05-11 07:38:47 -04007751 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007752 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7753 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007754 if (
7755 not isinstance(job.get("job_name"), str)
7756 or vnfr_id not in job["job_name"]
7757 ):
k4.rahulcf47a3b2023-04-27 12:08:48 +05307758 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007759 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007760 job["vnfr_id"] = vnfr_id
7761 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007762
preethika.p28b0bf82022-09-23 07:36:28 +00007763 async def rebuild_start_stop(
7764 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7765 ):
k4.rahulb827de92022-05-02 16:35:02 +00007766 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7767 self.logger.info(logging_text + "Enter")
7768 stage = ["Preparing the environment", ""]
7769 # database nsrs record
7770 db_nsr_update = {}
7771 vdu_vim_name = None
7772 vim_vm_id = None
7773 # in case of error, indicates what part of scale was failed to put nsr at error status
7774 start_deploy = time()
7775 try:
7776 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7777 vim_account_id = db_vnfr.get("vim-account-id")
7778 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007779 vdu_id = additional_param["vdu_id"]
7780 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007781 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007782 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007783 )
k4.rahulb827de92022-05-02 16:35:02 +00007784 if vdur:
7785 vdu_vim_name = vdur["name"]
7786 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7787 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007788 else:
7789 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007790 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7791 # wait for any previous tasks in process
7792 stage[1] = "Waiting for previous operations to terminate"
7793 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007794 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007795
7796 stage[1] = "Reading from database."
7797 self.logger.info(stage[1])
7798 self._write_ns_status(
7799 nsr_id=nsr_id,
7800 ns_state=None,
7801 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007802 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007803 )
7804 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7805
7806 # read from db: ns
7807 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7808 db_nsr_update["operational-status"] = operation_type
7809 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7810 # Payload for RO
7811 desc = {
7812 operation_type: {
7813 "vim_vm_id": vim_vm_id,
7814 "vnf_id": vnf_id,
7815 "vdu_index": additional_param["count-index"],
7816 "vdu_id": vdur["id"],
7817 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007818 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007819 }
7820 }
7821 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7822 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7823 self.logger.info("ro nsr id: {}".format(nsr_id))
7824 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7825 self.logger.info("response from RO: {}".format(result_dict))
7826 action_id = result_dict["action_id"]
7827 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007828 nsr_id,
7829 action_id,
7830 nslcmop_id,
7831 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007832 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007833 None,
7834 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007835 )
7836 return "COMPLETED", "Done"
7837 except (ROclient.ROClientException, DbException, LcmException) as e:
7838 self.logger.error("Exit Exception {}".format(e))
7839 exc = e
7840 except asyncio.CancelledError:
7841 self.logger.error("Cancelled Exception while '{}'".format(stage))
7842 exc = "Operation was cancelled"
7843 except Exception as e:
7844 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007845 self.logger.critical(
7846 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7847 )
k4.rahulb827de92022-05-02 16:35:02 +00007848 return "FAILED", "Error in operate VNF {}".format(exc)
7849
David Garciaaae391f2020-11-09 11:12:54 +01007850 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7851 """
7852 Get VCA Cloud and VCA Cloud Credentials for the VIM account
7853
7854 :param: vim_account_id: VIM Account ID
7855
7856 :return: (cloud_name, cloud_credential)
7857 """
bravof922c4172020-11-24 21:21:43 -03007858 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007859 return config.get("vca_cloud"), config.get("vca_cloud_credential")
7860
7861 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7862 """
7863 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
7864
7865 :param: vim_account_id: VIM Account ID
7866
7867 :return: (cloud_name, cloud_credential)
7868 """
bravof922c4172020-11-24 21:21:43 -03007869 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007870 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")
elumalai80bcf1c2022-04-28 18:05:01 +05307871
7872 async def migrate(self, nsr_id, nslcmop_id):
7873 """
7874 Migrate VNFs and VDUs instances in a NS
7875
7876 :param: nsr_id: NS Instance ID
7877 :param: nslcmop_id: nslcmop ID of migrate
7878
7879 """
7880 # Try to lock HA task here
7881 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7882 if not task_is_locked_by_me:
7883 return
7884 logging_text = "Task ns={} migrate ".format(nsr_id)
7885 self.logger.debug(logging_text + "Enter")
7886 # get all needed from database
7887 db_nslcmop = None
7888 db_nslcmop_update = {}
7889 nslcmop_operation_state = None
7890 db_nsr_update = {}
7891 target = {}
7892 exc = None
7893 # in case of error, indicates what part of scale was failed to put nsr at error status
7894 start_deploy = time()
7895
7896 try:
7897 # wait for any previous tasks in process
7898 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007899 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307900
7901 self._write_ns_status(
7902 nsr_id=nsr_id,
7903 ns_state=None,
7904 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007905 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307906 )
7907 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007908 self.logger.debug(
7909 step + " after having waited for previous tasks to be completed"
7910 )
elumalai80bcf1c2022-04-28 18:05:01 +05307911 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7912 migrate_params = db_nslcmop.get("operationParams")
7913
7914 target = {}
7915 target.update(migrate_params)
7916 desc = await self.RO.migrate(nsr_id, target)
7917 self.logger.debug("RO return > {}".format(desc))
7918 action_id = desc["action_id"]
7919 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007920 nsr_id,
7921 action_id,
7922 nslcmop_id,
7923 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007924 self.timeout.migrate,
preethika.p28b0bf82022-09-23 07:36:28 +00007925 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307926 )
7927 except (ROclient.ROClientException, DbException, LcmException) as e:
7928 self.logger.error("Exit Exception {}".format(e))
7929 exc = e
7930 except asyncio.CancelledError:
7931 self.logger.error("Cancelled Exception while '{}'".format(step))
7932 exc = "Operation was cancelled"
7933 except Exception as e:
7934 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007935 self.logger.critical(
7936 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7937 )
elumalai80bcf1c2022-04-28 18:05:01 +05307938 finally:
7939 self._write_ns_status(
7940 nsr_id=nsr_id,
7941 ns_state=None,
7942 current_operation="IDLE",
7943 current_operation_id=None,
7944 )
7945 if exc:
aticig349aa462022-05-19 12:29:35 +03007946 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05307947 nslcmop_operation_state = "FAILED"
7948 else:
7949 nslcmop_operation_state = "COMPLETED"
7950 db_nslcmop_update["detailed-status"] = "Done"
7951 db_nsr_update["detailed-status"] = "Done"
7952
7953 self._write_op_status(
7954 op_id=nslcmop_id,
7955 stage="",
7956 error_message="",
7957 operation_state=nslcmop_operation_state,
7958 other_update=db_nslcmop_update,
7959 )
7960 if nslcmop_operation_state:
7961 try:
7962 msg = {
7963 "nsr_id": nsr_id,
7964 "nslcmop_id": nslcmop_id,
7965 "operationState": nslcmop_operation_state,
7966 }
Gabriel Cubae7898982023-05-11 01:57:21 -05007967 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05307968 except Exception as e:
7969 self.logger.error(
7970 logging_text + "kafka_write notification Exception {}".format(e)
7971 )
7972 self.logger.debug(logging_text + "Exit")
7973 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007974
garciadeblas07f4e4c2022-06-09 09:42:58 +02007975 async def heal(self, nsr_id, nslcmop_id):
7976 """
7977 Heal NS
7978
7979 :param nsr_id: ns instance to heal
7980 :param nslcmop_id: operation to run
7981 :return:
7982 """
7983
7984 # Try to lock HA task here
7985 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7986 if not task_is_locked_by_me:
7987 return
7988
7989 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
7990 stage = ["", "", ""]
7991 tasks_dict_info = {}
7992 # ^ stage, step, VIM progress
7993 self.logger.debug(logging_text + "Enter")
7994 # get all needed from database
7995 db_nsr = None
7996 db_nslcmop_update = {}
7997 db_nsr_update = {}
7998 db_vnfrs = {} # vnf's info indexed by _id
7999 exc = None
8000 old_operational_status = ""
8001 old_config_status = ""
8002 nsi_id = None
8003 try:
8004 # wait for any previous tasks in process
8005 step = "Waiting for previous operations to terminate"
8006 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8007 self._write_ns_status(
8008 nsr_id=nsr_id,
8009 ns_state=None,
8010 current_operation="HEALING",
8011 current_operation_id=nslcmop_id,
8012 )
8013
8014 step = "Getting nslcmop from database"
8015 self.logger.debug(
8016 step + " after having waited for previous tasks to be completed"
8017 )
8018 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8019
8020 step = "Getting nsr from database"
8021 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8022 old_operational_status = db_nsr["operational-status"]
8023 old_config_status = db_nsr["config-status"]
8024
8025 db_nsr_update = {
8026 "_admin.deployed.RO.operational-status": "healing",
8027 }
8028 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8029
8030 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008031 await self.heal_RO(
8032 logging_text=logging_text,
8033 nsr_id=nsr_id,
8034 db_nslcmop=db_nslcmop,
8035 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008036 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008037 # VCA tasks
8038 # read from db: nsd
8039 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8040 self.logger.debug(logging_text + stage[1])
8041 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8042 self.fs.sync(db_nsr["nsd-id"])
8043 db_nsr["nsd"] = nsd
8044 # read from db: vnfr's of this ns
8045 step = "Getting vnfrs from db"
8046 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8047 for vnfr in db_vnfrs_list:
8048 db_vnfrs[vnfr["_id"]] = vnfr
8049 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8050
8051 # Check for each target VNF
8052 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8053 for target_vnf in target_list:
8054 # Find this VNF in the list from DB
8055 vnfr_id = target_vnf.get("vnfInstanceId", None)
8056 if vnfr_id:
8057 db_vnfr = db_vnfrs[vnfr_id]
8058 vnfd_id = db_vnfr.get("vnfd-id")
8059 vnfd_ref = db_vnfr.get("vnfd-ref")
8060 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8061 base_folder = vnfd["_admin"]["storage"]
8062 vdu_id = None
8063 vdu_index = 0
8064 vdu_name = None
8065 kdu_name = None
8066 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8067 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8068
8069 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008070 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8071 "vdu", []
8072 )
garciadeblas50639832022-09-01 13:09:47 +02008073 if not target_vdu_list:
8074 # Codigo nuevo para crear diccionario
8075 target_vdu_list = []
8076 for existing_vdu in db_vnfr.get("vdur"):
8077 vdu_name = existing_vdu.get("vdu-name", None)
8078 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008079 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8080 "run-day1", False
8081 )
8082 vdu_to_be_healed = {
8083 "vdu-id": vdu_name,
8084 "count-index": vdu_index,
8085 "run-day1": vdu_run_day1,
8086 }
garciadeblas50639832022-09-01 13:09:47 +02008087 target_vdu_list.append(vdu_to_be_healed)
8088 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008089 deploy_params_vdu = target_vdu
8090 # Set run-day1 vnf level value if not vdu level value exists
Gulsum Aticif4c1d2f2023-05-15 15:45:31 +03008091 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8092 "additionalParams", {}
8093 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008094 deploy_params_vdu["run-day1"] = target_vnf[
8095 "additionalParams"
8096 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008097 vdu_name = target_vdu.get("vdu-id", None)
8098 # TODO: Get vdu_id from vdud.
8099 vdu_id = vdu_name
8100 # For multi instance VDU count-index is mandatory
8101 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008102 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008103
8104 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8105 stage[1] = "Deploying Execution Environments."
8106 self.logger.debug(logging_text + stage[1])
8107
8108 # VNF Level charm. Normal case when proxy charms.
8109 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8110 descriptor_config = get_configuration(vnfd, vnfd_ref)
8111 if descriptor_config:
8112 # Continue if healed machine is management machine
8113 vnf_ip_address = db_vnfr.get("ip-address")
8114 target_instance = None
8115 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008116 if (
8117 instance["vdu-name"] == vdu_name
8118 and instance["count-index"] == vdu_index
8119 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008120 target_instance = instance
8121 break
8122 if vnf_ip_address == target_instance.get("ip-address"):
8123 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008124 logging_text=logging_text
8125 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8126 member_vnf_index, vdu_name, vdu_index
8127 ),
8128 db_nsr=db_nsr,
8129 db_vnfr=db_vnfr,
8130 nslcmop_id=nslcmop_id,
8131 nsr_id=nsr_id,
8132 nsi_id=nsi_id,
8133 vnfd_id=vnfd_ref,
8134 vdu_id=None,
8135 kdu_name=None,
8136 member_vnf_index=member_vnf_index,
8137 vdu_index=0,
8138 vdu_name=None,
8139 deploy_params=deploy_params_vdu,
8140 descriptor_config=descriptor_config,
8141 base_folder=base_folder,
8142 task_instantiation_info=tasks_dict_info,
8143 stage=stage,
8144 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008145
8146 # VDU Level charm. Normal case with native charms.
8147 descriptor_config = get_configuration(vnfd, vdu_name)
8148 if descriptor_config:
8149 self._heal_n2vc(
8150 logging_text=logging_text
8151 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8152 member_vnf_index, vdu_name, vdu_index
8153 ),
8154 db_nsr=db_nsr,
8155 db_vnfr=db_vnfr,
8156 nslcmop_id=nslcmop_id,
8157 nsr_id=nsr_id,
8158 nsi_id=nsi_id,
8159 vnfd_id=vnfd_ref,
8160 vdu_id=vdu_id,
8161 kdu_name=kdu_name,
8162 member_vnf_index=member_vnf_index,
8163 vdu_index=vdu_index,
8164 vdu_name=vdu_name,
8165 deploy_params=deploy_params_vdu,
8166 descriptor_config=descriptor_config,
8167 base_folder=base_folder,
8168 task_instantiation_info=tasks_dict_info,
8169 stage=stage,
8170 )
8171
8172 except (
8173 ROclient.ROClientException,
8174 DbException,
8175 LcmException,
8176 NgRoException,
8177 ) as e:
8178 self.logger.error(logging_text + "Exit Exception {}".format(e))
8179 exc = e
8180 except asyncio.CancelledError:
8181 self.logger.error(
8182 logging_text + "Cancelled Exception while '{}'".format(step)
8183 )
8184 exc = "Operation was cancelled"
8185 except Exception as e:
8186 exc = traceback.format_exc()
8187 self.logger.critical(
8188 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8189 exc_info=True,
8190 )
8191 finally:
8192 if tasks_dict_info:
8193 stage[1] = "Waiting for healing pending tasks."
8194 self.logger.debug(logging_text + stage[1])
8195 exc = await self._wait_for_tasks(
8196 logging_text,
8197 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008198 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008199 stage,
8200 nslcmop_id,
8201 nsr_id=nsr_id,
8202 )
8203 if exc:
8204 db_nslcmop_update[
8205 "detailed-status"
8206 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
8207 nslcmop_operation_state = "FAILED"
8208 if db_nsr:
8209 db_nsr_update["operational-status"] = old_operational_status
8210 db_nsr_update["config-status"] = old_config_status
8211 db_nsr_update[
8212 "detailed-status"
preethika.p28b0bf82022-09-23 07:36:28 +00008213 ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008214 for task, task_name in tasks_dict_info.items():
8215 if not task.done() or task.cancelled() or task.exception():
8216 if task_name.startswith(self.task_name_deploy_vca):
8217 # A N2VC task is pending
8218 db_nsr_update["config-status"] = "failed"
8219 else:
8220 # RO task is pending
8221 db_nsr_update["operational-status"] = "failed"
8222 else:
8223 error_description_nslcmop = None
8224 nslcmop_operation_state = "COMPLETED"
8225 db_nslcmop_update["detailed-status"] = "Done"
8226 db_nsr_update["detailed-status"] = "Done"
8227 db_nsr_update["operational-status"] = "running"
8228 db_nsr_update["config-status"] = "configured"
8229
8230 self._write_op_status(
8231 op_id=nslcmop_id,
8232 stage="",
8233 error_message=error_description_nslcmop,
8234 operation_state=nslcmop_operation_state,
8235 other_update=db_nslcmop_update,
8236 )
8237 if db_nsr:
8238 self._write_ns_status(
8239 nsr_id=nsr_id,
8240 ns_state=None,
8241 current_operation="IDLE",
8242 current_operation_id=None,
8243 other_update=db_nsr_update,
8244 )
8245
8246 if nslcmop_operation_state:
8247 try:
8248 msg = {
8249 "nsr_id": nsr_id,
8250 "nslcmop_id": nslcmop_id,
8251 "operationState": nslcmop_operation_state,
8252 }
Gabriel Cubae7898982023-05-11 01:57:21 -05008253 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008254 except Exception as e:
8255 self.logger.error(
8256 logging_text + "kafka_write notification Exception {}".format(e)
8257 )
8258 self.logger.debug(logging_text + "Exit")
8259 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8260
8261 async def heal_RO(
8262 self,
8263 logging_text,
8264 nsr_id,
8265 db_nslcmop,
8266 stage,
8267 ):
8268 """
8269 Heal at RO
8270 :param logging_text: preffix text to use at logging
8271 :param nsr_id: nsr identity
8272 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8273 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8274 :return: None or exception
8275 """
preethika.p28b0bf82022-09-23 07:36:28 +00008276
garciadeblas07f4e4c2022-06-09 09:42:58 +02008277 def get_vim_account(vim_account_id):
8278 nonlocal db_vims
8279 if vim_account_id in db_vims:
8280 return db_vims[vim_account_id]
8281 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8282 db_vims[vim_account_id] = db_vim
8283 return db_vim
8284
8285 try:
8286 start_heal = time()
8287 ns_params = db_nslcmop.get("operationParams")
8288 if ns_params and ns_params.get("timeout_ns_heal"):
8289 timeout_ns_heal = ns_params["timeout_ns_heal"]
8290 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008291 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008292
8293 db_vims = {}
8294
8295 nslcmop_id = db_nslcmop["_id"]
8296 target = {
8297 "action_id": nslcmop_id,
8298 }
preethika.p28b0bf82022-09-23 07:36:28 +00008299 self.logger.warning(
8300 "db_nslcmop={} and timeout_ns_heal={}".format(
8301 db_nslcmop, timeout_ns_heal
8302 )
8303 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008304 target.update(db_nslcmop.get("operationParams", {}))
8305
8306 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8307 desc = await self.RO.recreate(nsr_id, target)
8308 self.logger.debug("RO return > {}".format(desc))
8309 action_id = desc["action_id"]
8310 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8311 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008312 nsr_id,
8313 action_id,
8314 nslcmop_id,
8315 start_heal,
8316 timeout_ns_heal,
8317 stage,
8318 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008319 )
8320
8321 # Updating NSR
8322 db_nsr_update = {
8323 "_admin.deployed.RO.operational-status": "running",
8324 "detailed-status": " ".join(stage),
8325 }
8326 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8327 self._write_op_status(nslcmop_id, stage)
8328 self.logger.debug(
8329 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8330 )
8331
8332 except Exception as e:
8333 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008334 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008335 self.logger.error(
8336 "Error healing at VIM {}".format(e),
8337 exc_info=not isinstance(
8338 e,
8339 (
8340 ROclient.ROClientException,
8341 LcmException,
8342 DbException,
8343 NgRoException,
8344 ),
8345 ),
8346 )
8347 raise
8348
8349 def _heal_n2vc(
8350 self,
8351 logging_text,
8352 db_nsr,
8353 db_vnfr,
8354 nslcmop_id,
8355 nsr_id,
8356 nsi_id,
8357 vnfd_id,
8358 vdu_id,
8359 kdu_name,
8360 member_vnf_index,
8361 vdu_index,
8362 vdu_name,
8363 deploy_params,
8364 descriptor_config,
8365 base_folder,
8366 task_instantiation_info,
8367 stage,
8368 ):
8369 # launch instantiate_N2VC in a asyncio task and register task object
8370 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8371 # if not found, create one entry and update database
8372 # fill db_nsr._admin.deployed.VCA.<index>
8373
8374 self.logger.debug(
8375 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8376 )
aticig9bc63ac2022-07-27 09:32:06 +03008377
8378 charm_name = ""
8379 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008380 if "execution-environment-list" in descriptor_config:
8381 ee_list = descriptor_config.get("execution-environment-list", [])
8382 elif "juju" in descriptor_config:
8383 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008384 if "execution-environment-list" not in descriptor_config:
8385 # charm name is only required for ns charms
8386 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008387 else: # other types as script are not supported
8388 ee_list = []
8389
8390 for ee_item in ee_list:
8391 self.logger.debug(
8392 logging_text
8393 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8394 ee_item.get("juju"), ee_item.get("helm-chart")
8395 )
8396 )
8397 ee_descriptor_id = ee_item.get("id")
8398 if ee_item.get("juju"):
8399 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03008400 if get_charm_name:
8401 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008402 vca_type = (
8403 "lxc_proxy_charm"
8404 if ee_item["juju"].get("charm") is not None
8405 else "native_charm"
8406 )
8407 if ee_item["juju"].get("cloud") == "k8s":
8408 vca_type = "k8s_proxy_charm"
8409 elif ee_item["juju"].get("proxy") is False:
8410 vca_type = "native_charm"
8411 elif ee_item.get("helm-chart"):
8412 vca_name = ee_item["helm-chart"]
8413 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
8414 vca_type = "helm"
8415 else:
8416 vca_type = "helm-v3"
8417 else:
8418 self.logger.debug(
8419 logging_text + "skipping non juju neither charm configuration"
8420 )
8421 continue
8422
8423 vca_index = -1
8424 for vca_index, vca_deployed in enumerate(
8425 db_nsr["_admin"]["deployed"]["VCA"]
8426 ):
8427 if not vca_deployed:
8428 continue
8429 if (
8430 vca_deployed.get("member-vnf-index") == member_vnf_index
8431 and vca_deployed.get("vdu_id") == vdu_id
8432 and vca_deployed.get("kdu_name") == kdu_name
8433 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8434 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8435 ):
8436 break
8437 else:
8438 # not found, create one.
8439 target = (
8440 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8441 )
8442 if vdu_id:
8443 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8444 elif kdu_name:
8445 target += "/kdu/{}".format(kdu_name)
8446 vca_deployed = {
8447 "target_element": target,
8448 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8449 "member-vnf-index": member_vnf_index,
8450 "vdu_id": vdu_id,
8451 "kdu_name": kdu_name,
8452 "vdu_count_index": vdu_index,
8453 "operational-status": "init", # TODO revise
8454 "detailed-status": "", # TODO revise
8455 "step": "initial-deploy", # TODO revise
8456 "vnfd_id": vnfd_id,
8457 "vdu_name": vdu_name,
8458 "type": vca_type,
8459 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008460 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008461 }
8462 vca_index += 1
8463
8464 # create VCA and configurationStatus in db
8465 db_dict = {
8466 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8467 "configurationStatus.{}".format(vca_index): dict(),
8468 }
8469 self.update_db_2("nsrs", nsr_id, db_dict)
8470
8471 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8472
8473 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8474 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8475 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8476
8477 # Launch task
8478 task_n2vc = asyncio.ensure_future(
8479 self.heal_N2VC(
8480 logging_text=logging_text,
8481 vca_index=vca_index,
8482 nsi_id=nsi_id,
8483 db_nsr=db_nsr,
8484 db_vnfr=db_vnfr,
8485 vdu_id=vdu_id,
8486 kdu_name=kdu_name,
8487 vdu_index=vdu_index,
8488 deploy_params=deploy_params,
8489 config_descriptor=descriptor_config,
8490 base_folder=base_folder,
8491 nslcmop_id=nslcmop_id,
8492 stage=stage,
8493 vca_type=vca_type,
8494 vca_name=vca_name,
8495 ee_config_descriptor=ee_item,
8496 )
8497 )
8498 self.lcm_tasks.register(
8499 "ns",
8500 nsr_id,
8501 nslcmop_id,
8502 "instantiate_N2VC-{}".format(vca_index),
8503 task_n2vc,
8504 )
8505 task_instantiation_info[
8506 task_n2vc
8507 ] = self.task_name_deploy_vca + " {}.{}".format(
8508 member_vnf_index or "", vdu_id or ""
8509 )
8510
8511 async def heal_N2VC(
8512 self,
8513 logging_text,
8514 vca_index,
8515 nsi_id,
8516 db_nsr,
8517 db_vnfr,
8518 vdu_id,
8519 kdu_name,
8520 vdu_index,
8521 config_descriptor,
8522 deploy_params,
8523 base_folder,
8524 nslcmop_id,
8525 stage,
8526 vca_type,
8527 vca_name,
8528 ee_config_descriptor,
8529 ):
8530 nsr_id = db_nsr["_id"]
8531 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8532 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8533 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8534 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8535 db_dict = {
8536 "collection": "nsrs",
8537 "filter": {"_id": nsr_id},
8538 "path": db_update_entry,
8539 }
8540 step = ""
8541 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008542 element_type = "NS"
8543 element_under_configuration = nsr_id
8544
8545 vnfr_id = None
8546 if db_vnfr:
8547 vnfr_id = db_vnfr["_id"]
8548 osm_config["osm"]["vnf_id"] = vnfr_id
8549
8550 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8551
8552 if vca_type == "native_charm":
8553 index_number = 0
8554 else:
8555 index_number = vdu_index or 0
8556
8557 if vnfr_id:
8558 element_type = "VNF"
8559 element_under_configuration = vnfr_id
8560 namespace += ".{}-{}".format(vnfr_id, index_number)
8561 if vdu_id:
8562 namespace += ".{}-{}".format(vdu_id, index_number)
8563 element_type = "VDU"
8564 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8565 osm_config["osm"]["vdu_id"] = vdu_id
8566 elif kdu_name:
8567 namespace += ".{}".format(kdu_name)
8568 element_type = "KDU"
8569 element_under_configuration = kdu_name
8570 osm_config["osm"]["kdu_name"] = kdu_name
8571
8572 # Get artifact path
8573 if base_folder["pkg-dir"]:
8574 artifact_path = "{}/{}/{}/{}".format(
8575 base_folder["folder"],
8576 base_folder["pkg-dir"],
8577 "charms"
8578 if vca_type
8579 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8580 else "helm-charts",
8581 vca_name,
8582 )
8583 else:
8584 artifact_path = "{}/Scripts/{}/{}/".format(
8585 base_folder["folder"],
8586 "charms"
8587 if vca_type
8588 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8589 else "helm-charts",
8590 vca_name,
8591 )
8592
8593 self.logger.debug("Artifact path > {}".format(artifact_path))
8594
8595 # get initial_config_primitive_list that applies to this element
8596 initial_config_primitive_list = config_descriptor.get(
8597 "initial-config-primitive"
8598 )
8599
8600 self.logger.debug(
8601 "Initial config primitive list > {}".format(
8602 initial_config_primitive_list
8603 )
8604 )
8605
8606 # add config if not present for NS charm
8607 ee_descriptor_id = ee_config_descriptor.get("id")
8608 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8609 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8610 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8611 )
8612
8613 self.logger.debug(
8614 "Initial config primitive list #2 > {}".format(
8615 initial_config_primitive_list
8616 )
8617 )
8618 # n2vc_redesign STEP 3.1
8619 # find old ee_id if exists
8620 ee_id = vca_deployed.get("ee_id")
8621
8622 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8623 # create or register execution environment in VCA. Only for native charms when healing
8624 if vca_type == "native_charm":
8625 step = "Waiting to VM being up and getting IP address"
8626 self.logger.debug(logging_text + step)
8627 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8628 logging_text,
8629 nsr_id,
8630 vnfr_id,
8631 vdu_id,
8632 vdu_index,
8633 user=None,
8634 pub_key=None,
8635 )
8636 credentials = {"hostname": rw_mgmt_ip}
8637 # get username
8638 username = deep_get(
8639 config_descriptor, ("config-access", "ssh-access", "default-user")
8640 )
8641 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8642 # merged. Meanwhile let's get username from initial-config-primitive
8643 if not username and initial_config_primitive_list:
8644 for config_primitive in initial_config_primitive_list:
8645 for param in config_primitive.get("parameter", ()):
8646 if param["name"] == "ssh-username":
8647 username = param["value"]
8648 break
8649 if not username:
8650 raise LcmException(
8651 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8652 "'config-access.ssh-access.default-user'"
8653 )
8654 credentials["username"] = username
8655
8656 # n2vc_redesign STEP 3.2
8657 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8658 self._write_configuration_status(
8659 nsr_id=nsr_id,
8660 vca_index=vca_index,
8661 status="REGISTERING",
8662 element_under_configuration=element_under_configuration,
8663 element_type=element_type,
8664 )
8665
8666 step = "register execution environment {}".format(credentials)
8667 self.logger.debug(logging_text + step)
8668 ee_id = await self.vca_map[vca_type].register_execution_environment(
8669 credentials=credentials,
8670 namespace=namespace,
8671 db_dict=db_dict,
8672 vca_id=vca_id,
8673 )
8674
8675 # update ee_id en db
8676 db_dict_ee_id = {
8677 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8678 }
8679 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8680
8681 # for compatibility with MON/POL modules, the need model and application name at database
8682 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8683 # Not sure if this need to be done when healing
8684 """
8685 ee_id_parts = ee_id.split(".")
8686 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8687 if len(ee_id_parts) >= 2:
8688 model_name = ee_id_parts[0]
8689 application_name = ee_id_parts[1]
8690 db_nsr_update[db_update_entry + "model"] = model_name
8691 db_nsr_update[db_update_entry + "application"] = application_name
8692 """
8693
8694 # n2vc_redesign STEP 3.3
8695 # Install configuration software. Only for native charms.
8696 step = "Install configuration Software"
8697
8698 self._write_configuration_status(
8699 nsr_id=nsr_id,
8700 vca_index=vca_index,
8701 status="INSTALLING SW",
8702 element_under_configuration=element_under_configuration,
8703 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008704 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008705 other_update=None,
8706 )
8707
8708 # TODO check if already done
8709 self.logger.debug(logging_text + step)
8710 config = None
8711 if vca_type == "native_charm":
8712 config_primitive = next(
8713 (p for p in initial_config_primitive_list if p["name"] == "config"),
8714 None,
8715 )
8716 if config_primitive:
8717 config = self._map_primitive_params(
8718 config_primitive, {}, deploy_params
8719 )
8720 await self.vca_map[vca_type].install_configuration_sw(
8721 ee_id=ee_id,
8722 artifact_path=artifact_path,
8723 db_dict=db_dict,
8724 config=config,
8725 num_units=1,
8726 vca_id=vca_id,
8727 vca_type=vca_type,
8728 )
8729
8730 # write in db flag of configuration_sw already installed
8731 self.update_db_2(
8732 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8733 )
8734
8735 # Not sure if this need to be done when healing
8736 """
8737 # add relations for this VCA (wait for other peers related with this VCA)
8738 await self._add_vca_relations(
8739 logging_text=logging_text,
8740 nsr_id=nsr_id,
8741 vca_type=vca_type,
8742 vca_index=vca_index,
8743 )
8744 """
8745
8746 # if SSH access is required, then get execution environment SSH public
8747 # if native charm we have waited already to VM be UP
8748 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
8749 pub_key = None
8750 user = None
8751 # self.logger.debug("get ssh key block")
8752 if deep_get(
8753 config_descriptor, ("config-access", "ssh-access", "required")
8754 ):
8755 # self.logger.debug("ssh key needed")
8756 # Needed to inject a ssh key
8757 user = deep_get(
8758 config_descriptor,
8759 ("config-access", "ssh-access", "default-user"),
8760 )
8761 step = "Install configuration Software, getting public ssh key"
8762 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8763 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8764 )
8765
8766 step = "Insert public key into VM user={} ssh_key={}".format(
8767 user, pub_key
8768 )
8769 else:
8770 # self.logger.debug("no need to get ssh key")
8771 step = "Waiting to VM being up and getting IP address"
8772 self.logger.debug(logging_text + step)
8773
8774 # n2vc_redesign STEP 5.1
8775 # wait for RO (ip-address) Insert pub_key into VM
8776 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008777 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008778 if vnfr_id:
8779 if kdu_name:
8780 rw_mgmt_ip = await self.wait_kdu_up(
8781 logging_text, nsr_id, vnfr_id, kdu_name
8782 )
8783 else:
8784 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8785 logging_text,
8786 nsr_id,
8787 vnfr_id,
8788 vdu_id,
8789 vdu_index,
8790 user=user,
8791 pub_key=pub_key,
8792 )
8793 else:
8794 rw_mgmt_ip = None # This is for a NS configuration
8795
8796 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8797
8798 # store rw_mgmt_ip in deploy params for later replacement
8799 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8800
8801 # Day1 operations.
8802 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008803 runDay1 = deploy_params.get("run-day1", False)
8804 self.logger.debug(
8805 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8806 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008807 if runDay1:
8808 # n2vc_redesign STEP 6 Execute initial config primitive
8809 step = "execute initial config primitive"
8810
8811 # wait for dependent primitives execution (NS -> VNF -> VDU)
8812 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008813 await self._wait_dependent_n2vc(
8814 nsr_id, vca_deployed_list, vca_index
8815 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008816
8817 # stage, in function of element type: vdu, kdu, vnf or ns
8818 my_vca = vca_deployed_list[vca_index]
8819 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8820 # VDU or KDU
8821 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8822 elif my_vca.get("member-vnf-index"):
8823 # VNF
8824 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8825 else:
8826 # NS
8827 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8828
8829 self._write_configuration_status(
8830 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8831 )
8832
8833 self._write_op_status(op_id=nslcmop_id, stage=stage)
8834
8835 check_if_terminated_needed = True
8836 for initial_config_primitive in initial_config_primitive_list:
8837 # adding information on the vca_deployed if it is a NS execution environment
8838 if not vca_deployed["member-vnf-index"]:
8839 deploy_params["ns_config_info"] = json.dumps(
8840 self._get_ns_config_info(nsr_id)
8841 )
8842 # TODO check if already done
8843 primitive_params_ = self._map_primitive_params(
8844 initial_config_primitive, {}, deploy_params
8845 )
8846
8847 step = "execute primitive '{}' params '{}'".format(
8848 initial_config_primitive["name"], primitive_params_
8849 )
8850 self.logger.debug(logging_text + step)
8851 await self.vca_map[vca_type].exec_primitive(
8852 ee_id=ee_id,
8853 primitive_name=initial_config_primitive["name"],
8854 params_dict=primitive_params_,
8855 db_dict=db_dict,
8856 vca_id=vca_id,
8857 vca_type=vca_type,
8858 )
8859 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8860 if check_if_terminated_needed:
8861 if config_descriptor.get("terminate-config-primitive"):
8862 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008863 "nsrs",
8864 nsr_id,
8865 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008866 )
8867 check_if_terminated_needed = False
8868
8869 # TODO register in database that primitive is done
8870
8871 # STEP 7 Configure metrics
8872 # Not sure if this need to be done when healing
8873 """
8874 if vca_type == "helm" or vca_type == "helm-v3":
8875 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8876 ee_id=ee_id,
8877 artifact_path=artifact_path,
8878 ee_config_descriptor=ee_config_descriptor,
8879 vnfr_id=vnfr_id,
8880 nsr_id=nsr_id,
8881 target_ip=rw_mgmt_ip,
8882 )
8883 if prometheus_jobs:
8884 self.update_db_2(
8885 "nsrs",
8886 nsr_id,
8887 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8888 )
8889
8890 for job in prometheus_jobs:
8891 self.db.set_one(
8892 "prometheus_jobs",
8893 {"job_name": job["job_name"]},
8894 job,
8895 upsert=True,
8896 fail_on_empty=False,
8897 )
8898
8899 """
8900 step = "instantiated at VCA"
8901 self.logger.debug(logging_text + step)
8902
8903 self._write_configuration_status(
8904 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8905 )
8906
8907 except Exception as e: # TODO not use Exception but N2VC exception
8908 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8909 if not isinstance(
8910 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8911 ):
8912 self.logger.error(
8913 "Exception while {} : {}".format(step, e), exc_info=True
8914 )
8915 self._write_configuration_status(
8916 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8917 )
8918 raise LcmException("{} {}".format(step, e)) from e
8919
8920 async def _wait_heal_ro(
8921 self,
8922 nsr_id,
8923 timeout=600,
8924 ):
8925 start_time = time()
8926 while time() <= start_time + timeout:
8927 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00008928 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
8929 "operational-status"
8930 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02008931 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
8932 if operational_status_ro != "healing":
8933 break
Gabriel Cubae7898982023-05-11 01:57:21 -05008934 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008935 else: # timeout_ns_deploy
8936 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05308937
8938 async def vertical_scale(self, nsr_id, nslcmop_id):
8939 """
8940 Vertical Scale the VDUs in a NS
8941
8942 :param: nsr_id: NS Instance ID
8943 :param: nslcmop_id: nslcmop ID of migrate
8944
8945 """
8946 # Try to lock HA task here
8947 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8948 if not task_is_locked_by_me:
8949 return
8950 logging_text = "Task ns={} vertical scale ".format(nsr_id)
8951 self.logger.debug(logging_text + "Enter")
8952 # get all needed from database
8953 db_nslcmop = None
8954 db_nslcmop_update = {}
8955 nslcmop_operation_state = None
8956 db_nsr_update = {}
8957 target = {}
8958 exc = None
8959 # in case of error, indicates what part of scale was failed to put nsr at error status
8960 start_deploy = time()
8961
8962 try:
8963 # wait for any previous tasks in process
8964 step = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00008965 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05308966
8967 self._write_ns_status(
8968 nsr_id=nsr_id,
8969 ns_state=None,
8970 current_operation="VerticalScale",
preethika.p28b0bf82022-09-23 07:36:28 +00008971 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05308972 )
8973 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00008974 self.logger.debug(
8975 step + " after having waited for previous tasks to be completed"
8976 )
govindarajul4ff4b512022-05-02 20:02:41 +05308977 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8978 operationParams = db_nslcmop.get("operationParams")
8979 target = {}
8980 target.update(operationParams)
8981 desc = await self.RO.vertical_scale(nsr_id, target)
8982 self.logger.debug("RO return > {}".format(desc))
8983 action_id = desc["action_id"]
8984 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008985 nsr_id,
8986 action_id,
8987 nslcmop_id,
8988 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00008989 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00008990 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05308991 )
8992 except (ROclient.ROClientException, DbException, LcmException) as e:
8993 self.logger.error("Exit Exception {}".format(e))
8994 exc = e
8995 except asyncio.CancelledError:
8996 self.logger.error("Cancelled Exception while '{}'".format(step))
8997 exc = "Operation was cancelled"
8998 except Exception as e:
8999 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00009000 self.logger.critical(
9001 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
9002 )
govindarajul4ff4b512022-05-02 20:02:41 +05309003 finally:
9004 self._write_ns_status(
9005 nsr_id=nsr_id,
9006 ns_state=None,
9007 current_operation="IDLE",
9008 current_operation_id=None,
9009 )
9010 if exc:
preethika.p28b0bf82022-09-23 07:36:28 +00009011 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
govindarajul4ff4b512022-05-02 20:02:41 +05309012 nslcmop_operation_state = "FAILED"
9013 else:
9014 nslcmop_operation_state = "COMPLETED"
9015 db_nslcmop_update["detailed-status"] = "Done"
9016 db_nsr_update["detailed-status"] = "Done"
9017
9018 self._write_op_status(
9019 op_id=nslcmop_id,
9020 stage="",
9021 error_message="",
9022 operation_state=nslcmop_operation_state,
9023 other_update=db_nslcmop_update,
9024 )
9025 if nslcmop_operation_state:
9026 try:
9027 msg = {
9028 "nsr_id": nsr_id,
9029 "nslcmop_id": nslcmop_id,
9030 "operationState": nslcmop_operation_state,
9031 }
Gabriel Cubae7898982023-05-11 01:57:21 -05009032 await self.msg.aiowrite("ns", "verticalscaled", msg)
govindarajul4ff4b512022-05-02 20:02:41 +05309033 except Exception as e:
9034 self.logger.error(
9035 logging_text + "kafka_write notification Exception {}".format(e)
9036 )
9037 self.logger.debug(logging_text + "Exit")
9038 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")