blob: 999aee670f1c9b818144e50b9160b954689da3d8 [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,
Dario Faccin1df4ede2023-06-01 10:15:34 +020064 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
Dario Faccin1df4ede2023-06-01 10:15:34 +0200127from 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
Dario Faccin1df4ede2023-06-01 10:15:34 +0200136 EE_TLS_NAME = "ee-tls"
tiernoa2143262020-03-27 16:20:40 +0000137 task_name_deploy_vca = "Deploying VCA"
Dario Faccin1df4ede2023-06-01 10:15:34 +0200138 rel_operation_types = {
139 "GE": ">=",
140 "LE": "<=",
141 "GT": ">",
142 "LT": "<",
143 "EQ": "==",
144 "NE": "!=",
145 }
kuuseac3a8882019-10-03 10:48:06 +0200146
Dario Faccin1df4ede2023-06-01 10:15:34 +0200147 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
Dario Faccin1df4ede2023-06-01 10:15:34 +0200220 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"):
Dario Faccin1df4ede2023-06-01 10:15:34 +0200840 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:
907 return
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"] = {}
Dario Faccin1df4ede2023-06-01 10:15:34 +0200975 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 ):
Dario Faccin1df4ede2023-06-01 10:15:34 +02001057 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 ):
Dario Faccin1df4ede2023-06-01 10:15:34 +02001125 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
Dario Faccin1df4ede2023-06-01 10:15:34 +02001249 # 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
Dario Faccin1df4ede2023-06-01 10:15:34 +02001271 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)
Dario Faccin1df4ede2023-06-01 10:15:34 +02001339 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
Dario Faccin1df4ede2023-06-01 10:15:34 +02001525 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
Dario Faccin1df4ede2023-06-01 10:15:34 +02001556 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(
Dario Faccin1df4ede2023-06-01 10:15:34 +02001842 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 )
Dario Faccin1df4ede2023-06-01 10:15:34 +02002317 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
Dario Faccin1df4ede2023-06-01 10:15:34 +02002346 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:
2393 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")
2439 metric_name = f"osm_{metric_name}"
2440 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 ]
2468 rel_operator = self.rel_operation_types.get(
2469 operation, "<="
2470 )
2471 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 ]
2511 rel_operator = self.rel_operation_types.get(
2512 operation, "<="
2513 )
2514 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
2549 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}"}}'
2600 expression = f"{metric_selector} {rel_operator} {metric_threshold}"
2601 labels = {
2602 "ns_id": nsr_id,
2603 "vnf_member_index": vnf_member_index,
2604 "vdu_id": vdu_id,
2605 "vdu_name": "{{ $labels.vdu_name }}",
2606 }
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 ):
2619 alarm_action[action_type] = alarm_descriptor["actions"][
2620 action_type
2621 ]
2622 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):
Dario Faccin1df4ede2023-06-01 10:15:34 +02002848 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(
Dario Faccin1df4ede2023-06-01 10:15:34 +02002853 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",
Dario Faccin1df4ede2023-06-01 10:15:34 +02002857 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
Dario Faccin1df4ede2023-06-01 10:15:34 +02002993 # 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"
Dario Faccin1df4ede2023-06-01 10:15:34 +02003175 # 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)
quilesj4cda56b2019-12-05 10:02:20 +00003186
Dario Faccin1df4ede2023-06-01 10:15:34 +02003187 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)
3191
3192 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,
3223 },
garciadeblas5697b8b2021-03-24 09:17:02 +01003224 )
tierno59d22d22018-09-25 18:10:19 +02003225 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003226 self.logger.error(
3227 logging_text + "kafka_write notification Exception {}".format(e)
3228 )
tierno59d22d22018-09-25 18:10:19 +02003229
3230 self.logger.debug(logging_text + "Exit")
3231 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
3232
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003233 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02003234 if vnfd_id not in cached_vnfds:
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003235 cached_vnfds[vnfd_id] = self.db.get_one(
3236 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
3237 )
David Garciab4ebcd02021-10-28 02:00:43 +02003238 return cached_vnfds[vnfd_id]
3239
3240 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
3241 if vnf_profile_id not in cached_vnfrs:
3242 cached_vnfrs[vnf_profile_id] = self.db.get_one(
3243 "vnfrs",
3244 {
3245 "member-vnf-index-ref": vnf_profile_id,
3246 "nsr-id-ref": nsr_id,
3247 },
3248 )
3249 return cached_vnfrs[vnf_profile_id]
3250
3251 def _is_deployed_vca_in_relation(
3252 self, vca: DeployedVCA, relation: Relation
3253 ) -> bool:
3254 found = False
3255 for endpoint in (relation.provider, relation.requirer):
3256 if endpoint["kdu-resource-profile-id"]:
3257 continue
3258 found = (
3259 vca.vnf_profile_id == endpoint.vnf_profile_id
3260 and vca.vdu_profile_id == endpoint.vdu_profile_id
3261 and vca.execution_environment_ref == endpoint.execution_environment_ref
3262 )
3263 if found:
3264 break
3265 return found
3266
3267 def _update_ee_relation_data_with_implicit_data(
3268 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
3269 ):
3270 ee_relation_data = safe_get_ee_relation(
3271 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
3272 )
3273 ee_relation_level = EELevel.get_level(ee_relation_data)
3274 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
3275 "execution-environment-ref"
3276 ]:
3277 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
3278 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003279 project = nsd["_admin"]["projects_read"][0]
3280 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003281 entity_id = (
3282 vnfd_id
3283 if ee_relation_level == EELevel.VNF
3284 else ee_relation_data["vdu-profile-id"]
3285 )
3286 ee = get_juju_ee_ref(db_vnfd, entity_id)
3287 if not ee:
3288 raise Exception(
3289 f"not execution environments found for ee_relation {ee_relation_data}"
3290 )
3291 ee_relation_data["execution-environment-ref"] = ee["id"]
3292 return ee_relation_data
3293
3294 def _get_ns_relations(
3295 self,
3296 nsr_id: str,
3297 nsd: Dict[str, Any],
3298 vca: DeployedVCA,
3299 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003300 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003301 relations = []
3302 db_ns_relations = get_ns_configuration_relation_list(nsd)
3303 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003304 provider_dict = None
3305 requirer_dict = None
3306 if all(key in r for key in ("provider", "requirer")):
3307 provider_dict = r["provider"]
3308 requirer_dict = r["requirer"]
3309 elif "entities" in r:
3310 provider_id = r["entities"][0]["id"]
3311 provider_dict = {
3312 "nsr-id": nsr_id,
3313 "endpoint": r["entities"][0]["endpoint"],
3314 }
3315 if provider_id != nsd["id"]:
3316 provider_dict["vnf-profile-id"] = provider_id
3317 requirer_id = r["entities"][1]["id"]
3318 requirer_dict = {
3319 "nsr-id": nsr_id,
3320 "endpoint": r["entities"][1]["endpoint"],
3321 }
3322 if requirer_id != nsd["id"]:
3323 requirer_dict["vnf-profile-id"] = requirer_id
3324 else:
aticig15db6142022-01-24 12:51:26 +03003325 raise Exception(
3326 "provider/requirer or entities must be included in the relation."
3327 )
David Garciab4ebcd02021-10-28 02:00:43 +02003328 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003329 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003330 )
3331 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003332 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003333 )
3334 provider = EERelation(relation_provider)
3335 requirer = EERelation(relation_requirer)
3336 relation = Relation(r["name"], provider, requirer)
3337 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3338 if vca_in_relation:
3339 relations.append(relation)
3340 return relations
3341
3342 def _get_vnf_relations(
3343 self,
3344 nsr_id: str,
3345 nsd: Dict[str, Any],
3346 vca: DeployedVCA,
3347 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003348 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003349 relations = []
Patricia Reinosoceb03862023-01-12 09:40:53 +00003350 if vca.target_element == "ns":
3351 self.logger.debug("VCA is a NS charm, not a VNF.")
3352 return relations
David Garciab4ebcd02021-10-28 02:00:43 +02003353 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3354 vnf_profile_id = vnf_profile["id"]
3355 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003356 project = nsd["_admin"]["projects_read"][0]
3357 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003358 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3359 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003360 provider_dict = None
3361 requirer_dict = None
3362 if all(key in r for key in ("provider", "requirer")):
3363 provider_dict = r["provider"]
3364 requirer_dict = r["requirer"]
3365 elif "entities" in r:
3366 provider_id = r["entities"][0]["id"]
3367 provider_dict = {
3368 "nsr-id": nsr_id,
3369 "vnf-profile-id": vnf_profile_id,
3370 "endpoint": r["entities"][0]["endpoint"],
3371 }
3372 if provider_id != vnfd_id:
3373 provider_dict["vdu-profile-id"] = provider_id
3374 requirer_id = r["entities"][1]["id"]
3375 requirer_dict = {
3376 "nsr-id": nsr_id,
3377 "vnf-profile-id": vnf_profile_id,
3378 "endpoint": r["entities"][1]["endpoint"],
3379 }
3380 if requirer_id != vnfd_id:
3381 requirer_dict["vdu-profile-id"] = requirer_id
3382 else:
aticig15db6142022-01-24 12:51:26 +03003383 raise Exception(
3384 "provider/requirer or entities must be included in the relation."
3385 )
David Garciab4ebcd02021-10-28 02:00:43 +02003386 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003387 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003388 )
3389 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003390 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003391 )
3392 provider = EERelation(relation_provider)
3393 requirer = EERelation(relation_requirer)
3394 relation = Relation(r["name"], provider, requirer)
3395 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3396 if vca_in_relation:
3397 relations.append(relation)
3398 return relations
3399
3400 def _get_kdu_resource_data(
3401 self,
3402 ee_relation: EERelation,
3403 db_nsr: Dict[str, Any],
3404 cached_vnfds: Dict[str, Any],
3405 ) -> DeployedK8sResource:
3406 nsd = get_nsd(db_nsr)
3407 vnf_profiles = get_vnf_profiles(nsd)
3408 vnfd_id = find_in_list(
3409 vnf_profiles,
3410 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3411 )["vnfd-id"]
Gabriel Cubabd40ee82022-09-19 21:39:21 -05003412 project = nsd["_admin"]["projects_read"][0]
3413 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003414 kdu_resource_profile = get_kdu_resource_profile(
3415 db_vnfd, ee_relation.kdu_resource_profile_id
3416 )
3417 kdu_name = kdu_resource_profile["kdu-name"]
3418 deployed_kdu, _ = get_deployed_kdu(
3419 db_nsr.get("_admin", ()).get("deployed", ()),
3420 kdu_name,
3421 ee_relation.vnf_profile_id,
3422 )
3423 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3424 return deployed_kdu
3425
3426 def _get_deployed_component(
3427 self,
3428 ee_relation: EERelation,
3429 db_nsr: Dict[str, Any],
3430 cached_vnfds: Dict[str, Any],
3431 ) -> DeployedComponent:
3432 nsr_id = db_nsr["_id"]
3433 deployed_component = None
3434 ee_level = EELevel.get_level(ee_relation)
3435 if ee_level == EELevel.NS:
3436 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3437 if vca:
3438 deployed_component = DeployedVCA(nsr_id, vca)
3439 elif ee_level == EELevel.VNF:
3440 vca = get_deployed_vca(
3441 db_nsr,
3442 {
3443 "vdu_id": None,
3444 "member-vnf-index": ee_relation.vnf_profile_id,
3445 "ee_descriptor_id": ee_relation.execution_environment_ref,
3446 },
3447 )
3448 if vca:
3449 deployed_component = DeployedVCA(nsr_id, vca)
3450 elif ee_level == EELevel.VDU:
3451 vca = get_deployed_vca(
3452 db_nsr,
3453 {
3454 "vdu_id": ee_relation.vdu_profile_id,
3455 "member-vnf-index": ee_relation.vnf_profile_id,
3456 "ee_descriptor_id": ee_relation.execution_environment_ref,
3457 },
3458 )
3459 if vca:
3460 deployed_component = DeployedVCA(nsr_id, vca)
3461 elif ee_level == EELevel.KDU:
3462 kdu_resource_data = self._get_kdu_resource_data(
3463 ee_relation, db_nsr, cached_vnfds
3464 )
3465 if kdu_resource_data:
3466 deployed_component = DeployedK8sResource(kdu_resource_data)
3467 return deployed_component
3468
3469 async def _add_relation(
3470 self,
3471 relation: Relation,
3472 vca_type: str,
3473 db_nsr: Dict[str, Any],
3474 cached_vnfds: Dict[str, Any],
3475 cached_vnfrs: Dict[str, Any],
3476 ) -> bool:
3477 deployed_provider = self._get_deployed_component(
3478 relation.provider, db_nsr, cached_vnfds
3479 )
3480 deployed_requirer = self._get_deployed_component(
3481 relation.requirer, db_nsr, cached_vnfds
3482 )
3483 if (
3484 deployed_provider
3485 and deployed_requirer
3486 and deployed_provider.config_sw_installed
3487 and deployed_requirer.config_sw_installed
3488 ):
3489 provider_db_vnfr = (
3490 self._get_vnfr(
3491 relation.provider.nsr_id,
3492 relation.provider.vnf_profile_id,
3493 cached_vnfrs,
3494 )
3495 if relation.provider.vnf_profile_id
3496 else None
3497 )
3498 requirer_db_vnfr = (
3499 self._get_vnfr(
3500 relation.requirer.nsr_id,
3501 relation.requirer.vnf_profile_id,
3502 cached_vnfrs,
3503 )
3504 if relation.requirer.vnf_profile_id
3505 else None
3506 )
3507 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3508 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3509 provider_relation_endpoint = RelationEndpoint(
3510 deployed_provider.ee_id,
3511 provider_vca_id,
3512 relation.provider.endpoint,
3513 )
3514 requirer_relation_endpoint = RelationEndpoint(
3515 deployed_requirer.ee_id,
3516 requirer_vca_id,
3517 relation.requirer.endpoint,
3518 )
Patricia Reinosob4312c02023-01-06 22:28:44 +00003519 try:
3520 await self.vca_map[vca_type].add_relation(
3521 provider=provider_relation_endpoint,
3522 requirer=requirer_relation_endpoint,
3523 )
3524 except N2VCException as exception:
3525 self.logger.error(exception)
3526 raise LcmException(exception)
David Garciab4ebcd02021-10-28 02:00:43 +02003527 return True
3528 return False
3529
David Garciac1fe90a2021-03-31 19:12:02 +02003530 async def _add_vca_relations(
3531 self,
3532 logging_text,
3533 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003534 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003535 vca_index: int,
3536 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003537 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003538 # steps:
3539 # 1. find all relations for this VCA
3540 # 2. wait for other peers related
3541 # 3. add relations
3542
3543 try:
quilesj63f90042020-01-17 09:53:55 +00003544 # STEP 1: find all relations for this VCA
3545
3546 # read nsr record
3547 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003548 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003549
3550 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003551 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3552 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003553
David Garciab4ebcd02021-10-28 02:00:43 +02003554 cached_vnfds = {}
3555 cached_vnfrs = {}
3556 relations = []
3557 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3558 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003559
3560 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003561 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003562 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003563 return True
3564
David Garciab4ebcd02021-10-28 02:00:43 +02003565 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003566
3567 # add all relations
3568 start = time()
3569 while True:
3570 # check timeout
3571 now = time()
3572 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003573 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003574 return False
3575
David Garciab4ebcd02021-10-28 02:00:43 +02003576 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003577 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3578
David Garciab4ebcd02021-10-28 02:00:43 +02003579 # for each relation, find the VCA's related
3580 for relation in relations.copy():
3581 added = await self._add_relation(
3582 relation,
3583 vca_type,
3584 db_nsr,
3585 cached_vnfds,
3586 cached_vnfrs,
3587 )
3588 if added:
3589 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003590
David Garciab4ebcd02021-10-28 02:00:43 +02003591 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003592 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003593 break
David Garciab4ebcd02021-10-28 02:00:43 +02003594 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003595
3596 return True
3597
3598 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003599 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003600 return False
3601
garciadeblas5697b8b2021-03-24 09:17:02 +01003602 async def _install_kdu(
3603 self,
3604 nsr_id: str,
3605 nsr_db_path: str,
3606 vnfr_data: dict,
3607 kdu_index: int,
3608 kdud: dict,
3609 vnfd: dict,
3610 k8s_instance_info: dict,
3611 k8params: dict = None,
3612 timeout: int = 600,
3613 vca_id: str = None,
3614 ):
tiernob9018152020-04-16 14:18:24 +00003615 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003616 k8sclustertype = k8s_instance_info["k8scluster-type"]
3617 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003618 db_dict_install = {
3619 "collection": "nsrs",
3620 "filter": {"_id": nsr_id},
3621 "path": nsr_db_path,
3622 }
lloretgalleg7c121132020-07-08 07:53:22 +00003623
romeromonser4554a702021-05-28 12:00:08 +02003624 if k8s_instance_info.get("kdu-deployment-name"):
3625 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3626 else:
3627 kdu_instance = self.k8scluster_map[
3628 k8sclustertype
3629 ].generate_kdu_instance_name(
3630 db_dict=db_dict_install,
3631 kdu_model=k8s_instance_info["kdu-model"],
3632 kdu_name=k8s_instance_info["kdu-name"],
3633 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003634
3635 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003636 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003637 item="nsrs",
3638 _id=nsr_id,
3639 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003640 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003641
3642 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3643 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3644 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3645 # namespace, this first verification could be removed, and the next step would be done for any kind
3646 # of KNF.
3647 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3648 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3649 if k8sclustertype in ("juju", "juju-bundle"):
3650 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3651 # that the user passed a namespace which he wants its KDU to be deployed in)
3652 if (
3653 self.db.count(
3654 table="nsrs",
3655 q_filter={
3656 "_id": nsr_id,
3657 "_admin.projects_write": k8s_instance_info["namespace"],
3658 "_admin.projects_read": k8s_instance_info["namespace"],
3659 },
3660 )
3661 > 0
3662 ):
3663 self.logger.debug(
3664 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3665 )
3666 self.update_db_2(
3667 item="nsrs",
3668 _id=nsr_id,
3669 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3670 )
3671 k8s_instance_info["namespace"] = kdu_instance
3672
David Garciad64e2742021-02-25 20:19:18 +01003673 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003674 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3675 kdu_model=k8s_instance_info["kdu-model"],
3676 atomic=True,
3677 params=k8params,
3678 db_dict=db_dict_install,
3679 timeout=timeout,
3680 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003681 namespace=k8s_instance_info["namespace"],
3682 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003683 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003684 )
lloretgalleg7c121132020-07-08 07:53:22 +00003685
3686 # Obtain services to obtain management service ip
3687 services = await self.k8scluster_map[k8sclustertype].get_services(
3688 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3689 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003690 namespace=k8s_instance_info["namespace"],
3691 )
lloretgalleg7c121132020-07-08 07:53:22 +00003692
3693 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003694 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003695 kdu_config = get_configuration(vnfd, kdud["name"])
3696 if kdu_config:
3697 target_ee_list = kdu_config.get("execution-environment-list", [])
3698 else:
3699 target_ee_list = []
3700
lloretgalleg7c121132020-07-08 07:53:22 +00003701 if services:
tierno7ecbc342020-09-21 14:05:39 +00003702 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003703 mgmt_services = [
3704 service
3705 for service in kdud.get("service", [])
3706 if service.get("mgmt-service")
3707 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003708 for mgmt_service in mgmt_services:
3709 for service in services:
3710 if service["name"].startswith(mgmt_service["name"]):
3711 # Mgmt service found, Obtain service ip
3712 ip = service.get("external_ip", service.get("cluster_ip"))
3713 if isinstance(ip, list) and len(ip) == 1:
3714 ip = ip[0]
3715
garciadeblas5697b8b2021-03-24 09:17:02 +01003716 vnfr_update_dict[
3717 "kdur.{}.ip-address".format(kdu_index)
3718 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003719
3720 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003721 service_external_cp = mgmt_service.get(
3722 "external-connection-point-ref"
3723 )
lloretgalleg7c121132020-07-08 07:53:22 +00003724 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003725 if (
3726 deep_get(vnfd, ("mgmt-interface", "cp"))
3727 == service_external_cp
3728 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003729 vnfr_update_dict["ip-address"] = ip
3730
bravof6ec62b72021-02-25 17:20:35 -03003731 if find_in_list(
3732 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003733 lambda ee: ee.get(
3734 "external-connection-point-ref", ""
3735 )
3736 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003737 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003738 vnfr_update_dict[
3739 "kdur.{}.ip-address".format(kdu_index)
3740 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003741 break
3742 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003743 self.logger.warn(
3744 "Mgmt service name: {} not found".format(
3745 mgmt_service["name"]
3746 )
3747 )
lloretgalleg7c121132020-07-08 07:53:22 +00003748
tierno7ecbc342020-09-21 14:05:39 +00003749 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3750 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003751
bravof9a256db2021-02-22 18:02:07 -03003752 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003753 if (
3754 kdu_config
3755 and kdu_config.get("initial-config-primitive")
3756 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3757 ):
3758 initial_config_primitive_list = kdu_config.get(
3759 "initial-config-primitive"
3760 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003761 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3762
3763 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003764 primitive_params_ = self._map_primitive_params(
3765 initial_config_primitive, {}, {}
3766 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003767
3768 await asyncio.wait_for(
3769 self.k8scluster_map[k8sclustertype].exec_primitive(
3770 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3771 kdu_instance=kdu_instance,
3772 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003773 params=primitive_params_,
3774 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003775 vca_id=vca_id,
3776 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003777 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003778 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003779
tiernob9018152020-04-16 14:18:24 +00003780 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003781 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003782 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003783 self.update_db_2(
3784 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3785 )
3786 self.update_db_2(
3787 "vnfrs",
3788 vnfr_data.get("_id"),
3789 {"kdur.{}.status".format(kdu_index): "ERROR"},
3790 )
tiernob9018152020-04-16 14:18:24 +00003791 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00003792 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00003793 pass
lloretgalleg7c121132020-07-08 07:53:22 +00003794 # reraise original error
3795 raise
3796
3797 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003798
garciadeblas5697b8b2021-03-24 09:17:02 +01003799 async def deploy_kdus(
3800 self,
3801 logging_text,
3802 nsr_id,
3803 nslcmop_id,
3804 db_vnfrs,
3805 db_vnfds,
3806 task_instantiation_info,
3807 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003808 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003809
garciadeblas5697b8b2021-03-24 09:17:02 +01003810 k8scluster_id_2_uuic = {
3811 "helm-chart-v3": {},
3812 "helm-chart": {},
3813 "juju-bundle": {},
3814 }
tierno626e0152019-11-29 14:16:16 +00003815
tierno16f4a4e2020-07-20 09:05:51 +00003816 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003817 nonlocal k8scluster_id_2_uuic
3818 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3819 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3820
tierno16f4a4e2020-07-20 09:05:51 +00003821 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003822 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3823 "k8scluster", cluster_id
3824 )
tierno16f4a4e2020-07-20 09:05:51 +00003825 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003826 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3827 task_name, cluster_id
3828 )
tierno16f4a4e2020-07-20 09:05:51 +00003829 self.logger.debug(logging_text + text)
3830 await asyncio.wait(task_dependency, timeout=3600)
3831
garciadeblas5697b8b2021-03-24 09:17:02 +01003832 db_k8scluster = self.db.get_one(
3833 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3834 )
tierno626e0152019-11-29 14:16:16 +00003835 if not db_k8scluster:
3836 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003837
tierno626e0152019-11-29 14:16:16 +00003838 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3839 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003840 if cluster_type == "helm-chart-v3":
3841 try:
3842 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003843 k8s_credentials = yaml.safe_dump(
3844 db_k8scluster.get("credentials")
3845 )
3846 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3847 k8s_credentials, reuse_cluster_uuid=cluster_id
3848 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003849 db_k8scluster_update = {}
3850 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3851 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003852 db_k8scluster_update[
3853 "_admin.helm-chart-v3.created"
3854 ] = uninstall_sw
3855 db_k8scluster_update[
3856 "_admin.helm-chart-v3.operationalState"
3857 ] = "ENABLED"
3858 self.update_db_2(
3859 "k8sclusters", cluster_id, db_k8scluster_update
3860 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003861 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003862 self.logger.error(
3863 logging_text
3864 + "error initializing helm-v3 cluster: {}".format(str(e))
3865 )
3866 raise LcmException(
3867 "K8s cluster '{}' has not been initialized for '{}'".format(
3868 cluster_id, cluster_type
3869 )
3870 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003871 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003872 raise LcmException(
3873 "K8s cluster '{}' has not been initialized for '{}'".format(
3874 cluster_id, cluster_type
3875 )
3876 )
tierno626e0152019-11-29 14:16:16 +00003877 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3878 return k8s_id
3879
3880 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003881 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003882 try:
tierno626e0152019-11-29 14:16:16 +00003883 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003884 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003885
tierno626e0152019-11-29 14:16:16 +00003886 index = 0
tiernoe876f672020-02-13 14:34:48 +00003887 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003888 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003889
tierno626e0152019-11-29 14:16:16 +00003890 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003891 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003892 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3893 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003894 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003895 vnfd_id = vnfr_data.get("vnfd-id")
3896 vnfd_with_id = find_in_list(
3897 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3898 )
3899 kdud = next(
3900 kdud
3901 for kdud in vnfd_with_id["kdu"]
3902 if kdud["name"] == kdur["kdu-name"]
3903 )
tiernode1584f2020-04-07 09:07:33 +00003904 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003905 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003906 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003907 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003908 # Default version: helm3, if helm-version is v2 assign v2
3909 k8sclustertype = "helm-chart-v3"
3910 self.logger.debug("kdur: {}".format(kdur))
garciadeblas5697b8b2021-03-24 09:17:02 +01003911 if (
3912 kdur.get("helm-version")
3913 and kdur.get("helm-version") == "v2"
3914 ):
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003915 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00003916 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003917 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003918 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003919 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003920 raise LcmException(
3921 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3922 "juju-bundle. Maybe an old NBI version is running".format(
3923 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3924 )
3925 )
quilesjacde94f2020-01-23 10:07:08 +00003926 # check if kdumodel is a file and exists
3927 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003928 vnfd_with_id = find_in_list(
3929 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3930 )
3931 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003932 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003933 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003934 if storage["pkg-dir"]:
3935 filename = "{}/{}/{}s/{}".format(
3936 storage["folder"],
3937 storage["pkg-dir"],
3938 k8sclustertype,
3939 kdumodel,
3940 )
3941 else:
3942 filename = "{}/Scripts/{}s/{}".format(
3943 storage["folder"],
3944 k8sclustertype,
3945 kdumodel,
3946 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003947 if self.fs.file_exists(
3948 filename, mode="file"
3949 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003950 kdumodel = self.fs.path + filename
3951 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003952 raise
garciadeblas5697b8b2021-03-24 09:17:02 +01003953 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00003954 pass
lloretgallegedc5f332020-02-20 11:50:50 +01003955
tiernoe876f672020-02-13 14:34:48 +00003956 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003957 step = "Synchronize repos for k8s cluster '{}'".format(
3958 k8s_cluster_id
3959 )
tierno16f4a4e2020-07-20 09:05:51 +00003960 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003961
lloretgalleg7c121132020-07-08 07:53:22 +00003962 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003963 if (
3964 k8sclustertype == "helm-chart"
3965 and cluster_uuid not in updated_cluster_list
3966 ) or (
3967 k8sclustertype == "helm-chart-v3"
3968 and cluster_uuid not in updated_v3_cluster_list
3969 ):
tiernoe876f672020-02-13 14:34:48 +00003970 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003971 self.k8scluster_map[k8sclustertype].synchronize_repos(
3972 cluster_uuid=cluster_uuid
3973 )
3974 )
tiernoe876f672020-02-13 14:34:48 +00003975 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003976 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003977 unset = {
3978 "_admin.helm_charts_added." + item: None
3979 for item in del_repo_list
3980 }
3981 updated = {
3982 "_admin.helm_charts_added." + item: name
3983 for item, name in added_repo_dict.items()
3984 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003985 updated_cluster_list.append(cluster_uuid)
3986 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003987 unset = {
3988 "_admin.helm_charts_v3_added." + item: None
3989 for item in del_repo_list
3990 }
3991 updated = {
3992 "_admin.helm_charts_v3_added." + item: name
3993 for item, name in added_repo_dict.items()
3994 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003995 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003996 self.logger.debug(
3997 logging_text + "repos synchronized on k8s cluster "
3998 "'{}' to_delete: {}, to_add: {}".format(
3999 k8s_cluster_id, del_repo_list, added_repo_dict
4000 )
4001 )
4002 self.db.set_one(
4003 "k8sclusters",
4004 {"_id": k8s_cluster_id},
4005 updated,
4006 unset=unset,
4007 )
lloretgallegedc5f332020-02-20 11:50:50 +01004008
lloretgalleg7c121132020-07-08 07:53:22 +00004009 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01004010 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
4011 vnfr_data["member-vnf-index-ref"],
4012 kdur["kdu-name"],
4013 k8s_cluster_id,
4014 )
4015 k8s_instance_info = {
4016 "kdu-instance": None,
4017 "k8scluster-uuid": cluster_uuid,
4018 "k8scluster-type": k8sclustertype,
4019 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
4020 "kdu-name": kdur["kdu-name"],
4021 "kdu-model": kdumodel,
4022 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02004023 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004024 }
tiernob9018152020-04-16 14:18:24 +00004025 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00004026 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00004027 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01004028 vnfd_with_id = find_in_list(
4029 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
4030 )
tiernoa2143262020-03-27 16:20:40 +00004031 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004032 self._install_kdu(
4033 nsr_id,
4034 db_path,
4035 vnfr_data,
4036 kdu_index,
4037 kdud,
4038 vnfd_with_id,
4039 k8s_instance_info,
4040 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02004041 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01004042 vca_id=vca_id,
4043 )
4044 )
4045 self.lcm_tasks.register(
4046 "ns",
4047 nsr_id,
4048 nslcmop_id,
4049 "instantiate_KDU-{}".format(index),
4050 task,
4051 )
4052 task_instantiation_info[task] = "Deploying KDU {}".format(
4053 kdur["kdu-name"]
4054 )
tiernoe876f672020-02-13 14:34:48 +00004055
tierno626e0152019-11-29 14:16:16 +00004056 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00004057
tiernoe876f672020-02-13 14:34:48 +00004058 except (LcmException, asyncio.CancelledError):
4059 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01004060 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00004061 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
4062 if isinstance(e, (N2VCException, DbException)):
4063 self.logger.error(logging_text + msg)
4064 else:
4065 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00004066 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01004067 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01004068 if db_nsr_update:
4069 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00004070
garciadeblas5697b8b2021-03-24 09:17:02 +01004071 def _deploy_n2vc(
4072 self,
4073 logging_text,
4074 db_nsr,
4075 db_vnfr,
4076 nslcmop_id,
4077 nsr_id,
4078 nsi_id,
4079 vnfd_id,
4080 vdu_id,
4081 kdu_name,
4082 member_vnf_index,
4083 vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004084 kdu_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01004085 vdu_name,
4086 deploy_params,
4087 descriptor_config,
4088 base_folder,
4089 task_instantiation_info,
4090 stage,
4091 ):
quilesj7e13aeb2019-10-08 13:34:55 +02004092 # launch instantiate_N2VC in a asyncio task and register task object
4093 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
4094 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02004095 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00004096
garciadeblas5697b8b2021-03-24 09:17:02 +01004097 self.logger.debug(
4098 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
4099 )
aticig9bc63ac2022-07-27 09:32:06 +03004100
4101 charm_name = ""
4102 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03004103 if "execution-environment-list" in descriptor_config:
4104 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02004105 elif "juju" in descriptor_config:
4106 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03004107 if "execution-environment-list" not in descriptor_config:
4108 # charm name is only required for ns charms
4109 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00004110 else: # other types as script are not supported
4111 ee_list = []
4112
4113 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004114 self.logger.debug(
4115 logging_text
4116 + "_deploy_n2vc ee_item juju={}, helm={}".format(
4117 ee_item.get("juju"), ee_item.get("helm-chart")
4118 )
4119 )
tiernoa278b842020-07-08 15:33:55 +00004120 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00004121 if ee_item.get("juju"):
garciadeblas5697b8b2021-03-24 09:17:02 +01004122 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03004123 if get_charm_name:
4124 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas5697b8b2021-03-24 09:17:02 +01004125 vca_type = (
4126 "lxc_proxy_charm"
4127 if ee_item["juju"].get("charm") is not None
4128 else "native_charm"
4129 )
4130 if ee_item["juju"].get("cloud") == "k8s":
tierno588547c2020-07-01 15:30:20 +00004131 vca_type = "k8s_proxy_charm"
garciadeblas5697b8b2021-03-24 09:17:02 +01004132 elif ee_item["juju"].get("proxy") is False:
tierno588547c2020-07-01 15:30:20 +00004133 vca_type = "native_charm"
4134 elif ee_item.get("helm-chart"):
garciadeblas5697b8b2021-03-24 09:17:02 +01004135 vca_name = ee_item["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00004136 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
4137 vca_type = "helm"
4138 else:
4139 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00004140 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004141 self.logger.debug(
4142 logging_text + "skipping non juju neither charm configuration"
4143 )
quilesj7e13aeb2019-10-08 13:34:55 +02004144 continue
quilesj3655ae02019-12-12 16:08:35 +00004145
tierno588547c2020-07-01 15:30:20 +00004146 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01004147 for vca_index, vca_deployed in enumerate(
4148 db_nsr["_admin"]["deployed"]["VCA"]
4149 ):
tierno588547c2020-07-01 15:30:20 +00004150 if not vca_deployed:
4151 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004152 if (
4153 vca_deployed.get("member-vnf-index") == member_vnf_index
4154 and vca_deployed.get("vdu_id") == vdu_id
4155 and vca_deployed.get("kdu_name") == kdu_name
4156 and vca_deployed.get("vdu_count_index", 0) == vdu_index
4157 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
4158 ):
tierno588547c2020-07-01 15:30:20 +00004159 break
4160 else:
4161 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01004162 target = (
4163 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
4164 )
tiernoa278b842020-07-08 15:33:55 +00004165 if vdu_id:
4166 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
4167 elif kdu_name:
4168 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00004169 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00004170 "target_element": target,
4171 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00004172 "member-vnf-index": member_vnf_index,
4173 "vdu_id": vdu_id,
4174 "kdu_name": kdu_name,
4175 "vdu_count_index": vdu_index,
4176 "operational-status": "init", # TODO revise
4177 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01004178 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00004179 "vnfd_id": vnfd_id,
4180 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00004181 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01004182 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03004183 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00004184 }
4185 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00004186
tierno588547c2020-07-01 15:30:20 +00004187 # create VCA and configurationStatus in db
4188 db_dict = {
4189 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01004190 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00004191 }
4192 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02004193
tierno588547c2020-07-01 15:30:20 +00004194 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
4195
bravof922c4172020-11-24 21:21:43 -03004196 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
4197 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
4198 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
4199
tierno588547c2020-07-01 15:30:20 +00004200 # Launch task
4201 task_n2vc = asyncio.ensure_future(
4202 self.instantiate_N2VC(
4203 logging_text=logging_text,
4204 vca_index=vca_index,
4205 nsi_id=nsi_id,
4206 db_nsr=db_nsr,
4207 db_vnfr=db_vnfr,
4208 vdu_id=vdu_id,
4209 kdu_name=kdu_name,
4210 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01004211 kdu_index=kdu_index,
tierno588547c2020-07-01 15:30:20 +00004212 deploy_params=deploy_params,
4213 config_descriptor=descriptor_config,
4214 base_folder=base_folder,
4215 nslcmop_id=nslcmop_id,
4216 stage=stage,
4217 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00004218 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01004219 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00004220 )
quilesj7e13aeb2019-10-08 13:34:55 +02004221 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004222 self.lcm_tasks.register(
4223 "ns",
4224 nsr_id,
4225 nslcmop_id,
4226 "instantiate_N2VC-{}".format(vca_index),
4227 task_n2vc,
4228 )
4229 task_instantiation_info[
4230 task_n2vc
4231 ] = self.task_name_deploy_vca + " {}.{}".format(
4232 member_vnf_index or "", vdu_id or ""
4233 )
tiernobaa51102018-12-14 13:16:18 +00004234
tiernoc9556972019-07-05 15:25:25 +00004235 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02004236 def _create_nslcmop(nsr_id, operation, params):
4237 """
4238 Creates a ns-lcm-opp content to be stored at database.
4239 :param nsr_id: internal id of the instance
4240 :param operation: instantiate, terminate, scale, action, ...
4241 :param params: user parameters for the operation
4242 :return: dictionary following SOL005 format
4243 """
4244 # Raise exception if invalid arguments
4245 if not (nsr_id and operation and params):
4246 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004247 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided"
4248 )
kuuse0ca67472019-05-13 15:59:27 +02004249 now = time()
4250 _id = str(uuid4())
4251 nslcmop = {
4252 "id": _id,
4253 "_id": _id,
4254 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
4255 "operationState": "PROCESSING",
4256 "statusEnteredTime": now,
4257 "nsInstanceId": nsr_id,
4258 "lcmOperationType": operation,
4259 "startTime": now,
4260 "isAutomaticInvocation": False,
4261 "operationParams": params,
4262 "isCancelPending": False,
4263 "links": {
4264 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
4265 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004266 },
kuuse0ca67472019-05-13 15:59:27 +02004267 }
4268 return nslcmop
4269
calvinosanch9f9c6f22019-11-04 13:37:39 +01004270 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00004271 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01004272 for key, value in params.items():
4273 if str(value).startswith("!!yaml "):
4274 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01004275 return params
4276
kuuse8b998e42019-07-30 15:22:16 +02004277 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004278 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02004279 primitive_params = {}
4280 params = {
4281 "member_vnf_index": vnf_index,
4282 "primitive": primitive,
4283 "primitive_params": primitive_params,
4284 }
4285 desc_params = {}
4286 return self._map_primitive_params(seq, params, desc_params)
4287
kuuseac3a8882019-10-03 10:48:06 +02004288 # sub-operations
4289
tierno51183952020-04-03 15:48:18 +00004290 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01004291 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
4292 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02004293 # b. Skip sub-operation
4294 # _ns_execute_primitive() or RO.create_action() will NOT be executed
4295 return self.SUBOPERATION_STATUS_SKIP
4296 else:
tierno7c4e24c2020-05-13 08:41:35 +00004297 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004298 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00004299 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01004300 operationState = "PROCESSING"
4301 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004302 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01004303 db_nslcmop, op_index, operationState, detailed_status
4304 )
kuuseac3a8882019-10-03 10:48:06 +02004305 # Return the sub-operation index
4306 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4307 # with arguments extracted from the sub-operation
4308 return op_index
4309
4310 # Find a sub-operation where all keys in a matching dictionary must match
4311 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4312 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004313 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004314 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004315 for i, op in enumerate(op_list):
4316 if all(op.get(k) == match[k] for k in match):
4317 return i
4318 return self.SUBOPERATION_STATUS_NOT_FOUND
4319
4320 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004321 def _update_suboperation_status(
4322 self, db_nslcmop, op_index, operationState, detailed_status
4323 ):
kuuseac3a8882019-10-03 10:48:06 +02004324 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004325 q_filter = {"_id": db_nslcmop["_id"]}
4326 update_dict = {
4327 "_admin.operations.{}.operationState".format(op_index): operationState,
4328 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4329 }
4330 self.db.set_one(
4331 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4332 )
kuuseac3a8882019-10-03 10:48:06 +02004333
4334 # Add sub-operation, return the index of the added sub-operation
4335 # Optionally, set operationState, detailed-status, and operationType
4336 # Status and type are currently set for 'scale' sub-operations:
4337 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4338 # 'detailed-status' : status message
4339 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4340 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004341 def _add_suboperation(
4342 self,
4343 db_nslcmop,
4344 vnf_index,
4345 vdu_id,
4346 vdu_count_index,
4347 vdu_name,
4348 primitive,
4349 mapped_primitive_params,
4350 operationState=None,
4351 detailed_status=None,
4352 operationType=None,
4353 RO_nsr_id=None,
4354 RO_scaling_info=None,
4355 ):
tiernoe876f672020-02-13 14:34:48 +00004356 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004357 return self.SUBOPERATION_STATUS_NOT_FOUND
4358 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004359 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4360 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004361 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004362 new_op = {
4363 "member_vnf_index": vnf_index,
4364 "vdu_id": vdu_id,
4365 "vdu_count_index": vdu_count_index,
4366 "primitive": primitive,
4367 "primitive_params": mapped_primitive_params,
4368 }
kuuseac3a8882019-10-03 10:48:06 +02004369 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004370 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004371 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004372 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004373 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004374 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004375 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004376 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004377 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004378 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004379 if not op_list:
4380 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004381 db_nslcmop_admin.update({"operations": [new_op]})
4382 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004383 else:
4384 # Existing operations, append operation to list
4385 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004386
garciadeblas5697b8b2021-03-24 09:17:02 +01004387 db_nslcmop_update = {"_admin.operations": op_list}
4388 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004389 op_index = len(op_list) - 1
4390 return op_index
4391
4392 # Helper methods for scale() sub-operations
4393
4394 # pre-scale/post-scale:
4395 # Check for 3 different cases:
4396 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4397 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004398 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004399 def _check_or_add_scale_suboperation(
4400 self,
4401 db_nslcmop,
4402 vnf_index,
4403 vnf_config_primitive,
4404 primitive_params,
4405 operationType,
4406 RO_nsr_id=None,
4407 RO_scaling_info=None,
4408 ):
kuuseac3a8882019-10-03 10:48:06 +02004409 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004410 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004411 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004412 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004413 "member_vnf_index": vnf_index,
4414 "RO_nsr_id": RO_nsr_id,
4415 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004416 }
4417 else:
4418 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004419 "member_vnf_index": vnf_index,
4420 "primitive": vnf_config_primitive,
4421 "primitive_params": primitive_params,
4422 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004423 }
4424 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004425 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004426 # a. New sub-operation
4427 # The sub-operation does not exist, add it.
4428 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4429 # The following parameters are set to None for all kind of scaling:
4430 vdu_id = None
4431 vdu_count_index = None
4432 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004433 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004434 vnf_config_primitive = None
4435 primitive_params = None
4436 else:
4437 RO_nsr_id = None
4438 RO_scaling_info = None
4439 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004440 operationState = "PROCESSING"
4441 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004442 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004443 self._add_suboperation(
4444 db_nslcmop,
4445 vnf_index,
4446 vdu_id,
4447 vdu_count_index,
4448 vdu_name,
4449 vnf_config_primitive,
4450 primitive_params,
4451 operationState,
4452 detailed_status,
4453 operationType,
4454 RO_nsr_id,
4455 RO_scaling_info,
4456 )
kuuseac3a8882019-10-03 10:48:06 +02004457 return self.SUBOPERATION_STATUS_NEW
4458 else:
4459 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4460 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004461 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004462
preethika.pdf7d8e02019-12-10 13:10:48 +00004463 # Function to return execution_environment id
4464
4465 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00004466 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00004467 for vca in vca_deployed_list:
4468 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
Dario Faccin1df4ede2023-06-01 10:15:34 +02004469 return vca.get("ee_id")
preethika.pdf7d8e02019-12-10 13:10:48 +00004470
David Garciac1fe90a2021-03-31 19:12:02 +02004471 async def destroy_N2VC(
4472 self,
4473 logging_text,
4474 db_nslcmop,
4475 vca_deployed,
4476 config_descriptor,
4477 vca_index,
4478 destroy_ee=True,
4479 exec_primitives=True,
4480 scaling_in=False,
4481 vca_id: str = None,
4482 ):
tiernoe876f672020-02-13 14:34:48 +00004483 """
4484 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4485 :param logging_text:
4486 :param db_nslcmop:
4487 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4488 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4489 :param vca_index: index in the database _admin.deployed.VCA
4490 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004491 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4492 not executed properly
aktas13251562021-02-12 22:19:10 +03004493 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004494 :return: None or exception
4495 """
tiernoe876f672020-02-13 14:34:48 +00004496
tierno588547c2020-07-01 15:30:20 +00004497 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004498 logging_text
4499 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004500 vca_index, vca_deployed, config_descriptor, destroy_ee
4501 )
4502 )
4503
4504 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4505
4506 # execute terminate_primitives
4507 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004508 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004509 config_descriptor.get("terminate-config-primitive"),
4510 vca_deployed.get("ee_descriptor_id"),
4511 )
tierno588547c2020-07-01 15:30:20 +00004512 vdu_id = vca_deployed.get("vdu_id")
4513 vdu_count_index = vca_deployed.get("vdu_count_index")
4514 vdu_name = vca_deployed.get("vdu_name")
4515 vnf_index = vca_deployed.get("member-vnf-index")
4516 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004517 for seq in terminate_primitives:
4518 # For each sequence in list, get primitive and call _ns_execute_primitive()
4519 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004520 vnf_index, seq.get("name")
4521 )
tierno588547c2020-07-01 15:30:20 +00004522 self.logger.debug(logging_text + step)
4523 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004524 primitive = seq.get("name")
4525 mapped_primitive_params = self._get_terminate_primitive_params(
4526 seq, vnf_index
4527 )
tierno588547c2020-07-01 15:30:20 +00004528
4529 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004530 self._add_suboperation(
4531 db_nslcmop,
4532 vnf_index,
4533 vdu_id,
4534 vdu_count_index,
4535 vdu_name,
4536 primitive,
4537 mapped_primitive_params,
4538 )
tierno588547c2020-07-01 15:30:20 +00004539 # Sub-operations: Call _ns_execute_primitive() instead of action()
4540 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004541 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004542 vca_deployed["ee_id"],
4543 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004544 mapped_primitive_params,
4545 vca_type=vca_type,
4546 vca_id=vca_id,
4547 )
tierno588547c2020-07-01 15:30:20 +00004548 except LcmException:
4549 # this happens when VCA is not deployed. In this case it is not needed to terminate
4550 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004551 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004552 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004553 raise LcmException(
4554 "terminate_primitive {} for vnf_member_index={} fails with "
4555 "error {}".format(seq.get("name"), vnf_index, result_detail)
4556 )
tierno588547c2020-07-01 15:30:20 +00004557 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004558 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4559 vca_index
4560 )
4561 self.update_db_2(
4562 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4563 )
tiernoe876f672020-02-13 14:34:48 +00004564
bravof73bac502021-05-11 07:38:47 -04004565 # Delete Prometheus Jobs if any
4566 # This uses NSR_ID, so it will destroy any jobs under this index
4567 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004568
tiernoe876f672020-02-13 14:34:48 +00004569 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004570 await self.vca_map[vca_type].delete_execution_environment(
4571 vca_deployed["ee_id"],
4572 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004573 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004574 vca_id=vca_id,
4575 )
kuuse0ca67472019-05-13 15:59:27 +02004576
David Garciac1fe90a2021-03-31 19:12:02 +02004577 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004578 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004579 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004580 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004581 await self.n2vc.delete_namespace(
4582 namespace=namespace,
Luis Vegaa27dc532022-11-11 20:10:49 +00004583 total_timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004584 vca_id=vca_id,
4585 )
tiernof59ad6c2020-04-08 12:50:52 +00004586 except N2VCNotFound: # already deleted. Skip
4587 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004588 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004589
tiernoe876f672020-02-13 14:34:48 +00004590 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004591 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004592 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004593 if not task_is_locked_by_me:
4594 return
4595
tierno59d22d22018-09-25 18:10:19 +02004596 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4597 self.logger.debug(logging_text + "Enter")
Luis Vegaa27dc532022-11-11 20:10:49 +00004598 timeout_ns_terminate = self.timeout.ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004599 db_nsr = None
4600 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004601 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004602 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004603 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004604 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004605 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004606 tasks_dict_info = {}
4607 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004608 stage = [
4609 "Stage 1/3: Preparing task.",
4610 "Waiting for previous operations to terminate.",
4611 "",
4612 ]
tiernoe876f672020-02-13 14:34:48 +00004613 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004614 try:
kuused124bfe2019-06-18 12:09:24 +02004615 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004616 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004617
tiernoe876f672020-02-13 14:34:48 +00004618 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4619 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4620 operation_params = db_nslcmop.get("operationParams") or {}
4621 if operation_params.get("timeout_ns_terminate"):
4622 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4623 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4624 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4625
4626 db_nsr_update["operational-status"] = "terminating"
4627 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004628 self._write_ns_status(
4629 nsr_id=nsr_id,
4630 ns_state="TERMINATING",
4631 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004632 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004633 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004634 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004635 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004636 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004637 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4638 return
tierno59d22d22018-09-25 18:10:19 +02004639
tiernoe876f672020-02-13 14:34:48 +00004640 stage[1] = "Getting vnf descriptors from db."
4641 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004642 db_vnfrs_dict = {
4643 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4644 }
tiernoe876f672020-02-13 14:34:48 +00004645 db_vnfds_from_id = {}
4646 db_vnfds_from_member_index = {}
4647 # Loop over VNFRs
4648 for vnfr in db_vnfrs_list:
4649 vnfd_id = vnfr["vnfd-id"]
4650 if vnfd_id not in db_vnfds_from_id:
4651 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4652 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004653 db_vnfds_from_member_index[
4654 vnfr["member-vnf-index-ref"]
4655 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004656
tiernoe876f672020-02-13 14:34:48 +00004657 # Destroy individual execution environments when there are terminating primitives.
4658 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004659 # TODO - check before calling _destroy_N2VC
4660 # if not operation_params.get("skip_terminate_primitives"):#
4661 # or not vca.get("needed_terminate"):
4662 stage[0] = "Stage 2/3 execute terminating primitives."
4663 self.logger.debug(logging_text + stage[0])
4664 stage[1] = "Looking execution environment that needs terminate."
4665 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004666
tierno588547c2020-07-01 15:30:20 +00004667 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004668 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004669 vca_member_vnf_index = vca.get("member-vnf-index")
4670 vca_id = self.get_vca_id(
4671 db_vnfrs_dict.get(vca_member_vnf_index)
4672 if vca_member_vnf_index
4673 else None,
4674 db_nsr,
4675 )
tierno588547c2020-07-01 15:30:20 +00004676 if not vca or not vca.get("ee_id"):
4677 continue
4678 if not vca.get("member-vnf-index"):
4679 # ns
4680 config_descriptor = db_nsr.get("ns-configuration")
4681 elif vca.get("vdu_id"):
4682 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004683 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004684 elif vca.get("kdu_name"):
4685 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004686 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004687 else:
bravofe5a31bc2021-02-17 19:09:12 -03004688 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004689 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004690 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004691 exec_terminate_primitives = not operation_params.get(
4692 "skip_terminate_primitives"
4693 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004694 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4695 # pending native charms
garciadeblas5697b8b2021-03-24 09:17:02 +01004696 destroy_ee = (
4697 True if vca_type in ("helm", "helm-v3", "native_charm") else False
4698 )
tierno86e33612020-09-16 14:13:06 +00004699 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4700 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004701 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004702 self.destroy_N2VC(
4703 logging_text,
4704 db_nslcmop,
4705 vca,
4706 config_descriptor,
4707 vca_index,
4708 destroy_ee,
4709 exec_terminate_primitives,
4710 vca_id=vca_id,
4711 )
4712 )
tierno588547c2020-07-01 15:30:20 +00004713 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004714
tierno588547c2020-07-01 15:30:20 +00004715 # wait for pending tasks of terminate primitives
4716 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004717 self.logger.debug(
4718 logging_text
4719 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4720 )
4721 error_list = await self._wait_for_tasks(
4722 logging_text,
4723 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00004724 min(self.timeout.charm_delete, timeout_ns_terminate),
garciadeblas5697b8b2021-03-24 09:17:02 +01004725 stage,
4726 nslcmop_id,
4727 )
tierno86e33612020-09-16 14:13:06 +00004728 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004729 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004730 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004731
tiernoe876f672020-02-13 14:34:48 +00004732 # remove All execution environments at once
4733 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004734
tierno49676be2020-04-07 16:34:35 +00004735 if nsr_deployed.get("VCA"):
4736 stage[1] = "Deleting all execution environments."
4737 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02004738 vca_id = self.get_vca_id({}, db_nsr)
4739 task_delete_ee = asyncio.ensure_future(
4740 asyncio.wait_for(
4741 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
Luis Vegaa27dc532022-11-11 20:10:49 +00004742 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004743 )
4744 )
tierno49676be2020-04-07 16:34:35 +00004745 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
4746 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02004747
Gabriel Cuba1411a002022-10-07 11:38:23 -05004748 # Delete Namespace and Certificates if necessary
4749 if check_helm_ee_in_ns(list(db_vnfds_from_member_index.values())):
4750 await self.vca_map["helm-v3"].delete_tls_certificate(
Dario Faccin1df4ede2023-06-01 10:15:34 +02004751 namespace=db_nslcmop["nsInstanceId"],
4752 certificate_name=self.EE_TLS_NAME,
Gabriel Cuba1411a002022-10-07 11:38:23 -05004753 )
Dario Faccin1df4ede2023-06-01 10:15:34 +02004754 await self.vca_map["helm-v3"].delete_namespace(
4755 namespace=db_nslcmop["nsInstanceId"],
4756 )
Gabriel Cuba1411a002022-10-07 11:38:23 -05004757
tiernoe876f672020-02-13 14:34:48 +00004758 # Delete from k8scluster
4759 stage[1] = "Deleting KDUs."
4760 self.logger.debug(logging_text + stage[1])
4761 # print(nsr_deployed)
4762 for kdu in get_iterable(nsr_deployed, "K8s"):
4763 if not kdu or not kdu.get("kdu-instance"):
4764 continue
4765 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004766 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004767 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4768 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004769 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004770 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4771 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004772 kdu_instance=kdu_instance,
4773 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004774 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004775 )
4776 )
tiernoe876f672020-02-13 14:34:48 +00004777 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004778 self.logger.error(
4779 logging_text
4780 + "Unknown k8s deployment type {}".format(
4781 kdu.get("k8scluster-type")
4782 )
4783 )
tiernoe876f672020-02-13 14:34:48 +00004784 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004785 tasks_dict_info[
4786 task_delete_kdu_instance
4787 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004788
4789 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004790 stage[1] = "Deleting ns from VIM."
Luis Vegaa27dc532022-11-11 20:10:49 +00004791 if self.ro_config.ng:
tierno69f0d382020-05-07 13:08:09 +00004792 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004793 self._terminate_ng_ro(
4794 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4795 )
4796 )
Gabriel Cuba411af2e2023-01-06 17:23:22 -05004797 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004798
tiernoe876f672020-02-13 14:34:48 +00004799 # rest of staff will be done at finally
4800
garciadeblas5697b8b2021-03-24 09:17:02 +01004801 except (
4802 ROclient.ROClientException,
4803 DbException,
4804 LcmException,
4805 N2VCException,
4806 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004807 self.logger.error(logging_text + "Exit Exception {}".format(e))
4808 exc = e
4809 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004810 self.logger.error(
4811 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4812 )
tiernoe876f672020-02-13 14:34:48 +00004813 exc = "Operation was cancelled"
4814 except Exception as e:
4815 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004816 self.logger.critical(
4817 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4818 exc_info=True,
4819 )
tiernoe876f672020-02-13 14:34:48 +00004820 finally:
4821 if exc:
4822 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004823 try:
tiernoe876f672020-02-13 14:34:48 +00004824 # wait for pending tasks
4825 if tasks_dict_info:
4826 stage[1] = "Waiting for terminate pending tasks."
4827 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004828 error_list += await self._wait_for_tasks(
4829 logging_text,
4830 tasks_dict_info,
4831 timeout_ns_terminate,
4832 stage,
4833 nslcmop_id,
4834 )
tiernoe876f672020-02-13 14:34:48 +00004835 stage[1] = stage[2] = ""
4836 except asyncio.CancelledError:
4837 error_list.append("Cancelled")
4838 # TODO cancell all tasks
4839 except Exception as exc:
4840 error_list.append(str(exc))
4841 # update status at database
4842 if error_list:
4843 error_detail = "; ".join(error_list)
4844 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004845 error_description_nslcmop = "{} Detail: {}".format(
4846 stage[0], error_detail
4847 )
4848 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4849 nslcmop_id, stage[0]
4850 )
tierno59d22d22018-09-25 18:10:19 +02004851
tierno59d22d22018-09-25 18:10:19 +02004852 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004853 db_nsr_update["detailed-status"] = (
4854 error_description_nsr + " Detail: " + error_detail
4855 )
tiernoe876f672020-02-13 14:34:48 +00004856 db_nslcmop_update["detailed-status"] = error_detail
4857 nslcmop_operation_state = "FAILED"
4858 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004859 else:
tiernoa2143262020-03-27 16:20:40 +00004860 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004861 error_description_nsr = error_description_nslcmop = None
4862 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004863 db_nsr_update["operational-status"] = "terminated"
4864 db_nsr_update["detailed-status"] = "Done"
4865 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4866 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004867 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004868
tiernoe876f672020-02-13 14:34:48 +00004869 if db_nsr:
4870 self._write_ns_status(
4871 nsr_id=nsr_id,
4872 ns_state=ns_state,
4873 current_operation="IDLE",
4874 current_operation_id=None,
4875 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004876 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004877 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004878 )
tiernoa17d4f42020-04-28 09:59:23 +00004879 self._write_op_status(
4880 op_id=nslcmop_id,
4881 stage="",
4882 error_message=error_description_nslcmop,
4883 operation_state=nslcmop_operation_state,
4884 other_update=db_nslcmop_update,
4885 )
lloretgalleg6d488782020-07-22 10:13:46 +00004886 if ns_state == "NOT_INSTANTIATED":
4887 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004888 self.db.set_list(
4889 "vnfrs",
4890 {"nsr-id-ref": nsr_id},
4891 {"_admin.nsState": "NOT_INSTANTIATED"},
4892 )
lloretgalleg6d488782020-07-22 10:13:46 +00004893 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004894 self.logger.warn(
4895 logging_text
4896 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4897 nsr_id, e
4898 )
4899 )
tiernoa17d4f42020-04-28 09:59:23 +00004900 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004901 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004902 if nslcmop_operation_state:
4903 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004904 await self.msg.aiowrite(
4905 "ns",
4906 "terminated",
4907 {
4908 "nsr_id": nsr_id,
4909 "nslcmop_id": nslcmop_id,
4910 "operationState": nslcmop_operation_state,
4911 "autoremove": autoremove,
4912 },
garciadeblas5697b8b2021-03-24 09:17:02 +01004913 )
tierno59d22d22018-09-25 18:10:19 +02004914 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004915 self.logger.error(
4916 logging_text + "kafka_write notification Exception {}".format(e)
4917 )
Dario Faccin1df4ede2023-06-01 10:15:34 +02004918 self.logger.debug(f"Deleting alerts: ns_id={nsr_id}")
4919 self.db.del_list("alerts", {"tags.ns_id": nsr_id})
quilesj7e13aeb2019-10-08 13:34:55 +02004920
tierno59d22d22018-09-25 18:10:19 +02004921 self.logger.debug(logging_text + "Exit")
4922 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4923
garciadeblas5697b8b2021-03-24 09:17:02 +01004924 async def _wait_for_tasks(
4925 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4926 ):
tiernoe876f672020-02-13 14:34:48 +00004927 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004928 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004929 error_list = []
4930 pending_tasks = list(created_tasks_info.keys())
4931 num_tasks = len(pending_tasks)
4932 num_done = 0
4933 stage[1] = "{}/{}.".format(num_done, num_tasks)
4934 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004935 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004936 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004937 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004938 done, pending_tasks = await asyncio.wait(
4939 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4940 )
tiernoe876f672020-02-13 14:34:48 +00004941 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004942 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004943 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004944 new_error = created_tasks_info[task] + ": Timeout"
4945 error_detail_list.append(new_error)
4946 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004947 break
4948 for task in done:
4949 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004950 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004951 else:
4952 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004953 if exc:
4954 if isinstance(exc, asyncio.TimeoutError):
4955 exc = "Timeout"
4956 new_error = created_tasks_info[task] + ": {}".format(exc)
4957 error_list.append(created_tasks_info[task])
4958 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004959 if isinstance(
4960 exc,
4961 (
4962 str,
4963 DbException,
4964 N2VCException,
4965 ROclient.ROClientException,
4966 LcmException,
4967 K8sException,
4968 NgRoException,
4969 ),
4970 ):
tierno067e04a2020-03-31 12:53:13 +00004971 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004972 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004973 exc_traceback = "".join(
4974 traceback.format_exception(None, exc, exc.__traceback__)
4975 )
4976 self.logger.error(
4977 logging_text
4978 + created_tasks_info[task]
4979 + " "
4980 + exc_traceback
4981 )
tierno067e04a2020-03-31 12:53:13 +00004982 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004983 self.logger.debug(
4984 logging_text + created_tasks_info[task] + ": Done"
4985 )
tiernoe876f672020-02-13 14:34:48 +00004986 stage[1] = "{}/{}.".format(num_done, num_tasks)
4987 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004988 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004989 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004990 self.update_db_2(
4991 "nsrs",
4992 nsr_id,
4993 {
4994 "errorDescription": "Error at: " + ", ".join(error_list),
4995 "errorDetail": ". ".join(error_detail_list),
4996 },
4997 )
tiernoe876f672020-02-13 14:34:48 +00004998 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004999 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00005000
tiernoda1ff8c2020-10-22 14:12:46 +00005001 @staticmethod
5002 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00005003 """
5004 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
5005 The default-value is used. If it is between < > it look for a value at instantiation_params
5006 :param primitive_desc: portion of VNFD/NSD that describes primitive
5007 :param params: Params provided by user
5008 :param instantiation_params: Instantiation params provided by user
5009 :return: a dictionary with the calculated params
5010 """
5011 calculated_params = {}
5012 for parameter in primitive_desc.get("parameter", ()):
5013 param_name = parameter["name"]
5014 if param_name in params:
5015 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00005016 elif "default-value" in parameter or "value" in parameter:
5017 if "value" in parameter:
5018 calculated_params[param_name] = parameter["value"]
5019 else:
5020 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005021 if (
5022 isinstance(calculated_params[param_name], str)
5023 and calculated_params[param_name].startswith("<")
5024 and calculated_params[param_name].endswith(">")
5025 ):
tierno98ad6ea2019-05-30 17:16:28 +00005026 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01005027 calculated_params[param_name] = instantiation_params[
5028 calculated_params[param_name][1:-1]
5029 ]
tiernoda964822019-01-14 15:53:47 +00005030 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005031 raise LcmException(
5032 "Parameter {} needed to execute primitive {} not provided".format(
5033 calculated_params[param_name], primitive_desc["name"]
5034 )
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 param_name, primitive_desc["name"]
5040 )
5041 )
tierno59d22d22018-09-25 18:10:19 +02005042
tiernoda964822019-01-14 15:53:47 +00005043 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01005044 calculated_params[param_name] = yaml.safe_dump(
5045 calculated_params[param_name], default_flow_style=True, width=256
5046 )
5047 elif isinstance(calculated_params[param_name], str) and calculated_params[
5048 param_name
5049 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00005050 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00005051 if parameter.get("data-type") == "INTEGER":
5052 try:
5053 calculated_params[param_name] = int(calculated_params[param_name])
5054 except ValueError: # error converting string to int
5055 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01005056 "Parameter {} of primitive {} must be integer".format(
5057 param_name, primitive_desc["name"]
5058 )
5059 )
tiernofa40e692020-10-14 14:59:36 +00005060 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01005061 calculated_params[param_name] = not (
5062 (str(calculated_params[param_name])).lower() == "false"
5063 )
tiernoc3f2a822019-11-05 13:45:04 +00005064
5065 # add always ns_config_info if primitive name is config
5066 if primitive_desc["name"] == "config":
5067 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01005068 calculated_params["ns_config_info"] = instantiation_params[
5069 "ns_config_info"
5070 ]
tiernoda964822019-01-14 15:53:47 +00005071 return calculated_params
5072
garciadeblas5697b8b2021-03-24 09:17:02 +01005073 def _look_for_deployed_vca(
5074 self,
5075 deployed_vca,
5076 member_vnf_index,
5077 vdu_id,
5078 vdu_count_index,
5079 kdu_name=None,
5080 ee_descriptor_id=None,
5081 ):
tiernoe876f672020-02-13 14:34:48 +00005082 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
5083 for vca in deployed_vca:
5084 if not vca:
5085 continue
5086 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
5087 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01005088 if (
5089 vdu_count_index is not None
5090 and vdu_count_index != vca["vdu_count_index"]
5091 ):
tiernoe876f672020-02-13 14:34:48 +00005092 continue
5093 if kdu_name and kdu_name != vca["kdu_name"]:
5094 continue
tiernoa278b842020-07-08 15:33:55 +00005095 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
5096 continue
tiernoe876f672020-02-13 14:34:48 +00005097 break
5098 else:
5099 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01005100 raise LcmException(
5101 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
5102 " is not deployed".format(
5103 member_vnf_index,
5104 vdu_id,
5105 vdu_count_index,
5106 kdu_name,
5107 ee_descriptor_id,
5108 )
5109 )
tiernoe876f672020-02-13 14:34:48 +00005110 # get ee_id
5111 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01005112 vca_type = vca.get(
5113 "type", "lxc_proxy_charm"
5114 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00005115 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005116 raise LcmException(
5117 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
5118 "execution environment".format(
5119 member_vnf_index, vdu_id, kdu_name, vdu_count_index
5120 )
5121 )
tierno588547c2020-07-01 15:30:20 +00005122 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00005123
David Garciac1fe90a2021-03-31 19:12:02 +02005124 async def _ns_execute_primitive(
5125 self,
5126 ee_id,
5127 primitive,
5128 primitive_params,
5129 retries=0,
5130 retries_interval=30,
5131 timeout=None,
5132 vca_type=None,
5133 db_dict=None,
5134 vca_id: str = None,
5135 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005136 try:
tierno98ad6ea2019-05-30 17:16:28 +00005137 if primitive == "config":
5138 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005139
tierno588547c2020-07-01 15:30:20 +00005140 vca_type = vca_type or "lxc_proxy_charm"
5141
quilesj7e13aeb2019-10-08 13:34:55 +02005142 while retries >= 0:
5143 try:
tierno067e04a2020-03-31 12:53:13 +00005144 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005145 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005146 ee_id=ee_id,
5147 primitive_name=primitive,
5148 params_dict=primitive_params,
Luis Vegaa27dc532022-11-11 20:10:49 +00005149 progress_timeout=self.timeout.progress_primitive,
5150 total_timeout=self.timeout.primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005151 db_dict=db_dict,
5152 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005153 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005154 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00005155 timeout=timeout or self.timeout.primitive,
garciadeblas5697b8b2021-03-24 09:17:02 +01005156 )
quilesj7e13aeb2019-10-08 13:34:55 +02005157 # execution was OK
5158 break
tierno067e04a2020-03-31 12:53:13 +00005159 except asyncio.CancelledError:
5160 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005161 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005162 retries -= 1
5163 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005164 self.logger.debug(
5165 "Error executing action {} on {} -> {}".format(
5166 primitive, ee_id, e
5167 )
5168 )
quilesj7e13aeb2019-10-08 13:34:55 +02005169 # wait and retry
Dario Faccin1df4ede2023-06-01 10:15:34 +02005170 await asyncio.sleep(retries_interval)
tierno73d8bd02019-11-18 17:33:27 +00005171 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005172 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005173 e = N2VCException(
5174 message="Timed out waiting for action to complete"
5175 )
5176 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005177
garciadeblas5697b8b2021-03-24 09:17:02 +01005178 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005179
tierno067e04a2020-03-31 12:53:13 +00005180 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005181 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005182 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005183 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005184
ksaikiranr3fde2c72021-03-15 10:39:06 +05305185 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5186 """
5187 Updating the vca_status with latest juju information in nsrs record
5188 :param: nsr_id: Id of the nsr
5189 :param: nslcmop_id: Id of the nslcmop
5190 :return: None
5191 """
5192
5193 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5194 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005195 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005196 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005197 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5198 cluster_uuid, kdu_instance, cluster_type = (
5199 k8s["k8scluster-uuid"],
5200 k8s["kdu-instance"],
5201 k8s["k8scluster-type"],
5202 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005203 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005204 cluster_uuid=cluster_uuid,
5205 kdu_instance=kdu_instance,
5206 filter={"_id": nsr_id},
5207 vca_id=vca_id,
5208 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005209 )
ksaikiranr656b6dd2021-02-19 10:25:18 +05305210 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005211 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305212 table, filter = "nsrs", {"_id": nsr_id}
5213 path = "_admin.deployed.VCA.{}.".format(vca_index)
5214 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305215
5216 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5217 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5218
tierno59d22d22018-09-25 18:10:19 +02005219 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005220 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005221 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005222 if not task_is_locked_by_me:
5223 return
5224
tierno59d22d22018-09-25 18:10:19 +02005225 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5226 self.logger.debug(logging_text + "Enter")
5227 # get all needed from database
5228 db_nsr = None
5229 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005230 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005231 db_nslcmop_update = {}
5232 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005233 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005234 exc = None
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005235 step = ""
tierno59d22d22018-09-25 18:10:19 +02005236 try:
kuused124bfe2019-06-18 12:09:24 +02005237 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005238 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005239 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005240
quilesj4cda56b2019-12-05 10:02:20 +00005241 self._write_ns_status(
5242 nsr_id=nsr_id,
5243 ns_state=None,
5244 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005245 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005246 )
5247
tierno59d22d22018-09-25 18:10:19 +02005248 step = "Getting information from database"
5249 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5250 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005251 if db_nslcmop["operationParams"].get("primitive_params"):
5252 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5253 db_nslcmop["operationParams"]["primitive_params"]
5254 )
tiernoda964822019-01-14 15:53:47 +00005255
tiernoe4f7e6c2018-11-27 14:55:30 +00005256 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005257 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005258 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005259 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005260 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005261 primitive = db_nslcmop["operationParams"]["primitive"]
5262 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005263 timeout_ns_action = db_nslcmop["operationParams"].get(
Luis Vegaa27dc532022-11-11 20:10:49 +00005264 "timeout_ns_action", self.timeout.primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01005265 )
tierno59d22d22018-09-25 18:10:19 +02005266
tierno1b633412019-02-25 16:48:23 +00005267 if vnf_index:
5268 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005269 db_vnfr = self.db.get_one(
5270 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5271 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005272 if db_vnfr.get("kdur"):
5273 kdur_list = []
5274 for kdur in db_vnfr["kdur"]:
5275 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005276 kdur["additionalParams"] = json.loads(
5277 kdur["additionalParams"]
5278 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005279 kdur_list.append(kdur)
5280 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005281 step = "Getting vnfd from database"
5282 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005283
5284 # Sync filesystem before running a primitive
5285 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005286 else:
tierno067e04a2020-03-31 12:53:13 +00005287 step = "Getting nsd from database"
5288 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005289
David Garciac1fe90a2021-03-31 19:12:02 +02005290 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005291 # for backward compatibility
5292 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5293 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5294 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5295 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5296
tiernoda964822019-01-14 15:53:47 +00005297 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005298 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005299 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005300 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005301 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005302 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005303 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005304 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005305 else:
tiernoa278b842020-07-08 15:33:55 +00005306 descriptor_configuration = db_nsd.get("ns-configuration")
5307
garciadeblas5697b8b2021-03-24 09:17:02 +01005308 if descriptor_configuration and descriptor_configuration.get(
5309 "config-primitive"
5310 ):
tiernoa278b842020-07-08 15:33:55 +00005311 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005312 if config_primitive["name"] == primitive:
5313 config_primitive_desc = config_primitive
5314 break
tiernoda964822019-01-14 15:53:47 +00005315
garciadeblas6bed6b32020-07-20 11:05:42 +00005316 if not config_primitive_desc:
5317 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005318 raise LcmException(
5319 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5320 primitive
5321 )
5322 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005323 primitive_name = primitive
5324 ee_descriptor_id = None
5325 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005326 primitive_name = config_primitive_desc.get(
5327 "execution-environment-primitive", primitive
5328 )
5329 ee_descriptor_id = config_primitive_desc.get(
5330 "execution-environment-ref"
5331 )
tierno1b633412019-02-25 16:48:23 +00005332
tierno1b633412019-02-25 16:48:23 +00005333 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005334 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005335 vdur = next(
5336 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5337 )
bravof922c4172020-11-24 21:21:43 -03005338 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005339 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005340 kdur = next(
5341 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5342 )
bravof922c4172020-11-24 21:21:43 -03005343 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005344 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005345 desc_params = parse_yaml_strings(
5346 db_vnfr.get("additionalParamsForVnf")
5347 )
tierno1b633412019-02-25 16:48:23 +00005348 else:
bravof922c4172020-11-24 21:21:43 -03005349 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005350 if kdu_name and get_configuration(db_vnfd, kdu_name):
5351 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005352 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005353 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005354 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005355 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005356 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005357 kdu = find_in_list(
5358 nsr_deployed["K8s"],
5359 lambda kdu: kdu_name == kdu["kdu-name"]
5360 and kdu["member-vnf-index"] == vnf_index,
5361 )
5362 kdu_action = (
5363 True
5364 if primitive_name in actions
5365 and kdu["k8scluster-type"] not in ("helm-chart", "helm-chart-v3")
5366 else False
5367 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005368
tiernoda964822019-01-14 15:53:47 +00005369 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005370 if kdu_name and (
5371 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5372 ):
tierno067e04a2020-03-31 12:53:13 +00005373 # kdur and desc_params already set from before
5374 if primitive_params:
5375 desc_params.update(primitive_params)
5376 # TODO Check if we will need something at vnf level
5377 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005378 if (
5379 kdu_name == kdu["kdu-name"]
5380 and kdu["member-vnf-index"] == vnf_index
5381 ):
tierno067e04a2020-03-31 12:53:13 +00005382 break
5383 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005384 raise LcmException(
5385 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5386 )
quilesj7e13aeb2019-10-08 13:34:55 +02005387
tierno067e04a2020-03-31 12:53:13 +00005388 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005389 msg = "unknown k8scluster-type '{}'".format(
5390 kdu.get("k8scluster-type")
5391 )
tierno067e04a2020-03-31 12:53:13 +00005392 raise LcmException(msg)
5393
garciadeblas5697b8b2021-03-24 09:17:02 +01005394 db_dict = {
5395 "collection": "nsrs",
5396 "filter": {"_id": nsr_id},
5397 "path": "_admin.deployed.K8s.{}".format(index),
5398 }
5399 self.logger.debug(
5400 logging_text
5401 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5402 )
tiernoa278b842020-07-08 15:33:55 +00005403 step = "Executing kdu {}".format(primitive_name)
5404 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00005405 if desc_params.get("kdu_model"):
5406 kdu_model = desc_params.get("kdu_model")
5407 del desc_params["kdu_model"]
5408 else:
5409 kdu_model = kdu.get("kdu-model")
Dario Faccin1df4ede2023-06-01 10:15:34 +02005410 if kdu_model.count("/") < 2: # helm chart is not embedded
5411 parts = kdu_model.split(sep=":")
5412 if len(parts) == 2:
5413 kdu_model = parts[0]
limondd8b0a62022-10-28 10:39:16 +02005414 if desc_params.get("kdu_atomic_upgrade"):
garciadeblasfb1e25f2022-11-18 14:36:22 +01005415 atomic_upgrade = desc_params.get(
5416 "kdu_atomic_upgrade"
5417 ).lower() in ("yes", "true", "1")
limondd8b0a62022-10-28 10:39:16 +02005418 del desc_params["kdu_atomic_upgrade"]
5419 else:
5420 atomic_upgrade = True
tierno067e04a2020-03-31 12:53:13 +00005421
5422 detailed_status = await asyncio.wait_for(
5423 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5424 cluster_uuid=kdu.get("k8scluster-uuid"),
5425 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005426 atomic=atomic_upgrade,
garciadeblas5697b8b2021-03-24 09:17:02 +01005427 kdu_model=kdu_model,
5428 params=desc_params,
5429 db_dict=db_dict,
5430 timeout=timeout_ns_action,
5431 ),
5432 timeout=timeout_ns_action + 10,
5433 )
5434 self.logger.debug(
5435 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5436 )
tiernoa278b842020-07-08 15:33:55 +00005437 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005438 detailed_status = await asyncio.wait_for(
5439 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5440 cluster_uuid=kdu.get("k8scluster-uuid"),
5441 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005442 db_dict=db_dict,
5443 ),
5444 timeout=timeout_ns_action,
5445 )
tiernoa278b842020-07-08 15:33:55 +00005446 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005447 detailed_status = await asyncio.wait_for(
5448 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5449 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005450 kdu_instance=kdu.get("kdu-instance"),
5451 vca_id=vca_id,
5452 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005453 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005454 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005455 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005456 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5457 kdu["kdu-name"], nsr_id
5458 )
5459 params = self._map_primitive_params(
5460 config_primitive_desc, primitive_params, desc_params
5461 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005462
5463 detailed_status = await asyncio.wait_for(
5464 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5465 cluster_uuid=kdu.get("k8scluster-uuid"),
5466 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005467 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005468 params=params,
5469 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005470 timeout=timeout_ns_action,
5471 vca_id=vca_id,
5472 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005473 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005474 )
tierno067e04a2020-03-31 12:53:13 +00005475
5476 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005477 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005478 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005479 detailed_status = ""
5480 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005481 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005482 ee_id, vca_type = self._look_for_deployed_vca(
5483 nsr_deployed["VCA"],
5484 member_vnf_index=vnf_index,
5485 vdu_id=vdu_id,
5486 vdu_count_index=vdu_count_index,
5487 ee_descriptor_id=ee_descriptor_id,
5488 )
5489 for vca_index, vca_deployed in enumerate(
5490 db_nsr["_admin"]["deployed"]["VCA"]
5491 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305492 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005493 db_dict = {
5494 "collection": "nsrs",
5495 "filter": {"_id": nsr_id},
5496 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5497 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305498 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005499 (
5500 nslcmop_operation_state,
5501 detailed_status,
5502 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005503 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005504 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005505 primitive_params=self._map_primitive_params(
5506 config_primitive_desc, primitive_params, desc_params
5507 ),
tierno588547c2020-07-01 15:30:20 +00005508 timeout=timeout_ns_action,
5509 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005510 db_dict=db_dict,
5511 vca_id=vca_id,
5512 )
tierno067e04a2020-03-31 12:53:13 +00005513
5514 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005515 error_description_nslcmop = (
5516 detailed_status if nslcmop_operation_state == "FAILED" else ""
5517 )
5518 self.logger.debug(
5519 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005520 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005521 nslcmop_operation_state, detailed_status
5522 )
5523 )
tierno59d22d22018-09-25 18:10:19 +02005524 return # database update is called inside finally
5525
tiernof59ad6c2020-04-08 12:50:52 +00005526 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005527 self.logger.error(logging_text + "Exit Exception {}".format(e))
5528 exc = e
5529 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005530 self.logger.error(
5531 logging_text + "Cancelled Exception while '{}'".format(step)
5532 )
tierno59d22d22018-09-25 18:10:19 +02005533 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005534 except asyncio.TimeoutError:
5535 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5536 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005537 except Exception as e:
5538 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005539 self.logger.critical(
5540 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5541 exc_info=True,
5542 )
tierno59d22d22018-09-25 18:10:19 +02005543 finally:
tierno067e04a2020-03-31 12:53:13 +00005544 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005545 db_nslcmop_update[
5546 "detailed-status"
5547 ] = (
5548 detailed_status
5549 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005550 nslcmop_operation_state = "FAILED"
5551 if db_nsr:
5552 self._write_ns_status(
5553 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005554 ns_state=db_nsr[
5555 "nsState"
5556 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005557 current_operation="IDLE",
5558 current_operation_id=None,
5559 # error_description=error_description_nsr,
5560 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005561 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005562 )
5563
garciadeblas5697b8b2021-03-24 09:17:02 +01005564 self._write_op_status(
5565 op_id=nslcmop_id,
5566 stage="",
5567 error_message=error_description_nslcmop,
5568 operation_state=nslcmop_operation_state,
5569 other_update=db_nslcmop_update,
5570 )
tierno067e04a2020-03-31 12:53:13 +00005571
tierno59d22d22018-09-25 18:10:19 +02005572 if nslcmop_operation_state:
5573 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005574 await self.msg.aiowrite(
5575 "ns",
5576 "actioned",
5577 {
5578 "nsr_id": nsr_id,
5579 "nslcmop_id": nslcmop_id,
5580 "operationState": nslcmop_operation_state,
5581 },
garciadeblas5697b8b2021-03-24 09:17:02 +01005582 )
tierno59d22d22018-09-25 18:10:19 +02005583 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005584 self.logger.error(
5585 logging_text + "kafka_write notification Exception {}".format(e)
5586 )
tierno59d22d22018-09-25 18:10:19 +02005587 self.logger.debug(logging_text + "Exit")
5588 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005589 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005590
elumalaica7ece02022-04-12 12:47:32 +05305591 async def terminate_vdus(
5592 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5593 ):
5594 """This method terminates VDUs
5595
5596 Args:
5597 db_vnfr: VNF instance record
5598 member_vnf_index: VNF index to identify the VDUs to be removed
5599 db_nsr: NS instance record
5600 update_db_nslcmops: Nslcmop update record
5601 """
5602 vca_scaling_info = []
5603 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5604 scaling_info["scaling_direction"] = "IN"
5605 scaling_info["vdu-delete"] = {}
5606 scaling_info["kdu-delete"] = {}
5607 db_vdur = db_vnfr.get("vdur")
5608 vdur_list = copy(db_vdur)
5609 count_index = 0
5610 for index, vdu in enumerate(vdur_list):
5611 vca_scaling_info.append(
5612 {
5613 "osm_vdu_id": vdu["vdu-id-ref"],
5614 "member-vnf-index": member_vnf_index,
5615 "type": "delete",
5616 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005617 }
5618 )
elumalaica7ece02022-04-12 12:47:32 +05305619 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5620 scaling_info["vdu"].append(
5621 {
5622 "name": vdu.get("name") or vdu.get("vdu-name"),
5623 "vdu_id": vdu["vdu-id-ref"],
5624 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005625 }
5626 )
elumalaica7ece02022-04-12 12:47:32 +05305627 for interface in vdu["interfaces"]:
5628 scaling_info["vdu"][index]["interface"].append(
5629 {
5630 "name": interface["name"],
5631 "ip_address": interface["ip-address"],
5632 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005633 }
5634 )
elumalaica7ece02022-04-12 12:47:32 +05305635 self.logger.info("NS update scaling info{}".format(scaling_info))
5636 stage[2] = "Terminating VDUs"
5637 if scaling_info.get("vdu-delete"):
5638 # scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00005639 if self.ro_config.ng:
elumalaica7ece02022-04-12 12:47:32 +05305640 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005641 logging_text,
5642 db_nsr,
5643 update_db_nslcmops,
5644 db_vnfr,
5645 scaling_info,
5646 stage,
elumalaica7ece02022-04-12 12:47:32 +05305647 )
5648
preethika.p28b0bf82022-09-23 07:36:28 +00005649 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305650 """This method is to Remove VNF instances from NS.
5651
5652 Args:
5653 nsr_id: NS instance id
5654 nslcmop_id: nslcmop id of update
5655 vnf_instance_id: id of the VNF instance to be removed
5656
5657 Returns:
5658 result: (str, str) COMPLETED/FAILED, details
5659 """
5660 try:
5661 db_nsr_update = {}
5662 logging_text = "Task ns={} update ".format(nsr_id)
5663 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5664 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5665 if check_vnfr_count > 1:
5666 stage = ["", "", ""]
5667 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005668 self.logger.debug(
5669 step + " after having waited for previous tasks to be completed"
5670 )
elumalaica7ece02022-04-12 12:47:32 +05305671 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5672 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5673 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5674 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5675 """ db_vnfr = self.db.get_one(
5676 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5677
5678 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005679 await self.terminate_vdus(
5680 db_vnfr,
5681 member_vnf_index,
5682 db_nsr,
5683 update_db_nslcmops,
5684 stage,
5685 logging_text,
5686 )
elumalaica7ece02022-04-12 12:47:32 +05305687
5688 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5689 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005690 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5691 "constituent-vnfr-ref"
5692 )
elumalaica7ece02022-04-12 12:47:32 +05305693 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5694 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5695 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5696 return "COMPLETED", "Done"
5697 else:
5698 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005699 raise LcmException(
5700 "{} Cannot terminate the last VNF in this NS.".format(
5701 vnf_instance_id
5702 )
5703 )
elumalaica7ece02022-04-12 12:47:32 +05305704 except (LcmException, asyncio.CancelledError):
5705 raise
5706 except Exception as e:
5707 self.logger.debug("Error removing VNF {}".format(e))
5708 return "FAILED", "Error removing VNF {}".format(e)
5709
elumalaib9e357c2022-04-27 09:58:38 +05305710 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005711 self,
5712 nsr_id,
5713 nslcmop_id,
5714 db_vnfd,
5715 db_vnfr,
5716 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305717 ):
5718 """This method updates and redeploys VNF instances
5719
5720 Args:
5721 nsr_id: NS instance id
5722 nslcmop_id: nslcmop id
5723 db_vnfd: VNF descriptor
5724 db_vnfr: VNF instance record
5725 db_nsr: NS instance record
5726
5727 Returns:
5728 result: (str, str) COMPLETED/FAILED, details
5729 """
5730 try:
5731 count_index = 0
5732 stage = ["", "", ""]
5733 logging_text = "Task ns={} update ".format(nsr_id)
5734 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5735 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5736
5737 # Terminate old VNF resources
5738 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005739 await self.terminate_vdus(
5740 db_vnfr,
5741 member_vnf_index,
5742 db_nsr,
5743 update_db_nslcmops,
5744 stage,
5745 logging_text,
5746 )
elumalaib9e357c2022-04-27 09:58:38 +05305747
5748 # old_vnfd_id = db_vnfr["vnfd-id"]
5749 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5750 new_db_vnfd = db_vnfd
5751 # new_vnfd_ref = new_db_vnfd["id"]
5752 # new_vnfd_id = vnfd_id
5753
5754 # Create VDUR
5755 new_vnfr_cp = []
5756 for cp in new_db_vnfd.get("ext-cpd", ()):
5757 vnf_cp = {
5758 "name": cp.get("id"),
5759 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5760 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5761 "id": cp.get("id"),
5762 }
5763 new_vnfr_cp.append(vnf_cp)
5764 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5765 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5766 # 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 +00005767 new_vnfr_update = {
5768 "revision": latest_vnfd_revision,
5769 "connection-point": new_vnfr_cp,
5770 "vdur": new_vdur,
5771 "ip-address": "",
5772 }
elumalaib9e357c2022-04-27 09:58:38 +05305773 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5774 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005775 "vnfrs",
5776 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305777 )
5778
5779 # Instantiate new VNF resources
5780 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5781 vca_scaling_info = []
5782 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5783 scaling_info["scaling_direction"] = "OUT"
5784 scaling_info["vdu-create"] = {}
5785 scaling_info["kdu-create"] = {}
5786 vdud_instantiate_list = db_vnfd["vdu"]
5787 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005788 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305789 if cloud_init_text:
5790 additional_params = (
5791 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5792 or {}
5793 )
5794 cloud_init_list = []
5795 if cloud_init_text:
5796 # TODO Information of its own ip is not available because db_vnfr is not updated.
5797 additional_params["OSM"] = get_osm_params(
5798 updated_db_vnfr, vdud["id"], 1
5799 )
5800 cloud_init_list.append(
5801 self._parse_cloud_init(
5802 cloud_init_text,
5803 additional_params,
5804 db_vnfd["id"],
5805 vdud["id"],
5806 )
5807 )
5808 vca_scaling_info.append(
5809 {
5810 "osm_vdu_id": vdud["id"],
5811 "member-vnf-index": member_vnf_index,
5812 "type": "create",
5813 "vdu_index": count_index,
5814 }
5815 )
5816 scaling_info["vdu-create"][vdud["id"]] = count_index
Luis Vegaa27dc532022-11-11 20:10:49 +00005817 if self.ro_config.ng:
elumalaib9e357c2022-04-27 09:58:38 +05305818 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005819 "New Resources to be deployed: {}".format(scaling_info)
5820 )
elumalaib9e357c2022-04-27 09:58:38 +05305821 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005822 logging_text,
5823 db_nsr,
5824 update_db_nslcmops,
5825 updated_db_vnfr,
5826 scaling_info,
5827 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305828 )
5829 return "COMPLETED", "Done"
5830 except (LcmException, asyncio.CancelledError):
5831 raise
5832 except Exception as e:
5833 self.logger.debug("Error updating VNF {}".format(e))
5834 return "FAILED", "Error updating VNF {}".format(e)
5835
aticigdffa6212022-04-12 15:27:53 +03005836 async def _ns_charm_upgrade(
5837 self,
5838 ee_id,
5839 charm_id,
5840 charm_type,
5841 path,
5842 timeout: float = None,
5843 ) -> (str, str):
5844 """This method upgrade charms in VNF instances
5845
5846 Args:
5847 ee_id: Execution environment id
5848 path: Local path to the charm
5849 charm_id: charm-id
5850 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5851 timeout: (Float) Timeout for the ns update operation
5852
5853 Returns:
5854 result: (str, str) COMPLETED/FAILED, details
5855 """
5856 try:
5857 charm_type = charm_type or "lxc_proxy_charm"
5858 output = await self.vca_map[charm_type].upgrade_charm(
5859 ee_id=ee_id,
5860 path=path,
5861 charm_id=charm_id,
5862 charm_type=charm_type,
Luis Vegaa27dc532022-11-11 20:10:49 +00005863 timeout=timeout or self.timeout.ns_update,
aticigdffa6212022-04-12 15:27:53 +03005864 )
5865
5866 if output:
5867 return "COMPLETED", output
5868
5869 except (LcmException, asyncio.CancelledError):
5870 raise
5871
5872 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005873 self.logger.debug("Error upgrading charm {}".format(path))
5874
5875 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5876
5877 async def update(self, nsr_id, nslcmop_id):
5878 """Update NS according to different update types
5879
5880 This method performs upgrade of VNF instances then updates the revision
5881 number in VNF record
5882
5883 Args:
5884 nsr_id: Network service will be updated
5885 nslcmop_id: ns lcm operation id
5886
5887 Returns:
5888 It may raise DbException, LcmException, N2VCException, K8sException
5889
5890 """
5891 # Try to lock HA task here
5892 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5893 if not task_is_locked_by_me:
5894 return
5895
5896 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5897 self.logger.debug(logging_text + "Enter")
5898
5899 # Set the required variables to be filled up later
5900 db_nsr = None
5901 db_nslcmop_update = {}
5902 vnfr_update = {}
5903 nslcmop_operation_state = None
5904 db_nsr_update = {}
5905 error_description_nslcmop = ""
5906 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305907 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005908 detailed_status = ""
Gabriel Cuba411af2e2023-01-06 17:23:22 -05005909 member_vnf_index = None
aticigdffa6212022-04-12 15:27:53 +03005910
5911 try:
5912 # wait for any previous tasks in process
5913 step = "Waiting for previous operations to terminate"
5914 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5915 self._write_ns_status(
5916 nsr_id=nsr_id,
5917 ns_state=None,
5918 current_operation="UPDATING",
5919 current_operation_id=nslcmop_id,
5920 )
5921
5922 step = "Getting nslcmop from database"
5923 db_nslcmop = self.db.get_one(
5924 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5925 )
5926 update_type = db_nslcmop["operationParams"]["updateType"]
5927
5928 step = "Getting nsr from database"
5929 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5930 old_operational_status = db_nsr["operational-status"]
5931 db_nsr_update["operational-status"] = "updating"
5932 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5933 nsr_deployed = db_nsr["_admin"].get("deployed")
5934
5935 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005936 # Get the input parameters given through update request
5937 vnf_instance_id = db_nslcmop["operationParams"][
5938 "changeVnfPackageData"
5939 ].get("vnfInstanceId")
5940
5941 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5942 "vnfdId"
5943 )
5944 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5945
5946 step = "Getting vnfr from database"
5947 db_vnfr = self.db.get_one(
5948 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5949 )
5950
5951 step = "Getting vnfds from database"
5952 # Latest VNFD
5953 latest_vnfd = self.db.get_one(
5954 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5955 )
5956 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5957
5958 # Current VNFD
5959 current_vnf_revision = db_vnfr.get("revision", 1)
5960 current_vnfd = self.db.get_one(
5961 "vnfds_revisions",
5962 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5963 fail_on_empty=False,
5964 )
5965 # Charm artifact paths will be filled up later
5966 (
5967 current_charm_artifact_path,
5968 target_charm_artifact_path,
5969 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005970 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005971 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005972
5973 step = "Checking if revision has changed in VNFD"
5974 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305975 change_type = "policy_updated"
5976
aticigdffa6212022-04-12 15:27:53 +03005977 # There is new revision of VNFD, update operation is required
5978 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005979 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005980
5981 step = "Removing the VNFD packages if they exist in the local path"
5982 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5983 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5984
5985 step = "Get the VNFD packages from FSMongo"
5986 self.fs.sync(from_path=latest_vnfd_path)
5987 self.fs.sync(from_path=current_vnfd_path)
5988
5989 step = (
5990 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5991 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005992 current_base_folder = current_vnfd["_admin"]["storage"]
5993 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005994
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005995 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005996 get_iterable(nsr_deployed, "VCA")
5997 ):
5998 vnf_index = db_vnfr.get("member-vnf-index-ref")
5999
6000 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006001 if vca_deployed.get("member-vnf-index") == vnf_index:
6002 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6003 vca_type = vca_deployed.get("type")
6004 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03006005
6006 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006007 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03006008
6009 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03006010 if current_vnfd.get("kdu"):
aticig1dda84c2022-09-10 01:56:58 +03006011 search_key = "kdu_name"
6012 else:
6013 search_key = "vnfd_id"
6014
6015 entity_id = vca_deployed.get(search_key)
6016
aticigdffa6212022-04-12 15:27:53 +03006017 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03006018 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03006019 )
6020
6021 if "execution-environment-list" in descriptor_config:
6022 ee_list = descriptor_config.get(
6023 "execution-environment-list", []
6024 )
6025 else:
6026 ee_list = []
6027
6028 # There could be several charm used in the same VNF
6029 for ee_item in ee_list:
6030 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03006031 step = "Getting charm name"
6032 charm_name = ee_item["juju"].get("charm")
6033
6034 step = "Setting Charm artifact paths"
6035 current_charm_artifact_path.append(
6036 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006037 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03006038 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006039 vca_type,
aticigdffa6212022-04-12 15:27:53 +03006040 current_vnf_revision,
6041 )
6042 )
6043 target_charm_artifact_path.append(
6044 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006045 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03006046 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006047 vca_type,
aticigd7083542022-05-30 20:45:55 +03006048 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03006049 )
6050 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006051 elif ee_item.get("helm-chart"):
6052 # add chart to list and all parameters
6053 step = "Getting helm chart name"
6054 chart_name = ee_item.get("helm-chart")
garciadeblasfb1e25f2022-11-18 14:36:22 +01006055 if (
6056 ee_item.get("helm-version")
6057 and ee_item.get("helm-version") == "v2"
6058 ):
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006059 vca_type = "helm"
6060 else:
6061 vca_type = "helm-v3"
6062 step = "Setting Helm chart artifact paths"
6063
garciadeblasfb1e25f2022-11-18 14:36:22 +01006064 helm_artifacts.append(
6065 {
6066 "current_artifact_path": get_charm_artifact_path(
6067 current_base_folder,
6068 chart_name,
6069 vca_type,
6070 current_vnf_revision,
6071 ),
6072 "target_artifact_path": get_charm_artifact_path(
6073 latest_base_folder,
6074 chart_name,
6075 vca_type,
6076 latest_vnfd_revision,
6077 ),
6078 "ee_id": ee_id,
6079 "vca_index": vca_index,
6080 "vdu_index": vdu_count_index,
6081 }
6082 )
aticigdffa6212022-04-12 15:27:53 +03006083
6084 charm_artifact_paths = zip(
6085 current_charm_artifact_path, target_charm_artifact_path
6086 )
6087
6088 step = "Checking if software version has changed in VNFD"
6089 if find_software_version(current_vnfd) != find_software_version(
6090 latest_vnfd
6091 ):
aticigdffa6212022-04-12 15:27:53 +03006092 step = "Checking if existing VNF has charm"
6093 for current_charm_path, target_charm_path in list(
6094 charm_artifact_paths
6095 ):
6096 if current_charm_path:
6097 raise LcmException(
6098 "Software version change is not supported as VNF instance {} has charm.".format(
6099 vnf_instance_id
6100 )
6101 )
6102
6103 # There is no change in the charm package, then redeploy the VNF
6104 # based on new descriptor
6105 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306106 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006107 (result, detailed_status) = await self._ns_redeploy_vnf(
6108 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306109 )
6110 if result == "FAILED":
6111 nslcmop_operation_state = result
6112 error_description_nslcmop = detailed_status
6113 db_nslcmop_update["detailed-status"] = detailed_status
6114 self.logger.debug(
6115 logging_text
6116 + " step {} Done with result {} {}".format(
6117 step, nslcmop_operation_state, detailed_status
6118 )
6119 )
aticigdffa6212022-04-12 15:27:53 +03006120
6121 else:
6122 step = "Checking if any charm package has changed or not"
6123 for current_charm_path, target_charm_path in list(
6124 charm_artifact_paths
6125 ):
6126 if (
6127 current_charm_path
6128 and target_charm_path
6129 and self.check_charm_hash_changed(
6130 current_charm_path, target_charm_path
6131 )
6132 ):
aticigdffa6212022-04-12 15:27:53 +03006133 step = "Checking whether VNF uses juju bundle"
6134 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03006135 raise LcmException(
6136 "Charm upgrade is not supported for the instance which"
6137 " uses juju-bundle: {}".format(
6138 check_juju_bundle_existence(current_vnfd)
6139 )
6140 )
6141
6142 step = "Upgrading Charm"
6143 (
6144 result,
6145 detailed_status,
6146 ) = await self._ns_charm_upgrade(
6147 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006148 charm_id=vca_id,
6149 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006150 path=self.fs.path + target_charm_path,
6151 timeout=timeout_seconds,
6152 )
6153
6154 if result == "FAILED":
6155 nslcmop_operation_state = result
6156 error_description_nslcmop = detailed_status
6157
6158 db_nslcmop_update["detailed-status"] = detailed_status
6159 self.logger.debug(
6160 logging_text
6161 + " step {} Done with result {} {}".format(
6162 step, nslcmop_operation_state, detailed_status
6163 )
6164 )
6165
6166 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306167 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6168 result = "COMPLETED"
6169 detailed_status = "Done"
6170 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006171
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006172 # helm base EE
6173 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006174 if not (
6175 item["current_artifact_path"]
6176 and item["target_artifact_path"]
6177 and self.check_charm_hash_changed(
6178 item["current_artifact_path"],
6179 item["target_artifact_path"],
6180 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006181 ):
6182 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006183 db_update_entry = "_admin.deployed.VCA.{}.".format(
6184 item["vca_index"]
6185 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006186 vnfr_id = db_vnfr["_id"]
6187 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6188 db_dict = {
6189 "collection": "nsrs",
6190 "filter": {"_id": nsr_id},
6191 "path": db_update_entry,
6192 }
6193 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006194 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006195 namespace=namespace,
6196 helm_id=helm_id,
6197 db_dict=db_dict,
6198 config=osm_config,
6199 artifact_path=item["target_artifact_path"],
6200 vca_type=vca_type,
6201 )
6202 vnf_id = db_vnfr.get("vnfd-ref")
6203 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6204 self.logger.debug("get ssh key block")
6205 rw_mgmt_ip = None
6206 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006207 config_descriptor,
6208 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006209 ):
6210 # Needed to inject a ssh key
6211 user = deep_get(
6212 config_descriptor,
6213 ("config-access", "ssh-access", "default-user"),
6214 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006215 step = (
6216 "Install configuration Software, getting public ssh key"
6217 )
6218 pub_key = await self.vca_map[
6219 vca_type
6220 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006221 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6222 )
6223
garciadeblasfb1e25f2022-11-18 14:36:22 +01006224 step = (
6225 "Insert public key into VM user={} ssh_key={}".format(
6226 user, pub_key
6227 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006228 )
6229 self.logger.debug(logging_text + step)
6230
6231 # wait for RO (ip-address) Insert pub_key into VM
6232 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6233 logging_text,
6234 nsr_id,
6235 vnfr_id,
6236 None,
6237 item["vdu_index"],
6238 user=user,
6239 pub_key=pub_key,
6240 )
6241
6242 initial_config_primitive_list = config_descriptor.get(
6243 "initial-config-primitive"
6244 )
6245 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006246 (
6247 p
6248 for p in initial_config_primitive_list
6249 if p["name"] == "config"
6250 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006251 None,
6252 )
6253 if not config_primitive:
6254 continue
6255
6256 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6257 if rw_mgmt_ip:
6258 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6259 if db_vnfr.get("additionalParamsForVnf"):
6260 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006261 parse_yaml_strings(
6262 db_vnfr["additionalParamsForVnf"].copy()
6263 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006264 )
6265 primitive_params_ = self._map_primitive_params(
6266 config_primitive, {}, deploy_params
6267 )
6268
6269 step = "execute primitive '{}' params '{}'".format(
6270 config_primitive["name"], primitive_params_
6271 )
6272 self.logger.debug(logging_text + step)
6273 await self.vca_map[vca_type].exec_primitive(
6274 ee_id=ee_id,
6275 primitive_name=config_primitive["name"],
6276 params_dict=primitive_params_,
6277 db_dict=db_dict,
6278 vca_id=vca_id,
6279 vca_type=vca_type,
6280 )
6281
6282 step = "Updating policies"
6283 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6284 detailed_status = "Done"
6285 db_nslcmop_update["detailed-status"] = "Done"
6286
aticigdffa6212022-04-12 15:27:53 +03006287 # If nslcmop_operation_state is None, so any operation is not failed.
6288 if not nslcmop_operation_state:
6289 nslcmop_operation_state = "COMPLETED"
6290
6291 # If update CHANGE_VNFPKG nslcmop_operation is successful
6292 # vnf revision need to be updated
6293 vnfr_update["revision"] = latest_vnfd_revision
6294 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6295
6296 self.logger.debug(
6297 logging_text
6298 + " task Done with result {} {}".format(
6299 nslcmop_operation_state, detailed_status
6300 )
6301 )
6302 elif update_type == "REMOVE_VNF":
6303 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306304 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6305 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6306 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6307 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006308 (result, detailed_status) = await self.remove_vnf(
6309 nsr_id, nslcmop_id, vnf_instance_id
6310 )
elumalaica7ece02022-04-12 12:47:32 +05306311 if result == "FAILED":
6312 nslcmop_operation_state = result
6313 error_description_nslcmop = detailed_status
6314 db_nslcmop_update["detailed-status"] = detailed_status
6315 change_type = "vnf_terminated"
6316 if not nslcmop_operation_state:
6317 nslcmop_operation_state = "COMPLETED"
6318 self.logger.debug(
6319 logging_text
6320 + " task Done with result {} {}".format(
6321 nslcmop_operation_state, detailed_status
6322 )
6323 )
aticigdffa6212022-04-12 15:27:53 +03006324
k4.rahulb827de92022-05-02 16:35:02 +00006325 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006326 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6327 "vnfInstanceId"
6328 ]
6329 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6330 "changeStateTo"
6331 ]
6332 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6333 "additionalParam"
6334 ]
k4.rahulb827de92022-05-02 16:35:02 +00006335 (result, detailed_status) = await self.rebuild_start_stop(
6336 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006337 )
k4.rahulb827de92022-05-02 16:35:02 +00006338 if result == "FAILED":
6339 nslcmop_operation_state = result
6340 error_description_nslcmop = detailed_status
6341 db_nslcmop_update["detailed-status"] = detailed_status
6342 if not nslcmop_operation_state:
6343 nslcmop_operation_state = "COMPLETED"
6344 self.logger.debug(
6345 logging_text
6346 + " task Done with result {} {}".format(
6347 nslcmop_operation_state, detailed_status
6348 )
6349 )
6350
aticigdffa6212022-04-12 15:27:53 +03006351 # If nslcmop_operation_state is None, so any operation is not failed.
6352 # All operations are executed in overall.
6353 if not nslcmop_operation_state:
6354 nslcmop_operation_state = "COMPLETED"
6355 db_nsr_update["operational-status"] = old_operational_status
6356
6357 except (DbException, LcmException, N2VCException, K8sException) as e:
6358 self.logger.error(logging_text + "Exit Exception {}".format(e))
6359 exc = e
6360 except asyncio.CancelledError:
6361 self.logger.error(
6362 logging_text + "Cancelled Exception while '{}'".format(step)
6363 )
6364 exc = "Operation was cancelled"
6365 except asyncio.TimeoutError:
6366 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6367 exc = "Timeout"
6368 except Exception as e:
6369 exc = traceback.format_exc()
6370 self.logger.critical(
6371 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6372 exc_info=True,
6373 )
6374 finally:
6375 if exc:
6376 db_nslcmop_update[
6377 "detailed-status"
6378 ] = (
6379 detailed_status
6380 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6381 nslcmop_operation_state = "FAILED"
6382 db_nsr_update["operational-status"] = old_operational_status
6383 if db_nsr:
6384 self._write_ns_status(
6385 nsr_id=nsr_id,
6386 ns_state=db_nsr["nsState"],
6387 current_operation="IDLE",
6388 current_operation_id=None,
6389 other_update=db_nsr_update,
6390 )
6391
6392 self._write_op_status(
6393 op_id=nslcmop_id,
6394 stage="",
6395 error_message=error_description_nslcmop,
6396 operation_state=nslcmop_operation_state,
6397 other_update=db_nslcmop_update,
6398 )
6399
6400 if nslcmop_operation_state:
6401 try:
elumalaica7ece02022-04-12 12:47:32 +05306402 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306403 "nsr_id": nsr_id,
6404 "nslcmop_id": nslcmop_id,
6405 "operationState": nslcmop_operation_state,
6406 }
Gabriel Cuba411af2e2023-01-06 17:23:22 -05006407 if (
6408 change_type in ("vnf_terminated", "policy_updated")
6409 and member_vnf_index
6410 ):
elumalaica7ece02022-04-12 12:47:32 +05306411 msg.update({"vnf_member_index": member_vnf_index})
Dario Faccin1df4ede2023-06-01 10:15:34 +02006412 await self.msg.aiowrite("ns", change_type, msg)
aticigdffa6212022-04-12 15:27:53 +03006413 except Exception as e:
6414 self.logger.error(
6415 logging_text + "kafka_write notification Exception {}".format(e)
6416 )
6417 self.logger.debug(logging_text + "Exit")
6418 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6419 return nslcmop_operation_state, detailed_status
6420
tierno59d22d22018-09-25 18:10:19 +02006421 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006422 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006423 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006424 if not task_is_locked_by_me:
6425 return
6426
tierno59d22d22018-09-25 18:10:19 +02006427 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006428 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006429 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006430 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006431 self.logger.debug(logging_text + "Enter")
6432 # get all needed from database
6433 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006434 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006435 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006436 exc = None
tierno9ab95942018-10-10 16:44:22 +02006437 # in case of error, indicates what part of scale was failed to put nsr at error status
6438 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006439 old_operational_status = ""
6440 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006441 nsi_id = None
tierno59d22d22018-09-25 18:10:19 +02006442 try:
kuused124bfe2019-06-18 12:09:24 +02006443 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006444 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006445 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6446 self._write_ns_status(
6447 nsr_id=nsr_id,
6448 ns_state=None,
6449 current_operation="SCALING",
6450 current_operation_id=nslcmop_id,
6451 )
quilesj4cda56b2019-12-05 10:02:20 +00006452
ikalyvas02d9e7b2019-05-27 18:16:01 +03006453 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006454 self.logger.debug(
6455 step + " after having waited for previous tasks to be completed"
6456 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006457 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006458
ikalyvas02d9e7b2019-05-27 18:16:01 +03006459 step = "Getting nsr from database"
6460 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006461 old_operational_status = db_nsr["operational-status"]
6462 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006463
tierno59d22d22018-09-25 18:10:19 +02006464 step = "Parsing scaling parameters"
6465 db_nsr_update["operational-status"] = "scaling"
6466 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006467 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006468
garciadeblas5697b8b2021-03-24 09:17:02 +01006469 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6470 "scaleByStepData"
6471 ]["member-vnf-index"]
6472 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6473 "scaleByStepData"
6474 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006475 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006476 # for backward compatibility
6477 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6478 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6479 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6480 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6481
tierno59d22d22018-09-25 18:10:19 +02006482 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006483 db_vnfr = self.db.get_one(
6484 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6485 )
bravof922c4172020-11-24 21:21:43 -03006486
David Garciac1fe90a2021-03-31 19:12:02 +02006487 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6488
tierno59d22d22018-09-25 18:10:19 +02006489 step = "Getting vnfd from database"
6490 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006491
aktas13251562021-02-12 22:19:10 +03006492 base_folder = db_vnfd["_admin"]["storage"]
6493
tierno59d22d22018-09-25 18:10:19 +02006494 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006495 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006496 get_scaling_aspect(db_vnfd),
6497 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006498 )
6499 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006500 raise LcmException(
6501 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6502 "at vnfd:scaling-group-descriptor".format(scaling_group)
6503 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006504
tierno15b1cf12019-08-29 13:21:40 +00006505 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006506 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006507 nb_scale_op = 0
6508 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006509 self.update_db_2(
6510 "nsrs",
6511 nsr_id,
6512 {
6513 "_admin.scaling-group": [
6514 {"name": scaling_group, "nb-scale-op": 0}
6515 ]
6516 },
6517 )
tierno59d22d22018-09-25 18:10:19 +02006518 admin_scale_index = 0
6519 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006520 for admin_scale_index, admin_scale_info in enumerate(
6521 db_nsr["_admin"]["scaling-group"]
6522 ):
tierno59d22d22018-09-25 18:10:19 +02006523 if admin_scale_info["name"] == scaling_group:
6524 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6525 break
tierno9ab95942018-10-10 16:44:22 +02006526 else: # not found, set index one plus last element and add new entry with the name
6527 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006528 db_nsr_update[
6529 "_admin.scaling-group.{}.name".format(admin_scale_index)
6530 ] = scaling_group
aktas5f75f102021-03-15 11:26:10 +03006531
6532 vca_scaling_info = []
6533 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006534 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006535 if "aspect-delta-details" not in scaling_descriptor:
6536 raise LcmException(
6537 "Aspect delta details not fount in scaling descriptor {}".format(
6538 scaling_descriptor["name"]
6539 )
6540 )
tierno59d22d22018-09-25 18:10:19 +02006541 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006542 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006543
aktas5f75f102021-03-15 11:26:10 +03006544 scaling_info["scaling_direction"] = "OUT"
6545 scaling_info["vdu-create"] = {}
6546 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006547 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006548 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006549 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006550 # vdu_index also provides the number of instance of the targeted vdu
6551 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
garciadeblas5697b8b2021-03-24 09:17:02 +01006552 cloud_init_text = self._get_vdu_cloud_init_content(
6553 vdud, db_vnfd
6554 )
tierno72ef84f2020-10-06 08:22:07 +00006555 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006556 additional_params = (
6557 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6558 or {}
6559 )
bravof832f8992020-12-07 12:57:31 -03006560 cloud_init_list = []
6561
6562 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6563 max_instance_count = 10
6564 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006565 max_instance_count = vdu_profile.get(
6566 "max-number-of-instances", 10
6567 )
6568
6569 default_instance_num = get_number_of_instances(
6570 db_vnfd, vdud["id"]
6571 )
aktas5f75f102021-03-15 11:26:10 +03006572 instances_number = vdu_delta.get("number-of-instances", 1)
6573 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006574
aktas5f75f102021-03-15 11:26:10 +03006575 new_instance_count = nb_scale_op + default_instance_num
6576 # Control if new count is over max and vdu count is less than max.
6577 # Then assign new instance count
6578 if new_instance_count > max_instance_count > vdu_count:
6579 instances_number = new_instance_count - max_instance_count
6580 else:
6581 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006582
aktas5f75f102021-03-15 11:26:10 +03006583 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006584 raise LcmException(
6585 "reached the limit of {} (max-instance-count) "
6586 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006587 "scaling-group-descriptor '{}'".format(
6588 nb_scale_op, scaling_group
6589 )
bravof922c4172020-11-24 21:21:43 -03006590 )
bravof832f8992020-12-07 12:57:31 -03006591 for x in range(vdu_delta.get("number-of-instances", 1)):
6592 if cloud_init_text:
6593 # TODO Information of its own ip is not available because db_vnfr is not updated.
6594 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006595 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006596 )
bravof832f8992020-12-07 12:57:31 -03006597 cloud_init_list.append(
6598 self._parse_cloud_init(
6599 cloud_init_text,
6600 additional_params,
6601 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006602 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006603 )
6604 )
aktas5f75f102021-03-15 11:26:10 +03006605 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006606 {
6607 "osm_vdu_id": vdu_delta["id"],
6608 "member-vnf-index": vnf_index,
6609 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006610 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006611 }
6612 )
aktas5f75f102021-03-15 11:26:10 +03006613 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6614 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006615 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006616 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006617 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006618
6619 # Might have different kdus in the same delta
6620 # Should have list for each kdu
6621 if not scaling_info["kdu-create"].get(kdu_name, None):
6622 scaling_info["kdu-create"][kdu_name] = []
6623
6624 kdur = get_kdur(db_vnfr, kdu_name)
6625 if kdur.get("helm-chart"):
6626 k8s_cluster_type = "helm-chart-v3"
6627 self.logger.debug("kdur: {}".format(kdur))
6628 if (
6629 kdur.get("helm-version")
6630 and kdur.get("helm-version") == "v2"
6631 ):
6632 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006633 elif kdur.get("juju-bundle"):
6634 k8s_cluster_type = "juju-bundle"
6635 else:
6636 raise LcmException(
6637 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6638 "juju-bundle. Maybe an old NBI version is running".format(
6639 db_vnfr["member-vnf-index-ref"], kdu_name
6640 )
6641 )
6642
6643 max_instance_count = 10
6644 if kdu_profile and "max-number-of-instances" in kdu_profile:
6645 max_instance_count = kdu_profile.get(
6646 "max-number-of-instances", 10
6647 )
6648
6649 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6650 deployed_kdu, _ = get_deployed_kdu(
6651 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006652 )
aktas5f75f102021-03-15 11:26:10 +03006653 if deployed_kdu is None:
6654 raise LcmException(
6655 "KDU '{}' for vnf '{}' not deployed".format(
6656 kdu_name, vnf_index
6657 )
6658 )
6659 kdu_instance = deployed_kdu.get("kdu-instance")
6660 instance_num = await self.k8scluster_map[
6661 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006662 ].get_scale_count(
6663 resource_name,
6664 kdu_instance,
6665 vca_id=vca_id,
6666 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6667 kdu_model=deployed_kdu.get("kdu-model"),
6668 )
aktas5f75f102021-03-15 11:26:10 +03006669 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006670 "number-of-instances", 1
6671 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006672
aktas5f75f102021-03-15 11:26:10 +03006673 # Control if new count is over max and instance_num is less than max.
6674 # Then assign max instance number to kdu replica count
6675 if kdu_replica_count > max_instance_count > instance_num:
6676 kdu_replica_count = max_instance_count
6677 if kdu_replica_count > max_instance_count:
6678 raise LcmException(
6679 "reached the limit of {} (max-instance-count) "
6680 "scaling-out operations for the "
6681 "scaling-group-descriptor '{}'".format(
6682 instance_num, scaling_group
6683 )
6684 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006685
aktas5f75f102021-03-15 11:26:10 +03006686 for x in range(kdu_delta.get("number-of-instances", 1)):
6687 vca_scaling_info.append(
6688 {
6689 "osm_kdu_id": kdu_name,
6690 "member-vnf-index": vnf_index,
6691 "type": "create",
6692 "kdu_index": instance_num + x - 1,
6693 }
6694 )
6695 scaling_info["kdu-create"][kdu_name].append(
6696 {
6697 "member-vnf-index": vnf_index,
6698 "type": "create",
6699 "k8s-cluster-type": k8s_cluster_type,
6700 "resource-name": resource_name,
6701 "scale": kdu_replica_count,
6702 }
6703 )
6704 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006705 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006706
6707 scaling_info["scaling_direction"] = "IN"
6708 scaling_info["vdu-delete"] = {}
6709 scaling_info["kdu-delete"] = {}
6710
bravof832f8992020-12-07 12:57:31 -03006711 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006712 for vdu_delta in delta.get("vdu-delta", {}):
6713 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006714 min_instance_count = 0
6715 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6716 if vdu_profile and "min-number-of-instances" in vdu_profile:
6717 min_instance_count = vdu_profile["min-number-of-instances"]
6718
garciadeblas5697b8b2021-03-24 09:17:02 +01006719 default_instance_num = get_number_of_instances(
6720 db_vnfd, vdu_delta["id"]
6721 )
aktas5f75f102021-03-15 11:26:10 +03006722 instance_num = vdu_delta.get("number-of-instances", 1)
6723 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006724
aktas5f75f102021-03-15 11:26:10 +03006725 new_instance_count = nb_scale_op + default_instance_num
6726
6727 if new_instance_count < min_instance_count < vdu_count:
6728 instances_number = min_instance_count - new_instance_count
6729 else:
6730 instances_number = instance_num
6731
6732 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006733 raise LcmException(
6734 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006735 "scaling-group-descriptor '{}'".format(
6736 nb_scale_op, scaling_group
6737 )
bravof832f8992020-12-07 12:57:31 -03006738 )
aktas13251562021-02-12 22:19:10 +03006739 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006740 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006741 {
6742 "osm_vdu_id": vdu_delta["id"],
6743 "member-vnf-index": vnf_index,
6744 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006745 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006746 }
6747 )
aktas5f75f102021-03-15 11:26:10 +03006748 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6749 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006750 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006751 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006752 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006753
6754 if not scaling_info["kdu-delete"].get(kdu_name, None):
6755 scaling_info["kdu-delete"][kdu_name] = []
6756
6757 kdur = get_kdur(db_vnfr, kdu_name)
6758 if kdur.get("helm-chart"):
6759 k8s_cluster_type = "helm-chart-v3"
6760 self.logger.debug("kdur: {}".format(kdur))
6761 if (
6762 kdur.get("helm-version")
6763 and kdur.get("helm-version") == "v2"
6764 ):
6765 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006766 elif kdur.get("juju-bundle"):
6767 k8s_cluster_type = "juju-bundle"
6768 else:
6769 raise LcmException(
6770 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6771 "juju-bundle. Maybe an old NBI version is running".format(
6772 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6773 )
6774 )
6775
6776 min_instance_count = 0
6777 if kdu_profile and "min-number-of-instances" in kdu_profile:
6778 min_instance_count = kdu_profile["min-number-of-instances"]
6779
6780 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6781 deployed_kdu, _ = get_deployed_kdu(
6782 nsr_deployed, kdu_name, vnf_index
6783 )
6784 if deployed_kdu is None:
6785 raise LcmException(
6786 "KDU '{}' for vnf '{}' not deployed".format(
6787 kdu_name, vnf_index
6788 )
6789 )
6790 kdu_instance = deployed_kdu.get("kdu-instance")
6791 instance_num = await self.k8scluster_map[
6792 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006793 ].get_scale_count(
6794 resource_name,
6795 kdu_instance,
6796 vca_id=vca_id,
6797 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6798 kdu_model=deployed_kdu.get("kdu-model"),
6799 )
aktas5f75f102021-03-15 11:26:10 +03006800 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006801 "number-of-instances", 1
6802 )
tierno59d22d22018-09-25 18:10:19 +02006803
aktas5f75f102021-03-15 11:26:10 +03006804 if kdu_replica_count < min_instance_count < instance_num:
6805 kdu_replica_count = min_instance_count
6806 if kdu_replica_count < min_instance_count:
6807 raise LcmException(
6808 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6809 "scaling-group-descriptor '{}'".format(
6810 instance_num, scaling_group
6811 )
6812 )
6813
6814 for x in range(kdu_delta.get("number-of-instances", 1)):
6815 vca_scaling_info.append(
6816 {
6817 "osm_kdu_id": kdu_name,
6818 "member-vnf-index": vnf_index,
6819 "type": "delete",
6820 "kdu_index": instance_num - x - 1,
6821 }
6822 )
6823 scaling_info["kdu-delete"][kdu_name].append(
6824 {
6825 "member-vnf-index": vnf_index,
6826 "type": "delete",
6827 "k8s-cluster-type": k8s_cluster_type,
6828 "resource-name": resource_name,
6829 "scale": kdu_replica_count,
6830 }
6831 )
6832
tierno59d22d22018-09-25 18:10:19 +02006833 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006834 vdu_delete = copy(scaling_info.get("vdu-delete"))
6835 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006836 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006837 if vdu_delete.get(vdur["vdu-id-ref"]):
6838 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006839 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006840 {
6841 "name": vdur.get("name") or vdur.get("vdu-name"),
6842 "vdu_id": vdur["vdu-id-ref"],
6843 "interface": [],
6844 }
6845 )
tierno59d22d22018-09-25 18:10:19 +02006846 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006847 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006848 {
6849 "name": interface["name"],
6850 "ip_address": interface["ip-address"],
6851 "mac_address": interface.get("mac-address"),
6852 }
6853 )
tierno2357f4e2020-10-19 16:38:59 +00006854 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006855
kuuseac3a8882019-10-03 10:48:06 +02006856 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006857 step = "Executing pre-scale vnf-config-primitive"
6858 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006859 for scaling_config_action in scaling_descriptor[
6860 "scaling-config-action"
6861 ]:
6862 if (
6863 scaling_config_action.get("trigger") == "pre-scale-in"
6864 and scaling_type == "SCALE_IN"
6865 ) or (
6866 scaling_config_action.get("trigger") == "pre-scale-out"
6867 and scaling_type == "SCALE_OUT"
6868 ):
6869 vnf_config_primitive = scaling_config_action[
6870 "vnf-config-primitive-name-ref"
6871 ]
6872 step = db_nslcmop_update[
6873 "detailed-status"
6874 ] = "executing pre-scale scaling-config-action '{}'".format(
6875 vnf_config_primitive
6876 )
tiernoda964822019-01-14 15:53:47 +00006877
tierno59d22d22018-09-25 18:10:19 +02006878 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006879 for config_primitive in (
6880 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6881 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006882 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006883 break
6884 else:
6885 raise LcmException(
6886 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006887 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006888 "primitive".format(scaling_group, vnf_config_primitive)
6889 )
tiernoda964822019-01-14 15:53:47 +00006890
aktas5f75f102021-03-15 11:26:10 +03006891 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006892 if db_vnfr.get("additionalParamsForVnf"):
6893 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006894
tierno9ab95942018-10-10 16:44:22 +02006895 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006896 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006897 primitive_params = self._map_primitive_params(
6898 config_primitive, {}, vnfr_params
6899 )
kuuseac3a8882019-10-03 10:48:06 +02006900
tierno7c4e24c2020-05-13 08:41:35 +00006901 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006902 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006903 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006904 vnf_index,
6905 vnf_config_primitive,
6906 primitive_params,
6907 "PRE-SCALE",
6908 )
tierno7c4e24c2020-05-13 08:41:35 +00006909 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006910 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006911 result = "COMPLETED"
6912 result_detail = "Done"
6913 self.logger.debug(
6914 logging_text
6915 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6916 vnf_config_primitive, result, result_detail
6917 )
6918 )
kuuseac3a8882019-10-03 10:48:06 +02006919 else:
tierno7c4e24c2020-05-13 08:41:35 +00006920 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006921 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006922 op_index = (
6923 len(db_nslcmop.get("_admin", {}).get("operations"))
6924 - 1
6925 )
6926 self.logger.debug(
6927 logging_text
6928 + "vnf_config_primitive={} New sub-operation".format(
6929 vnf_config_primitive
6930 )
6931 )
kuuseac3a8882019-10-03 10:48:06 +02006932 else:
tierno7c4e24c2020-05-13 08:41:35 +00006933 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006934 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6935 op_index
6936 ]
6937 vnf_index = op.get("member_vnf_index")
6938 vnf_config_primitive = op.get("primitive")
6939 primitive_params = op.get("primitive_params")
6940 self.logger.debug(
6941 logging_text
6942 + "vnf_config_primitive={} Sub-operation retry".format(
6943 vnf_config_primitive
6944 )
6945 )
tierno588547c2020-07-01 15:30:20 +00006946 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006947 ee_descriptor_id = config_primitive.get(
6948 "execution-environment-ref"
6949 )
6950 primitive_name = config_primitive.get(
6951 "execution-environment-primitive", vnf_config_primitive
6952 )
6953 ee_id, vca_type = self._look_for_deployed_vca(
6954 nsr_deployed["VCA"],
6955 member_vnf_index=vnf_index,
6956 vdu_id=None,
6957 vdu_count_index=None,
6958 ee_descriptor_id=ee_descriptor_id,
6959 )
kuuseac3a8882019-10-03 10:48:06 +02006960 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006961 ee_id,
6962 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006963 primitive_params,
6964 vca_type=vca_type,
6965 vca_id=vca_id,
6966 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006967 self.logger.debug(
6968 logging_text
6969 + "vnf_config_primitive={} Done with result {} {}".format(
6970 vnf_config_primitive, result, result_detail
6971 )
6972 )
kuuseac3a8882019-10-03 10:48:06 +02006973 # Update operationState = COMPLETED | FAILED
6974 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006975 db_nslcmop, op_index, result, result_detail
6976 )
kuuseac3a8882019-10-03 10:48:06 +02006977
tierno59d22d22018-09-25 18:10:19 +02006978 if result == "FAILED":
6979 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006980 db_nsr_update["config-status"] = old_config_status
6981 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006982 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006983
garciadeblas5697b8b2021-03-24 09:17:02 +01006984 db_nsr_update[
6985 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6986 ] = nb_scale_op
6987 db_nsr_update[
6988 "_admin.scaling-group.{}.time".format(admin_scale_index)
6989 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006990
aktas13251562021-02-12 22:19:10 +03006991 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006992 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006993 step = db_nslcmop_update[
6994 "detailed-status"
6995 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03006996 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006997 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006998 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006999 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007000 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007001 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007002 )
aktas5f75f102021-03-15 11:26:10 +03007003 if vca_info.get("osm_vdu_id"):
7004 vdu_id = vca_info["osm_vdu_id"]
7005 vdu_index = int(vca_info["vdu_index"])
7006 stage[
7007 1
7008 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7009 member_vnf_index, vdu_id, vdu_index
7010 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007011 stage[2] = step = "Scaling in VCA"
7012 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03007013 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
7014 config_update = db_nsr["configurationStatus"]
7015 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01007016 if (
7017 (vca or vca.get("ee_id"))
7018 and vca["member-vnf-index"] == member_vnf_index
7019 and vca["vdu_count_index"] == vdu_index
7020 ):
aktas13251562021-02-12 22:19:10 +03007021 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007022 config_descriptor = get_configuration(
7023 db_vnfd, vca.get("vdu_id")
7024 )
aktas13251562021-02-12 22:19:10 +03007025 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007026 config_descriptor = get_configuration(
7027 db_vnfd, vca.get("kdu_name")
7028 )
aktas13251562021-02-12 22:19:10 +03007029 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01007030 config_descriptor = get_configuration(
7031 db_vnfd, db_vnfd["id"]
7032 )
7033 operation_params = (
7034 db_nslcmop.get("operationParams") or {}
7035 )
7036 exec_terminate_primitives = not operation_params.get(
7037 "skip_terminate_primitives"
7038 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02007039 task = asyncio.ensure_future(
7040 asyncio.wait_for(
7041 self.destroy_N2VC(
7042 logging_text,
7043 db_nslcmop,
7044 vca,
7045 config_descriptor,
7046 vca_index,
7047 destroy_ee=True,
7048 exec_primitives=exec_terminate_primitives,
7049 scaling_in=True,
7050 vca_id=vca_id,
7051 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007052 timeout=self.timeout.charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02007053 )
7054 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007055 tasks_dict_info[task] = "Terminating VCA {}".format(
7056 vca.get("ee_id")
7057 )
aktas13251562021-02-12 22:19:10 +03007058 del vca_update[vca_index]
7059 del config_update[vca_index]
7060 # wait for pending tasks of terminate primitives
7061 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007062 self.logger.debug(
7063 logging_text
7064 + "Waiting for tasks {}".format(
7065 list(tasks_dict_info.keys())
7066 )
7067 )
7068 error_list = await self._wait_for_tasks(
7069 logging_text,
7070 tasks_dict_info,
7071 min(
Luis Vegaa27dc532022-11-11 20:10:49 +00007072 self.timeout.charm_delete, self.timeout.ns_terminate
garciadeblas5697b8b2021-03-24 09:17:02 +01007073 ),
7074 stage,
7075 nslcmop_id,
7076 )
aktas13251562021-02-12 22:19:10 +03007077 tasks_dict_info.clear()
7078 if error_list:
7079 raise LcmException("; ".join(error_list))
7080
7081 db_vca_and_config_update = {
7082 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01007083 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03007084 }
garciadeblas5697b8b2021-03-24 09:17:02 +01007085 self.update_db_2(
7086 "nsrs", db_nsr["_id"], db_vca_and_config_update
7087 )
aktas13251562021-02-12 22:19:10 +03007088 scale_process = None
7089 # SCALE-IN VCA - END
7090
kuuseac3a8882019-10-03 10:48:06 +02007091 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007092 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02007093 scale_process = "RO"
Luis Vegaa27dc532022-11-11 20:10:49 +00007094 if self.ro_config.ng:
garciadeblas5697b8b2021-03-24 09:17:02 +01007095 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03007096 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01007097 )
aktas5f75f102021-03-15 11:26:10 +03007098 scaling_info.pop("vdu-create", None)
7099 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007100
tierno9ab95942018-10-10 16:44:22 +02007101 scale_process = None
aktas13251562021-02-12 22:19:10 +03007102 # SCALE RO - END
7103
aktas5f75f102021-03-15 11:26:10 +03007104 # SCALE KDU - BEGIN
7105 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7106 scale_process = "KDU"
7107 await self._scale_kdu(
7108 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7109 )
7110 scaling_info.pop("kdu-create", None)
7111 scaling_info.pop("kdu-delete", None)
7112
7113 scale_process = None
7114 # SCALE KDU - END
7115
7116 if db_nsr_update:
7117 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7118
aktas13251562021-02-12 22:19:10 +03007119 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007120 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007121 step = db_nslcmop_update[
7122 "detailed-status"
7123 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007124 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007125 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007126 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007127 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007128 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007129 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007130 )
aktas13251562021-02-12 22:19:10 +03007131 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007132 if vca_info.get("osm_vdu_id"):
7133 vdu_index = int(vca_info["vdu_index"])
7134 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7135 if db_vnfr.get("additionalParamsForVnf"):
7136 deploy_params.update(
7137 parse_yaml_strings(
7138 db_vnfr["additionalParamsForVnf"].copy()
7139 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007140 )
aktas5f75f102021-03-15 11:26:10 +03007141 descriptor_config = get_configuration(
7142 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007143 )
aktas5f75f102021-03-15 11:26:10 +03007144 if descriptor_config:
7145 vdu_id = None
7146 vdu_name = None
7147 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007148 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007149 self._deploy_n2vc(
7150 logging_text=logging_text
7151 + "member_vnf_index={} ".format(member_vnf_index),
7152 db_nsr=db_nsr,
7153 db_vnfr=db_vnfr,
7154 nslcmop_id=nslcmop_id,
7155 nsr_id=nsr_id,
7156 nsi_id=nsi_id,
7157 vnfd_id=vnfd_id,
7158 vdu_id=vdu_id,
7159 kdu_name=kdu_name,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007160 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007161 member_vnf_index=member_vnf_index,
7162 vdu_index=vdu_index,
7163 vdu_name=vdu_name,
7164 deploy_params=deploy_params,
7165 descriptor_config=descriptor_config,
7166 base_folder=base_folder,
7167 task_instantiation_info=tasks_dict_info,
7168 stage=stage,
7169 )
7170 vdu_id = vca_info["osm_vdu_id"]
7171 vdur = find_in_list(
7172 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007173 )
aktas5f75f102021-03-15 11:26:10 +03007174 descriptor_config = get_configuration(db_vnfd, vdu_id)
7175 if vdur.get("additionalParams"):
7176 deploy_params_vdu = parse_yaml_strings(
7177 vdur["additionalParams"]
7178 )
7179 else:
7180 deploy_params_vdu = deploy_params
7181 deploy_params_vdu["OSM"] = get_osm_params(
7182 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007183 )
aktas5f75f102021-03-15 11:26:10 +03007184 if descriptor_config:
7185 vdu_name = None
7186 kdu_name = None
Pedro Escaleira120695e2022-06-11 21:17:26 +01007187 kdu_index = None
aktas5f75f102021-03-15 11:26:10 +03007188 stage[
7189 1
7190 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007191 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007192 )
7193 stage[2] = step = "Scaling out VCA"
7194 self._write_op_status(op_id=nslcmop_id, stage=stage)
7195 self._deploy_n2vc(
7196 logging_text=logging_text
7197 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7198 member_vnf_index, vdu_id, vdu_index
7199 ),
7200 db_nsr=db_nsr,
7201 db_vnfr=db_vnfr,
7202 nslcmop_id=nslcmop_id,
7203 nsr_id=nsr_id,
7204 nsi_id=nsi_id,
7205 vnfd_id=vnfd_id,
7206 vdu_id=vdu_id,
7207 kdu_name=kdu_name,
7208 member_vnf_index=member_vnf_index,
7209 vdu_index=vdu_index,
Pedro Escaleira120695e2022-06-11 21:17:26 +01007210 kdu_index=kdu_index,
aktas5f75f102021-03-15 11:26:10 +03007211 vdu_name=vdu_name,
7212 deploy_params=deploy_params_vdu,
7213 descriptor_config=descriptor_config,
7214 base_folder=base_folder,
7215 task_instantiation_info=tasks_dict_info,
7216 stage=stage,
7217 )
aktas13251562021-02-12 22:19:10 +03007218 # SCALE-UP VCA - END
7219 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007220
kuuseac3a8882019-10-03 10:48:06 +02007221 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007222 # execute primitive service POST-SCALING
7223 step = "Executing post-scale vnf-config-primitive"
7224 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007225 for scaling_config_action in scaling_descriptor[
7226 "scaling-config-action"
7227 ]:
7228 if (
7229 scaling_config_action.get("trigger") == "post-scale-in"
7230 and scaling_type == "SCALE_IN"
7231 ) or (
7232 scaling_config_action.get("trigger") == "post-scale-out"
7233 and scaling_type == "SCALE_OUT"
7234 ):
7235 vnf_config_primitive = scaling_config_action[
7236 "vnf-config-primitive-name-ref"
7237 ]
7238 step = db_nslcmop_update[
7239 "detailed-status"
7240 ] = "executing post-scale scaling-config-action '{}'".format(
7241 vnf_config_primitive
7242 )
tiernoda964822019-01-14 15:53:47 +00007243
aktas5f75f102021-03-15 11:26:10 +03007244 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007245 if db_vnfr.get("additionalParamsForVnf"):
7246 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7247
tierno59d22d22018-09-25 18:10:19 +02007248 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007249 for config_primitive in (
7250 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7251 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007252 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007253 break
7254 else:
tiernoa278b842020-07-08 15:33:55 +00007255 raise LcmException(
7256 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7257 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007258 "config-primitive".format(
7259 scaling_group, vnf_config_primitive
7260 )
7261 )
tierno9ab95942018-10-10 16:44:22 +02007262 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007263 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007264 primitive_params = self._map_primitive_params(
7265 config_primitive, {}, vnfr_params
7266 )
tiernod6de1992018-10-11 13:05:52 +02007267
tierno7c4e24c2020-05-13 08:41:35 +00007268 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007269 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007270 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007271 vnf_index,
7272 vnf_config_primitive,
7273 primitive_params,
7274 "POST-SCALE",
7275 )
quilesj4cda56b2019-12-05 10:02:20 +00007276 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007277 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007278 result = "COMPLETED"
7279 result_detail = "Done"
7280 self.logger.debug(
7281 logging_text
7282 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7283 vnf_config_primitive, result, result_detail
7284 )
7285 )
kuuseac3a8882019-10-03 10:48:06 +02007286 else:
quilesj4cda56b2019-12-05 10:02:20 +00007287 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007288 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007289 op_index = (
7290 len(db_nslcmop.get("_admin", {}).get("operations"))
7291 - 1
7292 )
7293 self.logger.debug(
7294 logging_text
7295 + "vnf_config_primitive={} New sub-operation".format(
7296 vnf_config_primitive
7297 )
7298 )
kuuseac3a8882019-10-03 10:48:06 +02007299 else:
tierno7c4e24c2020-05-13 08:41:35 +00007300 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007301 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7302 op_index
7303 ]
7304 vnf_index = op.get("member_vnf_index")
7305 vnf_config_primitive = op.get("primitive")
7306 primitive_params = op.get("primitive_params")
7307 self.logger.debug(
7308 logging_text
7309 + "vnf_config_primitive={} Sub-operation retry".format(
7310 vnf_config_primitive
7311 )
7312 )
tierno588547c2020-07-01 15:30:20 +00007313 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007314 ee_descriptor_id = config_primitive.get(
7315 "execution-environment-ref"
7316 )
7317 primitive_name = config_primitive.get(
7318 "execution-environment-primitive", vnf_config_primitive
7319 )
7320 ee_id, vca_type = self._look_for_deployed_vca(
7321 nsr_deployed["VCA"],
7322 member_vnf_index=vnf_index,
7323 vdu_id=None,
7324 vdu_count_index=None,
7325 ee_descriptor_id=ee_descriptor_id,
7326 )
kuuseac3a8882019-10-03 10:48:06 +02007327 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007328 ee_id,
7329 primitive_name,
7330 primitive_params,
7331 vca_type=vca_type,
7332 vca_id=vca_id,
7333 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007334 self.logger.debug(
7335 logging_text
7336 + "vnf_config_primitive={} Done with result {} {}".format(
7337 vnf_config_primitive, result, result_detail
7338 )
7339 )
kuuseac3a8882019-10-03 10:48:06 +02007340 # Update operationState = COMPLETED | FAILED
7341 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007342 db_nslcmop, op_index, result, result_detail
7343 )
kuuseac3a8882019-10-03 10:48:06 +02007344
tierno59d22d22018-09-25 18:10:19 +02007345 if result == "FAILED":
7346 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007347 db_nsr_update["config-status"] = old_config_status
7348 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007349 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007350
garciadeblas5697b8b2021-03-24 09:17:02 +01007351 db_nsr_update[
7352 "detailed-status"
7353 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7354 db_nsr_update["operational-status"] = (
7355 "running"
7356 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007357 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007358 )
tiernod6de1992018-10-11 13:05:52 +02007359 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007360 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007361 except (
7362 ROclient.ROClientException,
7363 DbException,
7364 LcmException,
7365 NgRoException,
7366 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007367 self.logger.error(logging_text + "Exit Exception {}".format(e))
7368 exc = e
7369 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007370 self.logger.error(
7371 logging_text + "Cancelled Exception while '{}'".format(step)
7372 )
tierno59d22d22018-09-25 18:10:19 +02007373 exc = "Operation was cancelled"
7374 except Exception as e:
7375 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007376 self.logger.critical(
7377 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7378 exc_info=True,
7379 )
tierno59d22d22018-09-25 18:10:19 +02007380 finally:
garciadeblas5697b8b2021-03-24 09:17:02 +01007381 self._write_ns_status(
7382 nsr_id=nsr_id,
7383 ns_state=None,
7384 current_operation="IDLE",
7385 current_operation_id=None,
7386 )
aktas13251562021-02-12 22:19:10 +03007387 if tasks_dict_info:
7388 stage[1] = "Waiting for instantiate pending tasks."
7389 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01007390 exc = await self._wait_for_tasks(
7391 logging_text,
7392 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00007393 self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007394 stage,
7395 nslcmop_id,
7396 nsr_id=nsr_id,
7397 )
tierno59d22d22018-09-25 18:10:19 +02007398 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01007399 db_nslcmop_update[
7400 "detailed-status"
7401 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tiernoa17d4f42020-04-28 09:59:23 +00007402 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007403 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007404 db_nsr_update["operational-status"] = old_operational_status
7405 db_nsr_update["config-status"] = old_config_status
7406 db_nsr_update["detailed-status"] = ""
7407 if scale_process:
7408 if "VCA" in scale_process:
7409 db_nsr_update["config-status"] = "failed"
7410 if "RO" in scale_process:
7411 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007412 db_nsr_update[
7413 "detailed-status"
7414 ] = "FAILED scaling nslcmop={} {}: {}".format(
7415 nslcmop_id, step, exc
7416 )
tiernoa17d4f42020-04-28 09:59:23 +00007417 else:
7418 error_description_nslcmop = None
7419 nslcmop_operation_state = "COMPLETED"
7420 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00007421
garciadeblas5697b8b2021-03-24 09:17:02 +01007422 self._write_op_status(
7423 op_id=nslcmop_id,
7424 stage="",
7425 error_message=error_description_nslcmop,
7426 operation_state=nslcmop_operation_state,
7427 other_update=db_nslcmop_update,
7428 )
tiernoa17d4f42020-04-28 09:59:23 +00007429 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007430 self._write_ns_status(
7431 nsr_id=nsr_id,
7432 ns_state=None,
7433 current_operation="IDLE",
7434 current_operation_id=None,
7435 other_update=db_nsr_update,
7436 )
tiernoa17d4f42020-04-28 09:59:23 +00007437
tierno59d22d22018-09-25 18:10:19 +02007438 if nslcmop_operation_state:
7439 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007440 msg = {
7441 "nsr_id": nsr_id,
7442 "nslcmop_id": nslcmop_id,
7443 "operationState": nslcmop_operation_state,
7444 }
Dario Faccin1df4ede2023-06-01 10:15:34 +02007445 await self.msg.aiowrite("ns", "scaled", msg)
tierno59d22d22018-09-25 18:10:19 +02007446 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007447 self.logger.error(
7448 logging_text + "kafka_write notification Exception {}".format(e)
7449 )
tierno59d22d22018-09-25 18:10:19 +02007450 self.logger.debug(logging_text + "Exit")
7451 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007452
aktas5f75f102021-03-15 11:26:10 +03007453 async def _scale_kdu(
7454 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7455 ):
7456 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7457 for kdu_name in _scaling_info:
7458 for kdu_scaling_info in _scaling_info[kdu_name]:
7459 deployed_kdu, index = get_deployed_kdu(
7460 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7461 )
7462 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7463 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007464 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007465 scale = int(kdu_scaling_info["scale"])
7466 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7467
7468 db_dict = {
7469 "collection": "nsrs",
7470 "filter": {"_id": nsr_id},
7471 "path": "_admin.deployed.K8s.{}".format(index),
7472 }
7473
7474 step = "scaling application {}".format(
7475 kdu_scaling_info["resource-name"]
7476 )
7477 self.logger.debug(logging_text + step)
7478
7479 if kdu_scaling_info["type"] == "delete":
7480 kdu_config = get_configuration(db_vnfd, kdu_name)
7481 if (
7482 kdu_config
7483 and kdu_config.get("terminate-config-primitive")
7484 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7485 ):
7486 terminate_config_primitive_list = kdu_config.get(
7487 "terminate-config-primitive"
7488 )
7489 terminate_config_primitive_list.sort(
7490 key=lambda val: int(val["seq"])
7491 )
7492
7493 for (
7494 terminate_config_primitive
7495 ) in terminate_config_primitive_list:
7496 primitive_params_ = self._map_primitive_params(
7497 terminate_config_primitive, {}, {}
7498 )
7499 step = "execute terminate config primitive"
7500 self.logger.debug(logging_text + step)
7501 await asyncio.wait_for(
7502 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7503 cluster_uuid=cluster_uuid,
7504 kdu_instance=kdu_instance,
7505 primitive_name=terminate_config_primitive["name"],
7506 params=primitive_params_,
7507 db_dict=db_dict,
Luis Vegaa27dc532022-11-11 20:10:49 +00007508 total_timeout=self.timeout.primitive,
aktas5f75f102021-03-15 11:26:10 +03007509 vca_id=vca_id,
7510 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007511 timeout=self.timeout.primitive
7512 * self.timeout.primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007513 )
7514
7515 await asyncio.wait_for(
7516 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007517 kdu_instance=kdu_instance,
7518 scale=scale,
7519 resource_name=kdu_scaling_info["resource-name"],
Luis Vegaa27dc532022-11-11 20:10:49 +00007520 total_timeout=self.timeout.scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007521 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007522 cluster_uuid=cluster_uuid,
7523 kdu_model=kdu_model,
7524 atomic=True,
7525 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007526 ),
Luis Vegaa27dc532022-11-11 20:10:49 +00007527 timeout=self.timeout.scale_on_error
7528 * self.timeout.scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007529 )
7530
7531 if kdu_scaling_info["type"] == "create":
7532 kdu_config = get_configuration(db_vnfd, kdu_name)
7533 if (
7534 kdu_config
7535 and kdu_config.get("initial-config-primitive")
7536 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7537 ):
7538 initial_config_primitive_list = kdu_config.get(
7539 "initial-config-primitive"
7540 )
7541 initial_config_primitive_list.sort(
7542 key=lambda val: int(val["seq"])
7543 )
7544
7545 for initial_config_primitive in initial_config_primitive_list:
7546 primitive_params_ = self._map_primitive_params(
7547 initial_config_primitive, {}, {}
7548 )
7549 step = "execute initial config primitive"
7550 self.logger.debug(logging_text + step)
7551 await asyncio.wait_for(
7552 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7553 cluster_uuid=cluster_uuid,
7554 kdu_instance=kdu_instance,
7555 primitive_name=initial_config_primitive["name"],
7556 params=primitive_params_,
7557 db_dict=db_dict,
7558 vca_id=vca_id,
7559 ),
7560 timeout=600,
7561 )
7562
garciadeblas5697b8b2021-03-24 09:17:02 +01007563 async def _scale_ng_ro(
7564 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7565 ):
tierno2357f4e2020-10-19 16:38:59 +00007566 nsr_id = db_nslcmop["nsInstanceId"]
7567 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7568 db_vnfrs = {}
7569
7570 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007571 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007572
7573 # for each vnf in ns, read vnfd
7574 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7575 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7576 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007577 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007578 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007579 # read from db
7580 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007581 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007582 n2vc_key = self.n2vc.get_public_key()
7583 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007584 self.scale_vnfr(
7585 db_vnfr,
7586 vdu_scaling_info.get("vdu-create"),
7587 vdu_scaling_info.get("vdu-delete"),
7588 mark_delete=True,
7589 )
tierno2357f4e2020-10-19 16:38:59 +00007590 # db_vnfr has been updated, update db_vnfrs to use it
7591 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007592 await self._instantiate_ng_ro(
7593 logging_text,
7594 nsr_id,
7595 db_nsd,
7596 db_nsr,
7597 db_nslcmop,
7598 db_vnfrs,
7599 db_vnfds,
7600 n2vc_key_list,
7601 stage=stage,
7602 start_deploy=time(),
Luis Vegaa27dc532022-11-11 20:10:49 +00007603 timeout_ns_deploy=self.timeout.ns_deploy,
garciadeblas5697b8b2021-03-24 09:17:02 +01007604 )
tierno2357f4e2020-10-19 16:38:59 +00007605 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007606 self.scale_vnfr(
7607 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7608 )
tierno2357f4e2020-10-19 16:38:59 +00007609
bravof73bac502021-05-11 07:38:47 -04007610 async def extract_prometheus_scrape_jobs(
Pedro Escaleira120695e2022-06-11 21:17:26 +01007611 self,
7612 ee_id: str,
7613 artifact_path: str,
7614 ee_config_descriptor: dict,
7615 vnfr_id: str,
7616 nsr_id: str,
7617 target_ip: str,
7618 element_type: str,
7619 vnf_member_index: str = "",
7620 vdu_id: str = "",
7621 vdu_index: int = None,
7622 kdu_name: str = "",
7623 kdu_index: int = None,
7624 ) -> dict:
7625 """Method to extract prometheus scrape jobs from EE's Prometheus template job file
7626 This method will wait until the corresponding VDU or KDU is fully instantiated
7627
7628 Args:
7629 ee_id (str): Execution Environment ID
7630 artifact_path (str): Path where the EE's content is (including the Prometheus template file)
7631 ee_config_descriptor (dict): Execution Environment's configuration descriptor
7632 vnfr_id (str): VNFR ID where this EE applies
7633 nsr_id (str): NSR ID where this EE applies
7634 target_ip (str): VDU/KDU instance IP address
7635 element_type (str): NS or VNF or VDU or KDU
7636 vnf_member_index (str, optional): VNF index where this EE applies. Defaults to "".
7637 vdu_id (str, optional): VDU ID where this EE applies. Defaults to "".
7638 vdu_index (int, optional): VDU index where this EE applies. Defaults to None.
7639 kdu_name (str, optional): KDU name where this EE applies. Defaults to "".
7640 kdu_index (int, optional): KDU index where this EE applies. Defaults to None.
7641
7642 Raises:
7643 LcmException: When the VDU or KDU instance was not found in an hour
7644
7645 Returns:
7646 _type_: Prometheus jobs
7647 """
7648 # default the vdur and kdur names to an empty string, to avoid any later
7649 # problem with Prometheus when the element type is not VDU or KDU
7650 vdur_name = ""
7651 kdur_name = ""
7652
tiernob996d942020-07-03 14:52:28 +00007653 # look if exist a file called 'prometheus*.j2' and
7654 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007655 job_file = next(
7656 (
7657 f
7658 for f in artifact_content
7659 if f.startswith("prometheus") and f.endswith(".j2")
7660 ),
7661 None,
7662 )
tiernob996d942020-07-03 14:52:28 +00007663 if not job_file:
7664 return
Dario Faccin1df4ede2023-06-01 10:15:34 +02007665 self.logger.debug("Artifact path{}".format(artifact_path))
7666 self.logger.debug("job file{}".format(job_file))
tiernob996d942020-07-03 14:52:28 +00007667 with self.fs.file_open((artifact_path, job_file), "r") as f:
7668 job_data = f.read()
7669
Pedro Escaleira120695e2022-06-11 21:17:26 +01007670 # obtain the VDUR or KDUR, if the element type is VDU or KDU
7671 if element_type in ("VDU", "KDU"):
7672 for _ in range(360):
7673 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
7674 if vdu_id and vdu_index is not None:
7675 vdur = next(
7676 (
7677 x
7678 for x in get_iterable(db_vnfr, "vdur")
7679 if (
7680 x.get("vdu-id-ref") == vdu_id
7681 and x.get("count-index") == vdu_index
7682 )
7683 ),
7684 {},
7685 )
7686 if vdur.get("name"):
7687 vdur_name = vdur.get("name")
7688 break
7689 if kdu_name and kdu_index is not None:
7690 kdur = next(
7691 (
7692 x
7693 for x in get_iterable(db_vnfr, "kdur")
7694 if (
7695 x.get("kdu-name") == kdu_name
7696 and x.get("count-index") == kdu_index
7697 )
7698 ),
7699 {},
7700 )
7701 if kdur.get("name"):
7702 kdur_name = kdur.get("name")
7703 break
7704
Dario Faccin1df4ede2023-06-01 10:15:34 +02007705 await asyncio.sleep(10)
Pedro Escaleira120695e2022-06-11 21:17:26 +01007706 else:
7707 if vdu_id and vdu_index is not None:
7708 raise LcmException(
7709 f"Timeout waiting VDU with name={vdu_id} and index={vdu_index} to be intantiated"
7710 )
7711 if kdu_name and kdu_index is not None:
7712 raise LcmException(
7713 f"Timeout waiting KDU with name={kdu_name} and index={kdu_index} to be intantiated"
7714 )
7715
tiernob996d942020-07-03 14:52:28 +00007716 # TODO get_service
Dario Faccin1df4ede2023-06-01 10:15:34 +02007717 if ee_id is not None:
7718 _, _, service = ee_id.partition(".") # remove prefix "namespace."
7719 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
7720 host_port = "80"
7721 vnfr_id = vnfr_id.replace("-", "")
7722 variables = {
7723 "JOB_NAME": vnfr_id,
7724 "TARGET_IP": target_ip,
7725 "EXPORTER_POD_IP": host_name,
7726 "EXPORTER_POD_PORT": host_port,
7727 "NSR_ID": nsr_id,
7728 "VNF_MEMBER_INDEX": vnf_member_index,
7729 "VDUR_NAME": vdur_name,
7730 "KDUR_NAME": kdur_name,
7731 "ELEMENT_TYPE": element_type,
7732 }
7733 else:
7734 metric_path = ee_config_descriptor["metric-path"]
7735 target_port = ee_config_descriptor["metric-port"]
7736 vnfr_id = vnfr_id.replace("-", "")
7737 variables = {
7738 "JOB_NAME": vnfr_id,
7739 "TARGET_IP": target_ip,
7740 "TARGET_PORT": target_port,
7741 "METRIC_PATH": metric_path,
7742 }
7743
bravof73bac502021-05-11 07:38:47 -04007744 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007745 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7746 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007747 if (
7748 not isinstance(job.get("job_name"), str)
7749 or vnfr_id not in job["job_name"]
7750 ):
Dario Faccin1df4ede2023-06-01 10:15:34 +02007751 job["job_name"] = vnfr_id + "_" + str(SystemRandom().randint(1, 10000))
tiernob996d942020-07-03 14:52:28 +00007752 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007753 job["vnfr_id"] = vnfr_id
7754 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007755
preethika.p28b0bf82022-09-23 07:36:28 +00007756 async def rebuild_start_stop(
7757 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7758 ):
k4.rahulb827de92022-05-02 16:35:02 +00007759 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7760 self.logger.info(logging_text + "Enter")
7761 stage = ["Preparing the environment", ""]
7762 # database nsrs record
7763 db_nsr_update = {}
7764 vdu_vim_name = None
7765 vim_vm_id = None
7766 # in case of error, indicates what part of scale was failed to put nsr at error status
7767 start_deploy = time()
7768 try:
7769 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7770 vim_account_id = db_vnfr.get("vim-account-id")
7771 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007772 vdu_id = additional_param["vdu_id"]
7773 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007774 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007775 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007776 )
k4.rahulb827de92022-05-02 16:35:02 +00007777 if vdur:
7778 vdu_vim_name = vdur["name"]
7779 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7780 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007781 else:
7782 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007783 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7784 # wait for any previous tasks in process
7785 stage[1] = "Waiting for previous operations to terminate"
7786 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007787 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007788
7789 stage[1] = "Reading from database."
7790 self.logger.info(stage[1])
7791 self._write_ns_status(
7792 nsr_id=nsr_id,
7793 ns_state=None,
7794 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007795 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007796 )
7797 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7798
7799 # read from db: ns
7800 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7801 db_nsr_update["operational-status"] = operation_type
7802 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7803 # Payload for RO
7804 desc = {
7805 operation_type: {
7806 "vim_vm_id": vim_vm_id,
7807 "vnf_id": vnf_id,
7808 "vdu_index": additional_param["count-index"],
7809 "vdu_id": vdur["id"],
7810 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007811 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007812 }
7813 }
7814 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7815 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7816 self.logger.info("ro nsr id: {}".format(nsr_id))
7817 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7818 self.logger.info("response from RO: {}".format(result_dict))
7819 action_id = result_dict["action_id"]
7820 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007821 nsr_id,
7822 action_id,
7823 nslcmop_id,
7824 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007825 self.timeout.operate,
preethika.p28b0bf82022-09-23 07:36:28 +00007826 None,
7827 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007828 )
7829 return "COMPLETED", "Done"
7830 except (ROclient.ROClientException, DbException, LcmException) as e:
7831 self.logger.error("Exit Exception {}".format(e))
7832 exc = e
7833 except asyncio.CancelledError:
7834 self.logger.error("Cancelled Exception while '{}'".format(stage))
7835 exc = "Operation was cancelled"
7836 except Exception as e:
7837 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007838 self.logger.critical(
7839 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7840 )
k4.rahulb827de92022-05-02 16:35:02 +00007841 return "FAILED", "Error in operate VNF {}".format(exc)
7842
David Garciaaae391f2020-11-09 11:12:54 +01007843 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7844 """
7845 Get VCA Cloud and VCA Cloud Credentials for the VIM account
7846
7847 :param: vim_account_id: VIM Account ID
7848
7849 :return: (cloud_name, cloud_credential)
7850 """
bravof922c4172020-11-24 21:21:43 -03007851 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007852 return config.get("vca_cloud"), config.get("vca_cloud_credential")
7853
7854 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7855 """
7856 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
7857
7858 :param: vim_account_id: VIM Account ID
7859
7860 :return: (cloud_name, cloud_credential)
7861 """
bravof922c4172020-11-24 21:21:43 -03007862 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007863 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")
elumalai80bcf1c2022-04-28 18:05:01 +05307864
7865 async def migrate(self, nsr_id, nslcmop_id):
7866 """
7867 Migrate VNFs and VDUs instances in a NS
7868
7869 :param: nsr_id: NS Instance ID
7870 :param: nslcmop_id: nslcmop ID of migrate
7871
7872 """
7873 # Try to lock HA task here
7874 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7875 if not task_is_locked_by_me:
7876 return
7877 logging_text = "Task ns={} migrate ".format(nsr_id)
7878 self.logger.debug(logging_text + "Enter")
7879 # get all needed from database
7880 db_nslcmop = None
7881 db_nslcmop_update = {}
7882 nslcmop_operation_state = None
7883 db_nsr_update = {}
7884 target = {}
7885 exc = None
7886 # in case of error, indicates what part of scale was failed to put nsr at error status
7887 start_deploy = time()
7888
7889 try:
7890 # wait for any previous tasks in process
7891 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007892 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307893
7894 self._write_ns_status(
7895 nsr_id=nsr_id,
7896 ns_state=None,
7897 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007898 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307899 )
7900 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007901 self.logger.debug(
7902 step + " after having waited for previous tasks to be completed"
7903 )
elumalai80bcf1c2022-04-28 18:05:01 +05307904 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7905 migrate_params = db_nslcmop.get("operationParams")
7906
7907 target = {}
7908 target.update(migrate_params)
7909 desc = await self.RO.migrate(nsr_id, target)
7910 self.logger.debug("RO return > {}".format(desc))
7911 action_id = desc["action_id"]
7912 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007913 nsr_id,
7914 action_id,
7915 nslcmop_id,
7916 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00007917 self.timeout.migrate,
preethika.p28b0bf82022-09-23 07:36:28 +00007918 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307919 )
7920 except (ROclient.ROClientException, DbException, LcmException) as e:
7921 self.logger.error("Exit Exception {}".format(e))
7922 exc = e
7923 except asyncio.CancelledError:
7924 self.logger.error("Cancelled Exception while '{}'".format(step))
7925 exc = "Operation was cancelled"
7926 except Exception as e:
7927 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007928 self.logger.critical(
7929 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7930 )
elumalai80bcf1c2022-04-28 18:05:01 +05307931 finally:
7932 self._write_ns_status(
7933 nsr_id=nsr_id,
7934 ns_state=None,
7935 current_operation="IDLE",
7936 current_operation_id=None,
7937 )
7938 if exc:
aticig349aa462022-05-19 12:29:35 +03007939 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05307940 nslcmop_operation_state = "FAILED"
7941 else:
7942 nslcmop_operation_state = "COMPLETED"
7943 db_nslcmop_update["detailed-status"] = "Done"
7944 db_nsr_update["detailed-status"] = "Done"
7945
7946 self._write_op_status(
7947 op_id=nslcmop_id,
7948 stage="",
7949 error_message="",
7950 operation_state=nslcmop_operation_state,
7951 other_update=db_nslcmop_update,
7952 )
7953 if nslcmop_operation_state:
7954 try:
7955 msg = {
7956 "nsr_id": nsr_id,
7957 "nslcmop_id": nslcmop_id,
7958 "operationState": nslcmop_operation_state,
7959 }
Dario Faccin1df4ede2023-06-01 10:15:34 +02007960 await self.msg.aiowrite("ns", "migrated", msg)
elumalai80bcf1c2022-04-28 18:05:01 +05307961 except Exception as e:
7962 self.logger.error(
7963 logging_text + "kafka_write notification Exception {}".format(e)
7964 )
7965 self.logger.debug(logging_text + "Exit")
7966 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007967
garciadeblas07f4e4c2022-06-09 09:42:58 +02007968 async def heal(self, nsr_id, nslcmop_id):
7969 """
7970 Heal NS
7971
7972 :param nsr_id: ns instance to heal
7973 :param nslcmop_id: operation to run
7974 :return:
7975 """
7976
7977 # Try to lock HA task here
7978 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7979 if not task_is_locked_by_me:
7980 return
7981
7982 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
7983 stage = ["", "", ""]
7984 tasks_dict_info = {}
7985 # ^ stage, step, VIM progress
7986 self.logger.debug(logging_text + "Enter")
7987 # get all needed from database
7988 db_nsr = None
7989 db_nslcmop_update = {}
7990 db_nsr_update = {}
7991 db_vnfrs = {} # vnf's info indexed by _id
7992 exc = None
7993 old_operational_status = ""
7994 old_config_status = ""
7995 nsi_id = None
7996 try:
7997 # wait for any previous tasks in process
7998 step = "Waiting for previous operations to terminate"
7999 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
8000 self._write_ns_status(
8001 nsr_id=nsr_id,
8002 ns_state=None,
8003 current_operation="HEALING",
8004 current_operation_id=nslcmop_id,
8005 )
8006
8007 step = "Getting nslcmop from database"
8008 self.logger.debug(
8009 step + " after having waited for previous tasks to be completed"
8010 )
8011 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8012
8013 step = "Getting nsr from database"
8014 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
8015 old_operational_status = db_nsr["operational-status"]
8016 old_config_status = db_nsr["config-status"]
8017
8018 db_nsr_update = {
8019 "_admin.deployed.RO.operational-status": "healing",
8020 }
8021 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8022
8023 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05008024 await self.heal_RO(
8025 logging_text=logging_text,
8026 nsr_id=nsr_id,
8027 db_nslcmop=db_nslcmop,
8028 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008029 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008030 # VCA tasks
8031 # read from db: nsd
8032 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
8033 self.logger.debug(logging_text + stage[1])
8034 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
8035 self.fs.sync(db_nsr["nsd-id"])
8036 db_nsr["nsd"] = nsd
8037 # read from db: vnfr's of this ns
8038 step = "Getting vnfrs from db"
8039 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
8040 for vnfr in db_vnfrs_list:
8041 db_vnfrs[vnfr["_id"]] = vnfr
8042 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
8043
8044 # Check for each target VNF
8045 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
8046 for target_vnf in target_list:
8047 # Find this VNF in the list from DB
8048 vnfr_id = target_vnf.get("vnfInstanceId", None)
8049 if vnfr_id:
8050 db_vnfr = db_vnfrs[vnfr_id]
8051 vnfd_id = db_vnfr.get("vnfd-id")
8052 vnfd_ref = db_vnfr.get("vnfd-ref")
8053 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
8054 base_folder = vnfd["_admin"]["storage"]
8055 vdu_id = None
8056 vdu_index = 0
8057 vdu_name = None
8058 kdu_name = None
8059 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
8060 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
8061
8062 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00008063 target_vdu_list = target_vnf.get("additionalParams", {}).get(
8064 "vdu", []
8065 )
garciadeblas50639832022-09-01 13:09:47 +02008066 if not target_vdu_list:
8067 # Codigo nuevo para crear diccionario
8068 target_vdu_list = []
8069 for existing_vdu in db_vnfr.get("vdur"):
8070 vdu_name = existing_vdu.get("vdu-name", None)
8071 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00008072 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
8073 "run-day1", False
8074 )
8075 vdu_to_be_healed = {
8076 "vdu-id": vdu_name,
8077 "count-index": vdu_index,
8078 "run-day1": vdu_run_day1,
8079 }
garciadeblas50639832022-09-01 13:09:47 +02008080 target_vdu_list.append(vdu_to_be_healed)
8081 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008082 deploy_params_vdu = target_vdu
8083 # Set run-day1 vnf level value if not vdu level value exists
Dario Faccin1df4ede2023-06-01 10:15:34 +02008084 if not deploy_params_vdu.get("run-day1") and target_vnf.get(
8085 "additionalParams", {}
8086 ).get("run-day1"):
preethika.p28b0bf82022-09-23 07:36:28 +00008087 deploy_params_vdu["run-day1"] = target_vnf[
8088 "additionalParams"
8089 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02008090 vdu_name = target_vdu.get("vdu-id", None)
8091 # TODO: Get vdu_id from vdud.
8092 vdu_id = vdu_name
8093 # For multi instance VDU count-index is mandatory
8094 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00008095 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008096
8097 # n2vc_redesign STEP 3 to 6 Deploy N2VC
8098 stage[1] = "Deploying Execution Environments."
8099 self.logger.debug(logging_text + stage[1])
8100
8101 # VNF Level charm. Normal case when proxy charms.
8102 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
8103 descriptor_config = get_configuration(vnfd, vnfd_ref)
8104 if descriptor_config:
8105 # Continue if healed machine is management machine
8106 vnf_ip_address = db_vnfr.get("ip-address")
8107 target_instance = None
8108 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00008109 if (
8110 instance["vdu-name"] == vdu_name
8111 and instance["count-index"] == vdu_index
8112 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02008113 target_instance = instance
8114 break
8115 if vnf_ip_address == target_instance.get("ip-address"):
8116 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00008117 logging_text=logging_text
8118 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8119 member_vnf_index, vdu_name, vdu_index
8120 ),
8121 db_nsr=db_nsr,
8122 db_vnfr=db_vnfr,
8123 nslcmop_id=nslcmop_id,
8124 nsr_id=nsr_id,
8125 nsi_id=nsi_id,
8126 vnfd_id=vnfd_ref,
8127 vdu_id=None,
8128 kdu_name=None,
8129 member_vnf_index=member_vnf_index,
8130 vdu_index=0,
8131 vdu_name=None,
8132 deploy_params=deploy_params_vdu,
8133 descriptor_config=descriptor_config,
8134 base_folder=base_folder,
8135 task_instantiation_info=tasks_dict_info,
8136 stage=stage,
8137 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008138
8139 # VDU Level charm. Normal case with native charms.
8140 descriptor_config = get_configuration(vnfd, vdu_name)
8141 if descriptor_config:
8142 self._heal_n2vc(
8143 logging_text=logging_text
8144 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
8145 member_vnf_index, vdu_name, vdu_index
8146 ),
8147 db_nsr=db_nsr,
8148 db_vnfr=db_vnfr,
8149 nslcmop_id=nslcmop_id,
8150 nsr_id=nsr_id,
8151 nsi_id=nsi_id,
8152 vnfd_id=vnfd_ref,
8153 vdu_id=vdu_id,
8154 kdu_name=kdu_name,
8155 member_vnf_index=member_vnf_index,
8156 vdu_index=vdu_index,
8157 vdu_name=vdu_name,
8158 deploy_params=deploy_params_vdu,
8159 descriptor_config=descriptor_config,
8160 base_folder=base_folder,
8161 task_instantiation_info=tasks_dict_info,
8162 stage=stage,
8163 )
8164
8165 except (
8166 ROclient.ROClientException,
8167 DbException,
8168 LcmException,
8169 NgRoException,
8170 ) as e:
8171 self.logger.error(logging_text + "Exit Exception {}".format(e))
8172 exc = e
8173 except asyncio.CancelledError:
8174 self.logger.error(
8175 logging_text + "Cancelled Exception while '{}'".format(step)
8176 )
8177 exc = "Operation was cancelled"
8178 except Exception as e:
8179 exc = traceback.format_exc()
8180 self.logger.critical(
8181 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
8182 exc_info=True,
8183 )
8184 finally:
8185 if tasks_dict_info:
8186 stage[1] = "Waiting for healing pending tasks."
8187 self.logger.debug(logging_text + stage[1])
8188 exc = await self._wait_for_tasks(
8189 logging_text,
8190 tasks_dict_info,
Luis Vegaa27dc532022-11-11 20:10:49 +00008191 self.timeout.ns_deploy,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008192 stage,
8193 nslcmop_id,
8194 nsr_id=nsr_id,
8195 )
8196 if exc:
8197 db_nslcmop_update[
8198 "detailed-status"
8199 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
8200 nslcmop_operation_state = "FAILED"
8201 if db_nsr:
8202 db_nsr_update["operational-status"] = old_operational_status
8203 db_nsr_update["config-status"] = old_config_status
8204 db_nsr_update[
8205 "detailed-status"
preethika.p28b0bf82022-09-23 07:36:28 +00008206 ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008207 for task, task_name in tasks_dict_info.items():
8208 if not task.done() or task.cancelled() or task.exception():
8209 if task_name.startswith(self.task_name_deploy_vca):
8210 # A N2VC task is pending
8211 db_nsr_update["config-status"] = "failed"
8212 else:
8213 # RO task is pending
8214 db_nsr_update["operational-status"] = "failed"
8215 else:
8216 error_description_nslcmop = None
8217 nslcmop_operation_state = "COMPLETED"
8218 db_nslcmop_update["detailed-status"] = "Done"
8219 db_nsr_update["detailed-status"] = "Done"
8220 db_nsr_update["operational-status"] = "running"
8221 db_nsr_update["config-status"] = "configured"
8222
8223 self._write_op_status(
8224 op_id=nslcmop_id,
8225 stage="",
8226 error_message=error_description_nslcmop,
8227 operation_state=nslcmop_operation_state,
8228 other_update=db_nslcmop_update,
8229 )
8230 if db_nsr:
8231 self._write_ns_status(
8232 nsr_id=nsr_id,
8233 ns_state=None,
8234 current_operation="IDLE",
8235 current_operation_id=None,
8236 other_update=db_nsr_update,
8237 )
8238
8239 if nslcmop_operation_state:
8240 try:
8241 msg = {
8242 "nsr_id": nsr_id,
8243 "nslcmop_id": nslcmop_id,
8244 "operationState": nslcmop_operation_state,
8245 }
Dario Faccin1df4ede2023-06-01 10:15:34 +02008246 await self.msg.aiowrite("ns", "healed", msg)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008247 except Exception as e:
8248 self.logger.error(
8249 logging_text + "kafka_write notification Exception {}".format(e)
8250 )
8251 self.logger.debug(logging_text + "Exit")
8252 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8253
8254 async def heal_RO(
8255 self,
8256 logging_text,
8257 nsr_id,
8258 db_nslcmop,
8259 stage,
8260 ):
8261 """
8262 Heal at RO
8263 :param logging_text: preffix text to use at logging
8264 :param nsr_id: nsr identity
8265 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8266 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8267 :return: None or exception
8268 """
preethika.p28b0bf82022-09-23 07:36:28 +00008269
garciadeblas07f4e4c2022-06-09 09:42:58 +02008270 def get_vim_account(vim_account_id):
8271 nonlocal db_vims
8272 if vim_account_id in db_vims:
8273 return db_vims[vim_account_id]
8274 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8275 db_vims[vim_account_id] = db_vim
8276 return db_vim
8277
8278 try:
8279 start_heal = time()
8280 ns_params = db_nslcmop.get("operationParams")
8281 if ns_params and ns_params.get("timeout_ns_heal"):
8282 timeout_ns_heal = ns_params["timeout_ns_heal"]
8283 else:
Luis Vegaa27dc532022-11-11 20:10:49 +00008284 timeout_ns_heal = self.timeout.ns_heal
garciadeblas07f4e4c2022-06-09 09:42:58 +02008285
8286 db_vims = {}
8287
8288 nslcmop_id = db_nslcmop["_id"]
8289 target = {
8290 "action_id": nslcmop_id,
8291 }
preethika.p28b0bf82022-09-23 07:36:28 +00008292 self.logger.warning(
8293 "db_nslcmop={} and timeout_ns_heal={}".format(
8294 db_nslcmop, timeout_ns_heal
8295 )
8296 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008297 target.update(db_nslcmop.get("operationParams", {}))
8298
8299 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8300 desc = await self.RO.recreate(nsr_id, target)
8301 self.logger.debug("RO return > {}".format(desc))
8302 action_id = desc["action_id"]
8303 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8304 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008305 nsr_id,
8306 action_id,
8307 nslcmop_id,
8308 start_heal,
8309 timeout_ns_heal,
8310 stage,
8311 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008312 )
8313
8314 # Updating NSR
8315 db_nsr_update = {
8316 "_admin.deployed.RO.operational-status": "running",
8317 "detailed-status": " ".join(stage),
8318 }
8319 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8320 self._write_op_status(nslcmop_id, stage)
8321 self.logger.debug(
8322 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8323 )
8324
8325 except Exception as e:
8326 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008327 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008328 self.logger.error(
8329 "Error healing at VIM {}".format(e),
8330 exc_info=not isinstance(
8331 e,
8332 (
8333 ROclient.ROClientException,
8334 LcmException,
8335 DbException,
8336 NgRoException,
8337 ),
8338 ),
8339 )
8340 raise
8341
8342 def _heal_n2vc(
8343 self,
8344 logging_text,
8345 db_nsr,
8346 db_vnfr,
8347 nslcmop_id,
8348 nsr_id,
8349 nsi_id,
8350 vnfd_id,
8351 vdu_id,
8352 kdu_name,
8353 member_vnf_index,
8354 vdu_index,
8355 vdu_name,
8356 deploy_params,
8357 descriptor_config,
8358 base_folder,
8359 task_instantiation_info,
8360 stage,
8361 ):
8362 # launch instantiate_N2VC in a asyncio task and register task object
8363 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8364 # if not found, create one entry and update database
8365 # fill db_nsr._admin.deployed.VCA.<index>
8366
8367 self.logger.debug(
8368 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8369 )
aticig9bc63ac2022-07-27 09:32:06 +03008370
8371 charm_name = ""
8372 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008373 if "execution-environment-list" in descriptor_config:
8374 ee_list = descriptor_config.get("execution-environment-list", [])
8375 elif "juju" in descriptor_config:
8376 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008377 if "execution-environment-list" not in descriptor_config:
8378 # charm name is only required for ns charms
8379 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008380 else: # other types as script are not supported
8381 ee_list = []
8382
8383 for ee_item in ee_list:
8384 self.logger.debug(
8385 logging_text
8386 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8387 ee_item.get("juju"), ee_item.get("helm-chart")
8388 )
8389 )
8390 ee_descriptor_id = ee_item.get("id")
8391 if ee_item.get("juju"):
8392 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03008393 if get_charm_name:
8394 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008395 vca_type = (
8396 "lxc_proxy_charm"
8397 if ee_item["juju"].get("charm") is not None
8398 else "native_charm"
8399 )
8400 if ee_item["juju"].get("cloud") == "k8s":
8401 vca_type = "k8s_proxy_charm"
8402 elif ee_item["juju"].get("proxy") is False:
8403 vca_type = "native_charm"
8404 elif ee_item.get("helm-chart"):
8405 vca_name = ee_item["helm-chart"]
8406 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
8407 vca_type = "helm"
8408 else:
8409 vca_type = "helm-v3"
8410 else:
8411 self.logger.debug(
8412 logging_text + "skipping non juju neither charm configuration"
8413 )
8414 continue
8415
8416 vca_index = -1
8417 for vca_index, vca_deployed in enumerate(
8418 db_nsr["_admin"]["deployed"]["VCA"]
8419 ):
8420 if not vca_deployed:
8421 continue
8422 if (
8423 vca_deployed.get("member-vnf-index") == member_vnf_index
8424 and vca_deployed.get("vdu_id") == vdu_id
8425 and vca_deployed.get("kdu_name") == kdu_name
8426 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8427 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8428 ):
8429 break
8430 else:
8431 # not found, create one.
8432 target = (
8433 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8434 )
8435 if vdu_id:
8436 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8437 elif kdu_name:
8438 target += "/kdu/{}".format(kdu_name)
8439 vca_deployed = {
8440 "target_element": target,
8441 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8442 "member-vnf-index": member_vnf_index,
8443 "vdu_id": vdu_id,
8444 "kdu_name": kdu_name,
8445 "vdu_count_index": vdu_index,
8446 "operational-status": "init", # TODO revise
8447 "detailed-status": "", # TODO revise
8448 "step": "initial-deploy", # TODO revise
8449 "vnfd_id": vnfd_id,
8450 "vdu_name": vdu_name,
8451 "type": vca_type,
8452 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008453 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008454 }
8455 vca_index += 1
8456
8457 # create VCA and configurationStatus in db
8458 db_dict = {
8459 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8460 "configurationStatus.{}".format(vca_index): dict(),
8461 }
8462 self.update_db_2("nsrs", nsr_id, db_dict)
8463
8464 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8465
8466 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8467 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8468 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8469
8470 # Launch task
8471 task_n2vc = asyncio.ensure_future(
8472 self.heal_N2VC(
8473 logging_text=logging_text,
8474 vca_index=vca_index,
8475 nsi_id=nsi_id,
8476 db_nsr=db_nsr,
8477 db_vnfr=db_vnfr,
8478 vdu_id=vdu_id,
8479 kdu_name=kdu_name,
8480 vdu_index=vdu_index,
8481 deploy_params=deploy_params,
8482 config_descriptor=descriptor_config,
8483 base_folder=base_folder,
8484 nslcmop_id=nslcmop_id,
8485 stage=stage,
8486 vca_type=vca_type,
8487 vca_name=vca_name,
8488 ee_config_descriptor=ee_item,
8489 )
8490 )
8491 self.lcm_tasks.register(
8492 "ns",
8493 nsr_id,
8494 nslcmop_id,
8495 "instantiate_N2VC-{}".format(vca_index),
8496 task_n2vc,
8497 )
8498 task_instantiation_info[
8499 task_n2vc
8500 ] = self.task_name_deploy_vca + " {}.{}".format(
8501 member_vnf_index or "", vdu_id or ""
8502 )
8503
8504 async def heal_N2VC(
8505 self,
8506 logging_text,
8507 vca_index,
8508 nsi_id,
8509 db_nsr,
8510 db_vnfr,
8511 vdu_id,
8512 kdu_name,
8513 vdu_index,
8514 config_descriptor,
8515 deploy_params,
8516 base_folder,
8517 nslcmop_id,
8518 stage,
8519 vca_type,
8520 vca_name,
8521 ee_config_descriptor,
8522 ):
8523 nsr_id = db_nsr["_id"]
8524 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8525 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8526 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8527 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8528 db_dict = {
8529 "collection": "nsrs",
8530 "filter": {"_id": nsr_id},
8531 "path": db_update_entry,
8532 }
8533 step = ""
8534 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008535 element_type = "NS"
8536 element_under_configuration = nsr_id
8537
8538 vnfr_id = None
8539 if db_vnfr:
8540 vnfr_id = db_vnfr["_id"]
8541 osm_config["osm"]["vnf_id"] = vnfr_id
8542
8543 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8544
8545 if vca_type == "native_charm":
8546 index_number = 0
8547 else:
8548 index_number = vdu_index or 0
8549
8550 if vnfr_id:
8551 element_type = "VNF"
8552 element_under_configuration = vnfr_id
8553 namespace += ".{}-{}".format(vnfr_id, index_number)
8554 if vdu_id:
8555 namespace += ".{}-{}".format(vdu_id, index_number)
8556 element_type = "VDU"
8557 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8558 osm_config["osm"]["vdu_id"] = vdu_id
8559 elif kdu_name:
8560 namespace += ".{}".format(kdu_name)
8561 element_type = "KDU"
8562 element_under_configuration = kdu_name
8563 osm_config["osm"]["kdu_name"] = kdu_name
8564
8565 # Get artifact path
8566 if base_folder["pkg-dir"]:
8567 artifact_path = "{}/{}/{}/{}".format(
8568 base_folder["folder"],
8569 base_folder["pkg-dir"],
8570 "charms"
8571 if vca_type
8572 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8573 else "helm-charts",
8574 vca_name,
8575 )
8576 else:
8577 artifact_path = "{}/Scripts/{}/{}/".format(
8578 base_folder["folder"],
8579 "charms"
8580 if vca_type
8581 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8582 else "helm-charts",
8583 vca_name,
8584 )
8585
8586 self.logger.debug("Artifact path > {}".format(artifact_path))
8587
8588 # get initial_config_primitive_list that applies to this element
8589 initial_config_primitive_list = config_descriptor.get(
8590 "initial-config-primitive"
8591 )
8592
8593 self.logger.debug(
8594 "Initial config primitive list > {}".format(
8595 initial_config_primitive_list
8596 )
8597 )
8598
8599 # add config if not present for NS charm
8600 ee_descriptor_id = ee_config_descriptor.get("id")
8601 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8602 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8603 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8604 )
8605
8606 self.logger.debug(
8607 "Initial config primitive list #2 > {}".format(
8608 initial_config_primitive_list
8609 )
8610 )
8611 # n2vc_redesign STEP 3.1
8612 # find old ee_id if exists
8613 ee_id = vca_deployed.get("ee_id")
8614
8615 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8616 # create or register execution environment in VCA. Only for native charms when healing
8617 if vca_type == "native_charm":
8618 step = "Waiting to VM being up and getting IP address"
8619 self.logger.debug(logging_text + step)
8620 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8621 logging_text,
8622 nsr_id,
8623 vnfr_id,
8624 vdu_id,
8625 vdu_index,
8626 user=None,
8627 pub_key=None,
8628 )
8629 credentials = {"hostname": rw_mgmt_ip}
8630 # get username
8631 username = deep_get(
8632 config_descriptor, ("config-access", "ssh-access", "default-user")
8633 )
8634 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8635 # merged. Meanwhile let's get username from initial-config-primitive
8636 if not username and initial_config_primitive_list:
8637 for config_primitive in initial_config_primitive_list:
8638 for param in config_primitive.get("parameter", ()):
8639 if param["name"] == "ssh-username":
8640 username = param["value"]
8641 break
8642 if not username:
8643 raise LcmException(
8644 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8645 "'config-access.ssh-access.default-user'"
8646 )
8647 credentials["username"] = username
8648
8649 # n2vc_redesign STEP 3.2
8650 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8651 self._write_configuration_status(
8652 nsr_id=nsr_id,
8653 vca_index=vca_index,
8654 status="REGISTERING",
8655 element_under_configuration=element_under_configuration,
8656 element_type=element_type,
8657 )
8658
8659 step = "register execution environment {}".format(credentials)
8660 self.logger.debug(logging_text + step)
8661 ee_id = await self.vca_map[vca_type].register_execution_environment(
8662 credentials=credentials,
8663 namespace=namespace,
8664 db_dict=db_dict,
8665 vca_id=vca_id,
8666 )
8667
8668 # update ee_id en db
8669 db_dict_ee_id = {
8670 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8671 }
8672 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8673
8674 # for compatibility with MON/POL modules, the need model and application name at database
8675 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8676 # Not sure if this need to be done when healing
8677 """
8678 ee_id_parts = ee_id.split(".")
8679 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8680 if len(ee_id_parts) >= 2:
8681 model_name = ee_id_parts[0]
8682 application_name = ee_id_parts[1]
8683 db_nsr_update[db_update_entry + "model"] = model_name
8684 db_nsr_update[db_update_entry + "application"] = application_name
8685 """
8686
8687 # n2vc_redesign STEP 3.3
8688 # Install configuration software. Only for native charms.
8689 step = "Install configuration Software"
8690
8691 self._write_configuration_status(
8692 nsr_id=nsr_id,
8693 vca_index=vca_index,
8694 status="INSTALLING SW",
8695 element_under_configuration=element_under_configuration,
8696 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008697 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008698 other_update=None,
8699 )
8700
8701 # TODO check if already done
8702 self.logger.debug(logging_text + step)
8703 config = None
8704 if vca_type == "native_charm":
8705 config_primitive = next(
8706 (p for p in initial_config_primitive_list if p["name"] == "config"),
8707 None,
8708 )
8709 if config_primitive:
8710 config = self._map_primitive_params(
8711 config_primitive, {}, deploy_params
8712 )
8713 await self.vca_map[vca_type].install_configuration_sw(
8714 ee_id=ee_id,
8715 artifact_path=artifact_path,
8716 db_dict=db_dict,
8717 config=config,
8718 num_units=1,
8719 vca_id=vca_id,
8720 vca_type=vca_type,
8721 )
8722
8723 # write in db flag of configuration_sw already installed
8724 self.update_db_2(
8725 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8726 )
8727
8728 # Not sure if this need to be done when healing
8729 """
8730 # add relations for this VCA (wait for other peers related with this VCA)
8731 await self._add_vca_relations(
8732 logging_text=logging_text,
8733 nsr_id=nsr_id,
8734 vca_type=vca_type,
8735 vca_index=vca_index,
8736 )
8737 """
8738
8739 # if SSH access is required, then get execution environment SSH public
8740 # if native charm we have waited already to VM be UP
8741 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
8742 pub_key = None
8743 user = None
8744 # self.logger.debug("get ssh key block")
8745 if deep_get(
8746 config_descriptor, ("config-access", "ssh-access", "required")
8747 ):
8748 # self.logger.debug("ssh key needed")
8749 # Needed to inject a ssh key
8750 user = deep_get(
8751 config_descriptor,
8752 ("config-access", "ssh-access", "default-user"),
8753 )
8754 step = "Install configuration Software, getting public ssh key"
8755 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8756 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8757 )
8758
8759 step = "Insert public key into VM user={} ssh_key={}".format(
8760 user, pub_key
8761 )
8762 else:
8763 # self.logger.debug("no need to get ssh key")
8764 step = "Waiting to VM being up and getting IP address"
8765 self.logger.debug(logging_text + step)
8766
8767 # n2vc_redesign STEP 5.1
8768 # wait for RO (ip-address) Insert pub_key into VM
8769 # IMPORTANT: We need do wait for RO to complete healing operation.
Luis Vegaa27dc532022-11-11 20:10:49 +00008770 await self._wait_heal_ro(nsr_id, self.timeout.ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008771 if vnfr_id:
8772 if kdu_name:
8773 rw_mgmt_ip = await self.wait_kdu_up(
8774 logging_text, nsr_id, vnfr_id, kdu_name
8775 )
8776 else:
8777 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8778 logging_text,
8779 nsr_id,
8780 vnfr_id,
8781 vdu_id,
8782 vdu_index,
8783 user=user,
8784 pub_key=pub_key,
8785 )
8786 else:
8787 rw_mgmt_ip = None # This is for a NS configuration
8788
8789 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8790
8791 # store rw_mgmt_ip in deploy params for later replacement
8792 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8793
8794 # Day1 operations.
8795 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008796 runDay1 = deploy_params.get("run-day1", False)
8797 self.logger.debug(
8798 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8799 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008800 if runDay1:
8801 # n2vc_redesign STEP 6 Execute initial config primitive
8802 step = "execute initial config primitive"
8803
8804 # wait for dependent primitives execution (NS -> VNF -> VDU)
8805 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008806 await self._wait_dependent_n2vc(
8807 nsr_id, vca_deployed_list, vca_index
8808 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008809
8810 # stage, in function of element type: vdu, kdu, vnf or ns
8811 my_vca = vca_deployed_list[vca_index]
8812 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8813 # VDU or KDU
8814 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8815 elif my_vca.get("member-vnf-index"):
8816 # VNF
8817 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8818 else:
8819 # NS
8820 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8821
8822 self._write_configuration_status(
8823 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8824 )
8825
8826 self._write_op_status(op_id=nslcmop_id, stage=stage)
8827
8828 check_if_terminated_needed = True
8829 for initial_config_primitive in initial_config_primitive_list:
8830 # adding information on the vca_deployed if it is a NS execution environment
8831 if not vca_deployed["member-vnf-index"]:
8832 deploy_params["ns_config_info"] = json.dumps(
8833 self._get_ns_config_info(nsr_id)
8834 )
8835 # TODO check if already done
8836 primitive_params_ = self._map_primitive_params(
8837 initial_config_primitive, {}, deploy_params
8838 )
8839
8840 step = "execute primitive '{}' params '{}'".format(
8841 initial_config_primitive["name"], primitive_params_
8842 )
8843 self.logger.debug(logging_text + step)
8844 await self.vca_map[vca_type].exec_primitive(
8845 ee_id=ee_id,
8846 primitive_name=initial_config_primitive["name"],
8847 params_dict=primitive_params_,
8848 db_dict=db_dict,
8849 vca_id=vca_id,
8850 vca_type=vca_type,
8851 )
8852 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8853 if check_if_terminated_needed:
8854 if config_descriptor.get("terminate-config-primitive"):
8855 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008856 "nsrs",
8857 nsr_id,
8858 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008859 )
8860 check_if_terminated_needed = False
8861
8862 # TODO register in database that primitive is done
8863
8864 # STEP 7 Configure metrics
8865 # Not sure if this need to be done when healing
8866 """
8867 if vca_type == "helm" or vca_type == "helm-v3":
8868 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8869 ee_id=ee_id,
8870 artifact_path=artifact_path,
8871 ee_config_descriptor=ee_config_descriptor,
8872 vnfr_id=vnfr_id,
8873 nsr_id=nsr_id,
8874 target_ip=rw_mgmt_ip,
8875 )
8876 if prometheus_jobs:
8877 self.update_db_2(
8878 "nsrs",
8879 nsr_id,
8880 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8881 )
8882
8883 for job in prometheus_jobs:
8884 self.db.set_one(
8885 "prometheus_jobs",
8886 {"job_name": job["job_name"]},
8887 job,
8888 upsert=True,
8889 fail_on_empty=False,
8890 )
8891
8892 """
8893 step = "instantiated at VCA"
8894 self.logger.debug(logging_text + step)
8895
8896 self._write_configuration_status(
8897 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8898 )
8899
8900 except Exception as e: # TODO not use Exception but N2VC exception
8901 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8902 if not isinstance(
8903 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8904 ):
8905 self.logger.error(
8906 "Exception while {} : {}".format(step, e), exc_info=True
8907 )
8908 self._write_configuration_status(
8909 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8910 )
8911 raise LcmException("{} {}".format(step, e)) from e
8912
8913 async def _wait_heal_ro(
8914 self,
8915 nsr_id,
8916 timeout=600,
8917 ):
8918 start_time = time()
8919 while time() <= start_time + timeout:
8920 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00008921 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
8922 "operational-status"
8923 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02008924 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
8925 if operational_status_ro != "healing":
8926 break
Dario Faccin1df4ede2023-06-01 10:15:34 +02008927 await asyncio.sleep(15)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008928 else: # timeout_ns_deploy
8929 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05308930
8931 async def vertical_scale(self, nsr_id, nslcmop_id):
8932 """
8933 Vertical Scale the VDUs in a NS
8934
8935 :param: nsr_id: NS Instance ID
8936 :param: nslcmop_id: nslcmop ID of migrate
8937
8938 """
8939 # Try to lock HA task here
8940 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8941 if not task_is_locked_by_me:
8942 return
8943 logging_text = "Task ns={} vertical scale ".format(nsr_id)
8944 self.logger.debug(logging_text + "Enter")
8945 # get all needed from database
8946 db_nslcmop = None
8947 db_nslcmop_update = {}
8948 nslcmop_operation_state = None
8949 db_nsr_update = {}
8950 target = {}
8951 exc = None
8952 # in case of error, indicates what part of scale was failed to put nsr at error status
8953 start_deploy = time()
8954
8955 try:
8956 # wait for any previous tasks in process
8957 step = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00008958 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05308959
8960 self._write_ns_status(
8961 nsr_id=nsr_id,
8962 ns_state=None,
8963 current_operation="VerticalScale",
preethika.p28b0bf82022-09-23 07:36:28 +00008964 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05308965 )
8966 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00008967 self.logger.debug(
8968 step + " after having waited for previous tasks to be completed"
8969 )
govindarajul4ff4b512022-05-02 20:02:41 +05308970 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8971 operationParams = db_nslcmop.get("operationParams")
8972 target = {}
8973 target.update(operationParams)
8974 desc = await self.RO.vertical_scale(nsr_id, target)
8975 self.logger.debug("RO return > {}".format(desc))
8976 action_id = desc["action_id"]
8977 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008978 nsr_id,
8979 action_id,
8980 nslcmop_id,
8981 start_deploy,
Luis Vegaa27dc532022-11-11 20:10:49 +00008982 self.timeout.verticalscale,
preethika.p28b0bf82022-09-23 07:36:28 +00008983 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05308984 )
8985 except (ROclient.ROClientException, DbException, LcmException) as e:
8986 self.logger.error("Exit Exception {}".format(e))
8987 exc = e
8988 except asyncio.CancelledError:
8989 self.logger.error("Cancelled Exception while '{}'".format(step))
8990 exc = "Operation was cancelled"
8991 except Exception as e:
8992 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00008993 self.logger.critical(
8994 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8995 )
govindarajul4ff4b512022-05-02 20:02:41 +05308996 finally:
8997 self._write_ns_status(
8998 nsr_id=nsr_id,
8999 ns_state=None,
9000 current_operation="IDLE",
9001 current_operation_id=None,
9002 )
9003 if exc:
preethika.p28b0bf82022-09-23 07:36:28 +00009004 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
govindarajul4ff4b512022-05-02 20:02:41 +05309005 nslcmop_operation_state = "FAILED"
9006 else:
9007 nslcmop_operation_state = "COMPLETED"
9008 db_nslcmop_update["detailed-status"] = "Done"
9009 db_nsr_update["detailed-status"] = "Done"
9010
9011 self._write_op_status(
9012 op_id=nslcmop_id,
9013 stage="",
9014 error_message="",
9015 operation_state=nslcmop_operation_state,
9016 other_update=db_nslcmop_update,
9017 )
9018 if nslcmop_operation_state:
9019 try:
9020 msg = {
9021 "nsr_id": nsr_id,
9022 "nslcmop_id": nslcmop_id,
9023 "operationState": nslcmop_operation_state,
9024 }
Dario Faccin1df4ede2023-06-01 10:15:34 +02009025 await self.msg.aiowrite("ns", "verticalscaled", msg)
govindarajul4ff4b512022-05-02 20:02:41 +05309026 except Exception as e:
9027 self.logger.error(
9028 logging_text + "kafka_write notification Exception {}".format(e)
9029 )
9030 self.logger.debug(logging_text + "Exit")
9031 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")