blob: d3ec1df92d40ae6133b39238ff34b26b79826a79 [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,
33)
tierno59d22d22018-09-25 18:10:19 +020034
tierno77677d92019-08-22 13:46:35 +000035from osm_lcm import ROclient
David Garciab4ebcd02021-10-28 02:00:43 +020036from osm_lcm.data_utils.nsr import (
37 get_deployed_kdu,
38 get_deployed_vca,
39 get_deployed_vca_list,
40 get_nsd,
41)
42from osm_lcm.data_utils.vca import (
43 DeployedComponent,
44 DeployedK8sResource,
45 DeployedVCA,
46 EELevel,
47 Relation,
48 EERelation,
49 safe_get_ee_relation,
50)
tierno69f0d382020-05-07 13:08:09 +000051from osm_lcm.ng_ro import NgRoClient, NgRoException
garciadeblas5697b8b2021-03-24 09:17:02 +010052from osm_lcm.lcm_utils import (
53 LcmException,
54 LcmExceptionNoMgmtIP,
55 LcmBase,
56 deep_get,
57 get_iterable,
58 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030059 check_juju_bundle_existence,
60 get_charm_artifact_path,
garciadeblas5697b8b2021-03-24 09:17:02 +010061)
David Garciab4ebcd02021-10-28 02:00:43 +020062from osm_lcm.data_utils.nsd import (
63 get_ns_configuration_relation_list,
64 get_vnf_profile,
65 get_vnf_profiles,
66)
garciadeblas5697b8b2021-03-24 09:17:02 +010067from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020068 get_kdu,
69 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020070 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010071 get_vdu_list,
72 get_vdu_profile,
73 get_ee_sorted_initial_config_primitive_list,
74 get_ee_sorted_terminate_config_primitive_list,
75 get_kdu_list,
76 get_virtual_link_profiles,
77 get_vdu,
78 get_configuration,
79 get_vdu_index,
80 get_scaling_aspect,
81 get_number_of_instances,
82 get_juju_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020083 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030084 find_software_version,
garciadeblas5697b8b2021-03-24 09:17:02 +010085)
bravof922c4172020-11-24 21:21:43 -030086from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030087from osm_lcm.data_utils.vnfr import (
88 get_osm_params,
89 get_vdur_index,
90 get_kdur,
91 get_volumes_from_instantiation_params,
92)
bravof922c4172020-11-24 21:21:43 -030093from osm_lcm.data_utils.dict_utils import parse_yaml_strings
94from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +020095from n2vc.definitions import RelationEndpoint
calvinosanch9f9c6f22019-11-04 13:37:39 +010096from n2vc.k8s_helm_conn import K8sHelmConnector
lloretgalleg18ebc3a2020-10-22 09:54:51 +000097from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -050098from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +020099
tierno27246d82018-09-27 15:59:09 +0200100from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200101from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200102
bravof922c4172020-11-24 21:21:43 -0300103from osm_lcm.data_utils.database.database import Database
104from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenomf7a883b2022-11-11 14:44:57 +0000105from osm_lcm.data_utils.wim import (
106 get_sdn_ports,
107 get_target_wim_attrs,
108 select_feasible_wim_account,
109)
bravof922c4172020-11-24 21:21:43 -0300110
quilesj7e13aeb2019-10-08 13:34:55 +0200111from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000112from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200113
tierno588547c2020-07-01 15:30:20 +0000114from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200115from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400116from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000117
tierno27246d82018-09-27 15:59:09 +0200118from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200119from time import time
tierno27246d82018-09-27 15:59:09 +0200120from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000121
tiernob996d942020-07-03 14:52:28 +0000122from random import randint
tierno59d22d22018-09-25 18:10:19 +0200123
tierno69f0d382020-05-07 13:08:09 +0000124__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200125
126
127class NsLcm(LcmBase):
garciadeblas5697b8b2021-03-24 09:17:02 +0100128 timeout_vca_on_error = (
129 5 * 60
130 ) # Time for charm from first time at blocked,error status to mark as failed
131 timeout_ns_deploy = 2 * 3600 # default global timeout for deployment a ns
132 timeout_ns_terminate = 1800 # default global timeout for un deployment a ns
garciadeblas07f4e4c2022-06-09 09:42:58 +0200133 timeout_ns_heal = 1800 # default global timeout for un deployment a ns
garciadeblasf9b04952019-04-09 18:53:58 +0200134 timeout_charm_delete = 10 * 60
David Garciaf6919842020-05-21 16:41:07 +0200135 timeout_primitive = 30 * 60 # timeout for primitive execution
aticigdffa6212022-04-12 15:27:53 +0300136 timeout_ns_update = 30 * 60 # timeout for ns update
garciadeblas5697b8b2021-03-24 09:17:02 +0100137 timeout_progress_primitive = (
138 10 * 60
139 ) # timeout for some progress in a primitive execution
elumalai80bcf1c2022-04-28 18:05:01 +0530140 timeout_migrate = 1800 # default global timeout for migrating vnfs
k4.rahulb827de92022-05-02 16:35:02 +0000141 timeout_operate = 1800 # default global timeout for migrating vnfs
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +0200142 timeout_verticalscale = 1800 # default global timeout for Vertical Sclaing
kuuseac3a8882019-10-03 10:48:06 +0200143 SUBOPERATION_STATUS_NOT_FOUND = -1
144 SUBOPERATION_STATUS_NEW = -2
145 SUBOPERATION_STATUS_SKIP = -3
tiernoa2143262020-03-27 16:20:40 +0000146 task_name_deploy_vca = "Deploying VCA"
kuuseac3a8882019-10-03 10:48:06 +0200147
bravof73bac502021-05-11 07:38:47 -0400148 def __init__(self, msg, lcm_tasks, config, loop):
tierno59d22d22018-09-25 18:10:19 +0200149 """
150 Init, Connect to database, filesystem storage, and messaging
151 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
152 :return: None
153 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100154 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200155
bravof922c4172020-11-24 21:21:43 -0300156 self.db = Database().instance.db
157 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200158 self.loop = loop
159 self.lcm_tasks = lcm_tasks
tierno744303e2020-01-13 16:46:31 +0000160 self.timeout = config["timeout"]
161 self.ro_config = config["ro_config"]
tierno69f0d382020-05-07 13:08:09 +0000162 self.ng_ro = config["ro_config"].get("ng")
tierno744303e2020-01-13 16:46:31 +0000163 self.vca_config = config["VCA"].copy()
tierno59d22d22018-09-25 18:10:19 +0200164
quilesj7e13aeb2019-10-08 13:34:55 +0200165 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100166 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200167 log=self.logger,
quilesj7e13aeb2019-10-08 13:34:55 +0200168 loop=self.loop,
bravof922c4172020-11-24 21:21:43 -0300169 on_update_db=self._on_update_n2vc_db,
170 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100171 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200172 )
quilesj7e13aeb2019-10-08 13:34:55 +0200173
tierno588547c2020-07-01 15:30:20 +0000174 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000175 log=self.logger,
176 loop=self.loop,
tierno588547c2020-07-01 15:30:20 +0000177 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100178 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000179 )
180
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000181 self.k8sclusterhelm2 = K8sHelmConnector(
calvinosanch9f9c6f22019-11-04 13:37:39 +0100182 kubectl_command=self.vca_config.get("kubectlpath"),
183 helm_command=self.vca_config.get("helmpath"),
calvinosanch9f9c6f22019-11-04 13:37:39 +0100184 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100185 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300186 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100187 db=self.db,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100188 )
189
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000190 self.k8sclusterhelm3 = K8sHelm3Connector(
191 kubectl_command=self.vca_config.get("kubectlpath"),
192 helm_command=self.vca_config.get("helm3path"),
193 fs=self.fs,
194 log=self.logger,
195 db=self.db,
196 on_update_db=None,
197 )
198
Adam Israelbaacc302019-12-01 12:41:39 -0500199 self.k8sclusterjuju = K8sJujuConnector(
200 kubectl_command=self.vca_config.get("kubectlpath"),
201 juju_command=self.vca_config.get("jujupath"),
Adam Israelbaacc302019-12-01 12:41:39 -0500202 log=self.logger,
David Garciaba89cbb2020-10-16 13:05:34 +0200203 loop=self.loop,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530204 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300205 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100206 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500207 )
208
tiernoa2143262020-03-27 16:20:40 +0000209 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000210 "helm-chart": self.k8sclusterhelm2,
211 "helm-chart-v3": self.k8sclusterhelm3,
212 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000213 "juju-bundle": self.k8sclusterjuju,
214 "juju": self.k8sclusterjuju,
215 }
tierno588547c2020-07-01 15:30:20 +0000216
217 self.vca_map = {
218 "lxc_proxy_charm": self.n2vc,
219 "native_charm": self.n2vc,
220 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000221 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100222 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000223 }
224
quilesj7e13aeb2019-10-08 13:34:55 +0200225 # create RO client
bravof922c4172020-11-24 21:21:43 -0300226 self.RO = NgRoClient(self.loop, **self.ro_config)
tierno59d22d22018-09-25 18:10:19 +0200227
garciadeblas07f4e4c2022-06-09 09:42:58 +0200228 self.op_status_map = {
229 "instantiation": self.RO.status,
230 "termination": self.RO.status,
231 "migrate": self.RO.status,
232 "healing": self.RO.recreate_status,
govindarajul0fe7c7d2022-07-06 10:47:00 +0000233 "verticalscale": self.RO.status,
k4.rahul8296c7b2022-07-07 07:23:53 +0000234 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200235 }
236
tierno2357f4e2020-10-19 16:38:59 +0000237 @staticmethod
238 def increment_ip_mac(ip_mac, vm_index=1):
239 if not isinstance(ip_mac, str):
240 return ip_mac
241 try:
242 # try with ipv4 look for last dot
243 i = ip_mac.rfind(".")
244 if i > 0:
245 i += 1
246 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
247 # try with ipv6 or mac look for last colon. Operate in hex
248 i = ip_mac.rfind(":")
249 if i > 0:
250 i += 1
251 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100252 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
253 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
254 )
tierno2357f4e2020-10-19 16:38:59 +0000255 except Exception:
256 pass
257 return None
258
quilesj3655ae02019-12-12 16:08:35 +0000259 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj3655ae02019-12-12 16:08:35 +0000260 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
261
262 try:
263 # TODO filter RO descriptor fields...
264
265 # write to database
266 db_dict = dict()
267 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
garciadeblas5697b8b2021-03-24 09:17:02 +0100268 db_dict["deploymentStatus"] = ro_descriptor
quilesj3655ae02019-12-12 16:08:35 +0000269 self.update_db_2("nsrs", nsrs_id, db_dict)
270
271 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100272 self.logger.warn(
273 "Cannot write database RO deployment for ns={} -> {}".format(nsrs_id, e)
274 )
quilesj3655ae02019-12-12 16:08:35 +0000275
David Garciac1fe90a2021-03-31 19:12:02 +0200276 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj69a722c2020-01-09 08:30:17 +0000277 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100278 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000279 path = path[:-1]
280
quilesj3655ae02019-12-12 16:08:35 +0000281 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
282 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000283 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100284 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000285
286 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100287 nsr = self.db.get_one(table="nsrs", q_filter=filter)
288 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000289
290 # get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100291 status_dict = await self.n2vc.get_status(
292 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
293 )
quilesj3655ae02019-12-12 16:08:35 +0000294
295 # vcaStatus
296 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100297 db_dict["vcaStatus"] = status_dict
298 await self.n2vc.update_vca_status(db_dict["vcaStatus"], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000299
300 # update configurationStatus for this VCA
301 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100302 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000303
garciadeblas5697b8b2021-03-24 09:17:02 +0100304 vca_list = deep_get(
305 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
306 )
307 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000308
garciadeblas5697b8b2021-03-24 09:17:02 +0100309 configuration_status_list = nsr.get("configurationStatus")
310 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000311
garciadeblas5697b8b2021-03-24 09:17:02 +0100312 if config_status == "BROKEN" and vca_status != "failed":
313 db_dict["configurationStatus"][vca_index] = "READY"
314 elif config_status != "BROKEN" and vca_status == "failed":
315 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000316 except Exception as e:
317 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100318 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000319
320 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
321 # if nsState = 'DEGRADED' check if all is OK
322 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100323 if current_ns_status in ("READY", "DEGRADED"):
324 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000325 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100326 if status_dict.get("machines"):
327 for machine_id in status_dict.get("machines"):
328 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000329 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100330 if machine.get("agent-status"):
331 s = machine.get("agent-status").get("status")
332 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000333 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100334 error_description += (
335 "machine {} agent-status={} ; ".format(
336 machine_id, s
337 )
338 )
quilesj3655ae02019-12-12 16:08:35 +0000339 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100340 if machine.get("instance-status"):
341 s = machine.get("instance-status").get("status")
342 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000343 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100344 error_description += (
345 "machine {} instance-status={} ; ".format(
346 machine_id, s
347 )
348 )
quilesj3655ae02019-12-12 16:08:35 +0000349 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100350 if status_dict.get("applications"):
351 for app_id in status_dict.get("applications"):
352 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000353 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100354 if app.get("status"):
355 s = app.get("status").get("status")
356 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000357 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100358 error_description += (
359 "application {} status={} ; ".format(app_id, s)
360 )
quilesj3655ae02019-12-12 16:08:35 +0000361
362 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100363 db_dict["errorDescription"] = error_description
364 if current_ns_status == "READY" and is_degraded:
365 db_dict["nsState"] = "DEGRADED"
366 if current_ns_status == "DEGRADED" and not is_degraded:
367 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000368
369 # write to database
370 self.update_db_2("nsrs", nsr_id, db_dict)
371
tierno51183952020-04-03 15:48:18 +0000372 except (asyncio.CancelledError, asyncio.TimeoutError):
373 raise
quilesj3655ae02019-12-12 16:08:35 +0000374 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100375 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200376
garciadeblas5697b8b2021-03-24 09:17:02 +0100377 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100378 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100379 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530380 """
381 Updating vca status in NSR record
382 :param cluster_uuid: UUID of a k8s cluster
383 :param kdu_instance: The unique name of the KDU instance
384 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100385 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530386 :return: none
387 """
388
389 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
390 # .format(cluster_uuid, kdu_instance, filter))
391
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100392 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530393 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100394 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
395 cluster_uuid=cluster_uuid,
396 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200397 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100398 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200399 vca_id=vca_id,
400 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100401
ksaikiranr656b6dd2021-02-19 10:25:18 +0530402 # vcaStatus
403 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100404 db_dict["vcaStatus"] = {nsr_id: vca_status}
ksaikiranr656b6dd2021-02-19 10:25:18 +0530405
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100406 if cluster_type in ("juju-bundle", "juju"):
407 # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA
408 # status in a similar way between Juju Bundles and Helm Charts on this side
409 await self.k8sclusterjuju.update_vca_status(
410 db_dict["vcaStatus"],
411 kdu_instance,
412 vca_id=vca_id,
413 )
414
415 self.logger.debug(
416 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200417 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530418
419 # write to database
420 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530421 except (asyncio.CancelledError, asyncio.TimeoutError):
422 raise
423 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100424 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530425
tierno72ef84f2020-10-06 08:22:07 +0000426 @staticmethod
427 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
428 try:
Luisfd2e7242022-07-01 14:35:49 +0000429 env = Environment(undefined=StrictUndefined, autoescape=True)
tierno72ef84f2020-10-06 08:22:07 +0000430 template = env.from_string(cloud_init_text)
431 return template.render(additional_params or {})
432 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100433 raise LcmException(
434 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
435 "file, must be provided in the instantiation parameters inside the "
436 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
437 )
tierno72ef84f2020-10-06 08:22:07 +0000438 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100439 raise LcmException(
440 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
441 vnfd_id, vdu_id, e
442 )
443 )
tierno72ef84f2020-10-06 08:22:07 +0000444
bravof922c4172020-11-24 21:21:43 -0300445 def _get_vdu_cloud_init_content(self, vdu, vnfd):
446 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000447 try:
tierno72ef84f2020-10-06 08:22:07 +0000448 if vdu.get("cloud-init-file"):
449 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300450 if base_folder["pkg-dir"]:
451 cloud_init_file = "{}/{}/cloud_init/{}".format(
452 base_folder["folder"],
453 base_folder["pkg-dir"],
454 vdu["cloud-init-file"],
455 )
456 else:
457 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
458 base_folder["folder"],
459 vdu["cloud-init-file"],
460 )
tierno72ef84f2020-10-06 08:22:07 +0000461 with self.fs.file_open(cloud_init_file, "r") as ci_file:
462 cloud_init_content = ci_file.read()
463 elif vdu.get("cloud-init"):
464 cloud_init_content = vdu["cloud-init"]
465
466 return cloud_init_content
467 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100468 raise LcmException(
469 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
470 vnfd["id"], vdu["id"], cloud_init_file, e
471 )
472 )
tierno72ef84f2020-10-06 08:22:07 +0000473
tierno72ef84f2020-10-06 08:22:07 +0000474 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100475 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300476 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100477 )
tierno72ef84f2020-10-06 08:22:07 +0000478 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300479 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000480
gcalvino35be9152018-12-20 09:33:12 +0100481 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200482 """
483 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
484 :param vnfd: input vnfd
485 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000486 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100487 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200488 :return: copy of vnfd
489 """
tierno72ef84f2020-10-06 08:22:07 +0000490 vnfd_RO = deepcopy(vnfd)
491 # remove unused by RO configuration, monitoring, scaling and internal keys
492 vnfd_RO.pop("_id", None)
493 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000494 vnfd_RO.pop("monitoring-param", None)
495 vnfd_RO.pop("scaling-group-descriptor", None)
496 vnfd_RO.pop("kdu", None)
497 vnfd_RO.pop("k8s-cluster", None)
498 if new_id:
499 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000500
tierno72ef84f2020-10-06 08:22:07 +0000501 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
502 for vdu in get_iterable(vnfd_RO, "vdu"):
503 vdu.pop("cloud-init-file", None)
504 vdu.pop("cloud-init", None)
505 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200506
tierno2357f4e2020-10-19 16:38:59 +0000507 @staticmethod
508 def ip_profile_2_RO(ip_profile):
509 RO_ip_profile = deepcopy(ip_profile)
510 if "dns-server" in RO_ip_profile:
511 if isinstance(RO_ip_profile["dns-server"], list):
512 RO_ip_profile["dns-address"] = []
513 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100514 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000515 else:
516 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
517 if RO_ip_profile.get("ip-version") == "ipv4":
518 RO_ip_profile["ip-version"] = "IPv4"
519 if RO_ip_profile.get("ip-version") == "ipv6":
520 RO_ip_profile["ip-version"] = "IPv6"
521 if "dhcp-params" in RO_ip_profile:
522 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
523 return RO_ip_profile
524
bravof922c4172020-11-24 21:21:43 -0300525 def _get_ro_vim_id_for_vim_account(self, vim_account):
526 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
527 if db_vim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100528 raise LcmException(
529 "VIM={} is not available. operationalState={}".format(
530 vim_account, db_vim["_admin"]["operationalState"]
531 )
532 )
bravof922c4172020-11-24 21:21:43 -0300533 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
534 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200535
bravof922c4172020-11-24 21:21:43 -0300536 def get_ro_wim_id_for_wim_account(self, wim_account):
537 if isinstance(wim_account, str):
538 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
539 if db_wim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100540 raise LcmException(
541 "WIM={} is not available. operationalState={}".format(
542 wim_account, db_wim["_admin"]["operationalState"]
543 )
544 )
bravof922c4172020-11-24 21:21:43 -0300545 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
546 return RO_wim_id
547 else:
548 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200549
tierno2357f4e2020-10-19 16:38:59 +0000550 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno2357f4e2020-10-19 16:38:59 +0000551 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000552 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000553 db_update = {"_admin.modified": time()}
554 if vdu_create:
555 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100556 vdur = next(
557 (
558 vdur
559 for vdur in reversed(db_vnfr["vdur"])
560 if vdur["vdu-id-ref"] == vdu_id
561 ),
562 None,
563 )
tierno2357f4e2020-10-19 16:38:59 +0000564 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000565 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300566 self.logger.debug(
567 "No vdur in the database. Using the vdur-template to scale"
568 )
vegall8d625f12022-03-22 16:23:30 +0000569 vdur_template = db_vnfr.get("vdur-template")
570 if not vdur_template:
571 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300572 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
573 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000574 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100575 )
vegall8d625f12022-03-22 16:23:30 +0000576 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300577 # Delete a template from the database after using it
578 self.db.set_one(
579 "vnfrs",
580 {"_id": db_vnfr["_id"]},
581 None,
582 pull={"vdur-template": {"_id": vdur["_id"]}},
583 )
tierno2357f4e2020-10-19 16:38:59 +0000584 for count in range(vdu_count):
585 vdur_copy = deepcopy(vdur)
586 vdur_copy["status"] = "BUILD"
587 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100588 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000589 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000590 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100591 vdur_copy["id"] = "{}-{}".format(
592 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
593 )
tierno2357f4e2020-10-19 16:38:59 +0000594 vdur_copy.pop("vim_info", None)
595 for iface in vdur_copy["interfaces"]:
596 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100597 iface["ip-address"] = self.increment_ip_mac(
598 iface["ip-address"], count + 1
599 )
tierno2357f4e2020-10-19 16:38:59 +0000600 else:
601 iface.pop("ip-address", None)
602 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100603 iface["mac-address"] = self.increment_ip_mac(
604 iface["mac-address"], count + 1
605 )
tierno2357f4e2020-10-19 16:38:59 +0000606 else:
607 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000608 if db_vnfr["vdur"]:
609 iface.pop(
610 "mgmt_vnf", None
611 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000612 db_vdu_push_list.append(vdur_copy)
613 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200614 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000615 if len(db_vnfr["vdur"]) == 1:
616 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300617 self.logger.debug(
618 "Scaling to 0 !, creating the template with the last vdur"
619 )
vegall8d625f12022-03-22 16:23:30 +0000620 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000621 for vdu_id, vdu_count in vdu_delete.items():
622 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100623 indexes_to_delete = [
624 iv[0]
625 for iv in enumerate(db_vnfr["vdur"])
626 if iv[1]["vdu-id-ref"] == vdu_id
627 ]
628 db_update.update(
629 {
630 "vdur.{}.status".format(i): "DELETING"
631 for i in indexes_to_delete[-vdu_count:]
632 }
633 )
tierno2357f4e2020-10-19 16:38:59 +0000634 else:
635 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100636 vdus_to_delete = [
637 v
638 for v in reversed(db_vnfr["vdur"])
639 if v["vdu-id-ref"] == vdu_id
640 ]
tierno2357f4e2020-10-19 16:38:59 +0000641 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100642 self.db.set_one(
643 "vnfrs",
644 {"_id": db_vnfr["_id"]},
645 None,
646 pull={"vdur": {"_id": vdu["_id"]}},
647 )
vegall8d625f12022-03-22 16:23:30 +0000648 db_push = {}
649 if db_vdu_push_list:
650 db_push["vdur"] = db_vdu_push_list
651 if template_vdur:
652 db_push["vdur-template"] = template_vdur
653 if not db_push:
654 db_push = None
655 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000656 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
657 # modify passed dictionary db_vnfr
658 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
659 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200660
tiernof578e552018-11-08 19:07:20 +0100661 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
662 """
663 Updates database nsr with the RO info for the created vld
664 :param ns_update_nsr: dictionary to be filled with the updated info
665 :param db_nsr: content of db_nsr. This is also modified
666 :param nsr_desc_RO: nsr descriptor from RO
667 :return: Nothing, LcmException is raised on errors
668 """
669
670 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
671 for net_RO in get_iterable(nsr_desc_RO, "nets"):
672 if vld["id"] != net_RO.get("ns_net_osm_id"):
673 continue
674 vld["vim-id"] = net_RO.get("vim_net_id")
675 vld["name"] = net_RO.get("vim_name")
676 vld["status"] = net_RO.get("status")
677 vld["status-detailed"] = net_RO.get("error_msg")
678 ns_update_nsr["vld.{}".format(vld_index)] = vld
679 break
680 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100681 raise LcmException(
682 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
683 )
tiernof578e552018-11-08 19:07:20 +0100684
tiernoe876f672020-02-13 14:34:48 +0000685 def set_vnfr_at_error(self, db_vnfrs, error_text):
686 try:
687 for db_vnfr in db_vnfrs.values():
688 vnfr_update = {"status": "ERROR"}
689 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
690 if "status" not in vdur:
691 vdur["status"] = "ERROR"
692 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
693 if error_text:
694 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100695 vnfr_update[
696 "vdur.{}.status-detailed".format(vdu_index)
697 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000698 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
699 except DbException as e:
700 self.logger.error("Cannot update vnf. {}".format(e))
701
tierno59d22d22018-09-25 18:10:19 +0200702 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
703 """
704 Updates database vnfr with the RO info, e.g. ip_address, vim_id... Descriptor db_vnfrs is also updated
tierno27246d82018-09-27 15:59:09 +0200705 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
706 :param nsr_desc_RO: nsr descriptor from RO
707 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200708 """
709 for vnf_index, db_vnfr in db_vnfrs.items():
710 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200711 if vnf_RO["member_vnf_index"] != vnf_index:
712 continue
713 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100714 if vnf_RO.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100715 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO[
716 "ip_address"
717 ].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100718 elif not db_vnfr.get("ip-address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100719 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
720 raise LcmExceptionNoMgmtIP(
721 "ns member_vnf_index '{}' has no IP address".format(
722 vnf_index
723 )
724 )
tierno59d22d22018-09-25 18:10:19 +0200725
tierno27246d82018-09-27 15:59:09 +0200726 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
727 vdur_RO_count_index = 0
728 if vdur.get("pdu-type"):
729 continue
730 for vdur_RO in get_iterable(vnf_RO, "vms"):
731 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
732 continue
733 if vdur["count-index"] != vdur_RO_count_index:
734 vdur_RO_count_index += 1
735 continue
736 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000737 if vdur_RO.get("ip_address"):
738 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000739 else:
740 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200741 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
742 vdur["name"] = vdur_RO.get("vim_name")
743 vdur["status"] = vdur_RO.get("status")
744 vdur["status-detailed"] = vdur_RO.get("error_msg")
745 for ifacer in get_iterable(vdur, "interfaces"):
746 for interface_RO in get_iterable(vdur_RO, "interfaces"):
747 if ifacer["name"] == interface_RO.get("internal_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100748 ifacer["ip-address"] = interface_RO.get(
749 "ip_address"
750 )
751 ifacer["mac-address"] = interface_RO.get(
752 "mac_address"
753 )
tierno27246d82018-09-27 15:59:09 +0200754 break
755 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100756 raise LcmException(
757 "ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
758 "from VIM info".format(
759 vnf_index, vdur["vdu-id-ref"], ifacer["name"]
760 )
761 )
tierno27246d82018-09-27 15:59:09 +0200762 vnfr_update["vdur.{}".format(vdu_index)] = vdur
763 break
764 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100765 raise LcmException(
766 "ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
767 "VIM info".format(
768 vnf_index, vdur["vdu-id-ref"], vdur["count-index"]
769 )
770 )
tiernof578e552018-11-08 19:07:20 +0100771
772 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
773 for net_RO in get_iterable(nsr_desc_RO, "nets"):
774 if vld["id"] != net_RO.get("vnf_net_osm_id"):
775 continue
776 vld["vim-id"] = net_RO.get("vim_net_id")
777 vld["name"] = net_RO.get("vim_name")
778 vld["status"] = net_RO.get("status")
779 vld["status-detailed"] = net_RO.get("error_msg")
780 vnfr_update["vld.{}".format(vld_index)] = vld
781 break
782 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100783 raise LcmException(
784 "ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
785 vnf_index, vld["id"]
786 )
787 )
tiernof578e552018-11-08 19:07:20 +0100788
tierno27246d82018-09-27 15:59:09 +0200789 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
790 break
tierno59d22d22018-09-25 18:10:19 +0200791
792 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100793 raise LcmException(
794 "ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(
795 vnf_index
796 )
797 )
tierno59d22d22018-09-25 18:10:19 +0200798
tierno5ee02052019-12-05 19:55:02 +0000799 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000800 """
801 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000802 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000803 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
804 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
805 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
806 """
tierno5ee02052019-12-05 19:55:02 +0000807 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
808 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000809 mapping = {}
810 ns_config_info = {"osm-config-mapping": mapping}
811 for vca in vca_deployed_list:
812 if not vca["member-vnf-index"]:
813 continue
814 if not vca["vdu_id"]:
815 mapping[vca["member-vnf-index"]] = vca["application"]
816 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100817 mapping[
818 "{}.{}.{}".format(
819 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
820 )
821 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000822 return ns_config_info
823
garciadeblas5697b8b2021-03-24 09:17:02 +0100824 async def _instantiate_ng_ro(
825 self,
826 logging_text,
827 nsr_id,
828 nsd,
829 db_nsr,
830 db_nslcmop,
831 db_vnfrs,
832 db_vnfds,
833 n2vc_key_list,
834 stage,
835 start_deploy,
836 timeout_ns_deploy,
837 ):
tierno2357f4e2020-10-19 16:38:59 +0000838 db_vims = {}
839
840 def get_vim_account(vim_account_id):
841 nonlocal db_vims
842 if vim_account_id in db_vims:
843 return db_vims[vim_account_id]
844 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
845 db_vims[vim_account_id] = db_vim
846 return db_vim
847
848 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100849 def parse_vld_instantiation_params(
850 target_vim, target_vld, vld_params, target_sdn
851 ):
tierno2357f4e2020-10-19 16:38:59 +0000852 if vld_params.get("ip-profile"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100853 target_vld["vim_info"][target_vim]["ip_profile"] = vld_params[
854 "ip-profile"
855 ]
tierno2357f4e2020-10-19 16:38:59 +0000856 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100857 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
858 "provider-network"
859 ]
tierno2357f4e2020-10-19 16:38:59 +0000860 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100861 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
862 "provider-network"
863 ]["sdn-ports"]
gifrerenomf7a883b2022-11-11 14:44:57 +0000864
865 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
866 # if wim_account_id is specified in vld_params, validate if it is feasible.
867 wim_account_id, db_wim = select_feasible_wim_account(
868 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
869 )
870
871 if wim_account_id:
872 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
873 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
874 # update vld_params with correct WIM account Id
875 vld_params["wimAccountId"] = wim_account_id
876
877 target_wim = "wim:{}".format(wim_account_id)
878 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
879 sdn_ports = get_sdn_ports(vld_params, db_wim)
880 if len(sdn_ports) > 0:
881 target_vld["vim_info"][target_wim] = target_wim_attrs
882 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
883
884 self.logger.debug(
885 "Target VLD with WIM data: {:s}".format(str(target_vld))
886 )
887
tierno2357f4e2020-10-19 16:38:59 +0000888 for param in ("vim-network-name", "vim-network-id"):
889 if vld_params.get(param):
890 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300891 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300892 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100893 populate_dict(
894 target_vld["vim_info"],
895 (other_target_vim, param.replace("-", "_")),
896 vim_net,
897 )
tierno2357f4e2020-10-19 16:38:59 +0000898 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100899 target_vld["vim_info"][target_vim][
900 param.replace("-", "_")
901 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300902 if vld_params.get("common_id"):
903 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000904
aticig15db6142022-01-24 12:51:26 +0300905 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
906 def update_ns_vld_target(target, ns_params):
907 for vnf_params in ns_params.get("vnf", ()):
908 if vnf_params.get("vimAccountId"):
909 target_vnf = next(
910 (
911 vnfr
912 for vnfr in db_vnfrs.values()
913 if vnf_params["member-vnf-index"]
914 == vnfr["member-vnf-index-ref"]
915 ),
916 None,
917 )
918 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleira8af05102022-09-12 00:14:41 +0100919 if not vdur:
920 continue
aticig15db6142022-01-24 12:51:26 +0300921 for a_index, a_vld in enumerate(target["ns"]["vld"]):
922 target_vld = find_in_list(
923 get_iterable(vdur, "interfaces"),
924 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
925 )
aticig84bd9a72022-06-14 03:01:36 +0300926
927 vld_params = find_in_list(
928 get_iterable(ns_params, "vld"),
929 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
930 )
aticig15db6142022-01-24 12:51:26 +0300931 if target_vld:
932 if vnf_params.get("vimAccountId") not in a_vld.get(
933 "vim_info", {}
934 ):
aticig84bd9a72022-06-14 03:01:36 +0300935 target_vim_network_list = [
936 v for _, v in a_vld.get("vim_info").items()
937 ]
938 target_vim_network_name = next(
939 (
940 item.get("vim_network_name", "")
941 for item in target_vim_network_list
942 ),
943 "",
944 )
945
aticig15db6142022-01-24 12:51:26 +0300946 target["ns"]["vld"][a_index].get("vim_info").update(
947 {
948 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300949 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300950 }
951 }
952 )
953
aticig84bd9a72022-06-14 03:01:36 +0300954 if vld_params:
955 for param in ("vim-network-name", "vim-network-id"):
956 if vld_params.get(param) and isinstance(
957 vld_params[param], dict
958 ):
959 for vim, vim_net in vld_params[
960 param
961 ].items():
962 other_target_vim = "vim:" + vim
963 populate_dict(
964 target["ns"]["vld"][a_index].get(
965 "vim_info"
966 ),
967 (
968 other_target_vim,
969 param.replace("-", "_"),
970 ),
971 vim_net,
972 )
973
tierno69f0d382020-05-07 13:08:09 +0000974 nslcmop_id = db_nslcmop["_id"]
975 target = {
976 "name": db_nsr["name"],
977 "ns": {"vld": []},
978 "vnf": [],
979 "image": deepcopy(db_nsr["image"]),
980 "flavor": deepcopy(db_nsr["flavor"]),
981 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000982 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000983 }
984 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000985 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000986 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000987 flavor["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100988 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100989 target["affinity-or-anti-affinity-group"] = deepcopy(
990 db_nsr["affinity-or-anti-affinity-group"]
991 )
992 for affinity_or_anti_affinity_group in target[
993 "affinity-or-anti-affinity-group"
994 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100995 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000996
tierno2357f4e2020-10-19 16:38:59 +0000997 if db_nslcmop.get("lcmOperationType") != "instantiate":
998 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100999 db_nslcmop_instantiate = self.db.get_list(
1000 "nslcmops",
1001 {
1002 "nsInstanceId": db_nslcmop["nsInstanceId"],
1003 "lcmOperationType": "instantiate",
1004 },
1005 )[-1]
tierno2357f4e2020-10-19 16:38:59 +00001006 ns_params = db_nslcmop_instantiate.get("operationParams")
1007 else:
1008 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -03001009 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
1010 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +00001011
1012 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +00001013 for vld_index, vld in enumerate(db_nsr.get("vld")):
1014 target_vim = "vim:{}".format(ns_params["vimAccountId"])
1015 target_vld = {
1016 "id": vld["id"],
1017 "name": vld["name"],
1018 "mgmt-network": vld.get("mgmt-network", False),
1019 "type": vld.get("type"),
1020 "vim_info": {
bravof922c4172020-11-24 21:21:43 -03001021 target_vim: {
1022 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +01001023 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -03001024 }
garciadeblas5697b8b2021-03-24 09:17:02 +01001025 },
tierno2357f4e2020-10-19 16:38:59 +00001026 }
1027 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +00001028 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +00001029 db_vim = get_vim_account(ns_params["vimAccountId"])
Gulsum Atici08a25f22023-01-10 14:10:42 +03001030 if vim_config := db_vim.get("config"):
1031 if sdnc_id := vim_config.get("sdn-controller"):
1032 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
1033 target_sdn = "sdn:{}".format(sdnc_id)
1034 target_vld["vim_info"][target_sdn] = {
1035 "sdn": True,
1036 "target_vim": target_vim,
1037 "vlds": [sdn_vld],
1038 "type": vld.get("type"),
1039 }
tierno2357f4e2020-10-19 16:38:59 +00001040
bravof922c4172020-11-24 21:21:43 -03001041 nsd_vnf_profiles = get_vnf_profiles(nsd)
1042 for nsd_vnf_profile in nsd_vnf_profiles:
1043 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
1044 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001045 cp2target[
1046 "member_vnf:{}.{}".format(
1047 cp["constituent-cpd-id"][0][
1048 "constituent-base-element-id"
1049 ],
1050 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
1051 )
1052 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +00001053
1054 # check at nsd descriptor, if there is an ip-profile
1055 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +00001056 nsd_vlp = find_in_list(
1057 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001058 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
1059 == vld["id"],
1060 )
1061 if (
1062 nsd_vlp
1063 and nsd_vlp.get("virtual-link-protocol-data")
1064 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1065 ):
1066 ip_profile_source_data = nsd_vlp["virtual-link-protocol-data"][
1067 "l3-protocol-data"
1068 ]
lloretgalleg19008482021-04-19 11:40:18 +00001069 ip_profile_dest_data = {}
1070 if "ip-version" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001071 ip_profile_dest_data["ip-version"] = ip_profile_source_data[
1072 "ip-version"
1073 ]
lloretgalleg19008482021-04-19 11:40:18 +00001074 if "cidr" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001075 ip_profile_dest_data["subnet-address"] = ip_profile_source_data[
1076 "cidr"
1077 ]
lloretgalleg19008482021-04-19 11:40:18 +00001078 if "gateway-ip" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001079 ip_profile_dest_data["gateway-address"] = ip_profile_source_data[
1080 "gateway-ip"
1081 ]
lloretgalleg19008482021-04-19 11:40:18 +00001082 if "dhcp-enabled" in ip_profile_source_data:
1083 ip_profile_dest_data["dhcp-params"] = {
1084 "enabled": ip_profile_source_data["dhcp-enabled"]
1085 }
1086 vld_params["ip-profile"] = ip_profile_dest_data
bravof922c4172020-11-24 21:21:43 -03001087
tierno2357f4e2020-10-19 16:38:59 +00001088 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +01001089 vld_instantiation_params = find_in_list(
1090 get_iterable(ns_params, "vld"),
1091 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
1092 )
tierno2357f4e2020-10-19 16:38:59 +00001093 if vld_instantiation_params:
1094 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -03001095 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +00001096 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +03001097 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
1098 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -03001099
tierno69f0d382020-05-07 13:08:09 +00001100 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +01001101 vnfd = find_in_list(
1102 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
1103 )
1104 vnf_params = find_in_list(
1105 get_iterable(ns_params, "vnf"),
1106 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
1107 )
tierno69f0d382020-05-07 13:08:09 +00001108 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +00001109 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +00001110 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +00001111 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +01001112 vnf_cp = find_in_list(
1113 vnfd.get("int-virtual-link-desc", ()),
1114 lambda cpd: cpd.get("id") == vld["id"],
1115 )
tierno69f0d382020-05-07 13:08:09 +00001116 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01001117 ns_cp = "member_vnf:{}.{}".format(
1118 vnfr["member-vnf-index-ref"], vnf_cp["id"]
1119 )
tierno69f0d382020-05-07 13:08:09 +00001120 if cp2target.get(ns_cp):
1121 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -03001122
garciadeblas5697b8b2021-03-24 09:17:02 +01001123 vld["vim_info"] = {
1124 target_vim: {"vim_network_name": vld.get("vim-network-name")}
1125 }
tierno2357f4e2020-10-19 16:38:59 +00001126 # check if this network needs SDN assist
1127 target_sdn = None
1128 if vld.get("pci-interfaces"):
1129 db_vim = get_vim_account(vnfr["vim-account-id"])
1130 sdnc_id = db_vim["config"].get("sdn-controller")
1131 if sdnc_id:
1132 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
1133 target_sdn = "sdn:{}".format(sdnc_id)
1134 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001135 "sdn": True,
1136 "target_vim": target_vim,
1137 "vlds": [sdn_vld],
1138 "type": vld.get("type"),
1139 }
tierno69f0d382020-05-07 13:08:09 +00001140
tierno2357f4e2020-10-19 16:38:59 +00001141 # check at vnfd descriptor, if there is an ip-profile
1142 vld_params = {}
bravof922c4172020-11-24 21:21:43 -03001143 vnfd_vlp = find_in_list(
1144 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001145 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -03001146 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001147 if (
1148 vnfd_vlp
1149 and vnfd_vlp.get("virtual-link-protocol-data")
1150 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1151 ):
1152 ip_profile_source_data = vnfd_vlp["virtual-link-protocol-data"][
1153 "l3-protocol-data"
1154 ]
bravof922c4172020-11-24 21:21:43 -03001155 ip_profile_dest_data = {}
1156 if "ip-version" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001157 ip_profile_dest_data["ip-version"] = ip_profile_source_data[
1158 "ip-version"
1159 ]
bravof922c4172020-11-24 21:21:43 -03001160 if "cidr" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001161 ip_profile_dest_data["subnet-address"] = ip_profile_source_data[
1162 "cidr"
1163 ]
bravof922c4172020-11-24 21:21:43 -03001164 if "gateway-ip" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001165 ip_profile_dest_data[
1166 "gateway-address"
1167 ] = ip_profile_source_data["gateway-ip"]
bravof922c4172020-11-24 21:21:43 -03001168 if "dhcp-enabled" in ip_profile_source_data:
1169 ip_profile_dest_data["dhcp-params"] = {
1170 "enabled": ip_profile_source_data["dhcp-enabled"]
1171 }
1172
1173 vld_params["ip-profile"] = ip_profile_dest_data
tierno2357f4e2020-10-19 16:38:59 +00001174 # update vld_params with instantiation params
1175 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01001176 vld_instantiation_params = find_in_list(
1177 get_iterable(vnf_params, "internal-vld"),
1178 lambda i_vld: i_vld["name"] == vld["id"],
1179 )
tierno2357f4e2020-10-19 16:38:59 +00001180 if vld_instantiation_params:
1181 vld_params.update(vld_instantiation_params)
1182 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1183
1184 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001185 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001186 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1187 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001188 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001189
bravof922c4172020-11-24 21:21:43 -03001190 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1191
1192 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001193 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1194 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001195 if (
1196 vdu_configuration
1197 and vdu_configuration.get("config-access")
1198 and vdu_configuration.get("config-access").get("ssh-access")
1199 ):
bravof922c4172020-11-24 21:21:43 -03001200 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001201 vdur["ssh-access-required"] = vdu_configuration[
1202 "config-access"
1203 ]["ssh-access"]["required"]
1204 elif (
1205 vnf_configuration
1206 and vnf_configuration.get("config-access")
1207 and vnf_configuration.get("config-access").get("ssh-access")
1208 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1209 ):
bravof922c4172020-11-24 21:21:43 -03001210 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001211 vdur["ssh-access-required"] = vnf_configuration[
1212 "config-access"
1213 ]["ssh-access"]["required"]
1214 elif ssh_keys_instantiation and find_in_list(
1215 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1216 ):
bravof922c4172020-11-24 21:21:43 -03001217 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001218
bravof922c4172020-11-24 21:21:43 -03001219 self.logger.debug("NS > vdur > {}".format(vdur))
1220
1221 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001222 # cloud-init
1223 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001224 vdur["cloud-init"] = "{}:file:{}".format(
1225 vnfd["_id"], vdud.get("cloud-init-file")
1226 )
tierno2357f4e2020-10-19 16:38:59 +00001227 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1228 if vdur["cloud-init"] not in target["cloud_init_content"]:
1229 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001230 if base_folder["pkg-dir"]:
1231 cloud_init_file = "{}/{}/cloud_init/{}".format(
1232 base_folder["folder"],
1233 base_folder["pkg-dir"],
1234 vdud.get("cloud-init-file"),
1235 )
1236 else:
1237 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1238 base_folder["folder"],
1239 vdud.get("cloud-init-file"),
1240 )
tierno2357f4e2020-10-19 16:38:59 +00001241 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001242 target["cloud_init_content"][
1243 vdur["cloud-init"]
1244 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001245 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001246 vdur["cloud-init"] = "{}:vdu:{}".format(
1247 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1248 )
tierno2357f4e2020-10-19 16:38:59 +00001249 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001250 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1251 "cloud-init"
1252 ]
tierno2357f4e2020-10-19 16:38:59 +00001253 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001254 deploy_params_vdu = self._format_additional_params(
1255 vdur.get("additionalParams") or {}
1256 )
1257 deploy_params_vdu["OSM"] = get_osm_params(
1258 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1259 )
tierno2357f4e2020-10-19 16:38:59 +00001260 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001261
1262 # flavor
1263 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001264 if target_vim not in ns_flavor["vim_info"]:
1265 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001266
1267 # deal with images
1268 # in case alternative images are provided we must check if they should be applied
1269 # for the vim_type, modify the vim_type taking into account
1270 ns_image_id = int(vdur["ns-image-id"])
1271 if vdur.get("alt-image-ids"):
1272 db_vim = get_vim_account(vnfr["vim-account-id"])
1273 vim_type = db_vim["vim_type"]
1274 for alt_image_id in vdur.get("alt-image-ids"):
1275 ns_alt_image = target["image"][int(alt_image_id)]
1276 if vim_type == ns_alt_image.get("vim-type"):
1277 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001278 self.logger.debug(
1279 "use alternative image id: {}".format(alt_image_id)
1280 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001281 ns_image_id = alt_image_id
1282 vdur["ns-image-id"] = ns_image_id
1283 break
1284 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001285 if target_vim not in ns_image["vim_info"]:
1286 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001287
Alexis Romero305b5c42022-03-11 15:29:18 +01001288 # Affinity groups
1289 if vdur.get("affinity-or-anti-affinity-group-id"):
1290 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1291 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1292 if target_vim not in ns_ags["vim_info"]:
1293 ns_ags["vim_info"][target_vim] = {}
1294
tierno2357f4e2020-10-19 16:38:59 +00001295 vdur["vim_info"] = {target_vim: {}}
1296 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001297 if vnf_params:
1298 vdu_instantiation_params = find_in_list(
1299 get_iterable(vnf_params, "vdu"),
1300 lambda i_vdu: i_vdu["id"] == vdud["id"],
1301 )
1302 if vdu_instantiation_params:
1303 # Parse the vdu_volumes from the instantiation params
1304 vdu_volumes = get_volumes_from_instantiation_params(
1305 vdu_instantiation_params, vdud
1306 )
1307 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
tierno2357f4e2020-10-19 16:38:59 +00001308 vdur_list.append(vdur)
1309 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001310 target["vnf"].append(target_vnf)
1311
garciadeblas07f4e4c2022-06-09 09:42:58 +02001312 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001313 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001314 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001315 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001316 await self._wait_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02001317 nsr_id,
1318 action_id,
1319 nslcmop_id,
1320 start_deploy,
1321 timeout_ns_deploy,
1322 stage,
1323 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001324 )
tierno69f0d382020-05-07 13:08:09 +00001325
1326 # Updating NSR
1327 db_nsr_update = {
1328 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001329 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001330 }
1331 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1332 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1333 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001334 self.logger.debug(
1335 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1336 )
tierno69f0d382020-05-07 13:08:09 +00001337 return
1338
garciadeblas5697b8b2021-03-24 09:17:02 +01001339 async def _wait_ng_ro(
1340 self,
1341 nsr_id,
1342 action_id,
1343 nslcmop_id=None,
1344 start_time=None,
1345 timeout=600,
1346 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001347 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001348 ):
tierno69f0d382020-05-07 13:08:09 +00001349 detailed_status_old = None
1350 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001351 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001352 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001353 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001354 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001355 if desc_status["status"] == "FAILED":
1356 raise NgRoException(desc_status["details"])
1357 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001358 if stage:
1359 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001360 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001361 if stage:
1362 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001363 break
1364 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001365 assert False, "ROclient.check_ns_status returns unknown {}".format(
1366 desc_status["status"]
1367 )
tierno2357f4e2020-10-19 16:38:59 +00001368 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001369 detailed_status_old = stage[2]
1370 db_nsr_update["detailed-status"] = " ".join(stage)
1371 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1372 self._write_op_status(nslcmop_id, stage)
bravof922c4172020-11-24 21:21:43 -03001373 await asyncio.sleep(15, loop=self.loop)
tierno69f0d382020-05-07 13:08:09 +00001374 else: # timeout_ns_deploy
1375 raise NgRoException("Timeout waiting ns to deploy")
1376
garciadeblas5697b8b2021-03-24 09:17:02 +01001377 async def _terminate_ng_ro(
1378 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1379 ):
tierno69f0d382020-05-07 13:08:09 +00001380 db_nsr_update = {}
1381 failed_detail = []
1382 action_id = None
1383 start_deploy = time()
1384 try:
1385 target = {
1386 "ns": {"vld": []},
1387 "vnf": [],
1388 "image": [],
1389 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001390 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001391 }
1392 desc = await self.RO.deploy(nsr_id, target)
1393 action_id = desc["action_id"]
1394 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = action_id
1395 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001396 self.logger.debug(
1397 logging_text
1398 + "ns terminate action at RO. action_id={}".format(action_id)
1399 )
tierno69f0d382020-05-07 13:08:09 +00001400
1401 # wait until done
1402 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001403 await self._wait_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02001404 nsr_id,
1405 action_id,
1406 nslcmop_id,
1407 start_deploy,
1408 delete_timeout,
1409 stage,
1410 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001411 )
tierno69f0d382020-05-07 13:08:09 +00001412
1413 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
1414 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1415 # delete all nsr
1416 await self.RO.delete(nsr_id)
1417 except Exception as e:
1418 if isinstance(e, NgRoException) and e.http_code == 404: # not found
1419 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1420 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1421 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01001422 self.logger.debug(
1423 logging_text + "RO_action_id={} already deleted".format(action_id)
1424 )
tierno69f0d382020-05-07 13:08:09 +00001425 elif isinstance(e, NgRoException) and e.http_code == 409: # conflict
1426 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001427 self.logger.debug(
1428 logging_text
1429 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1430 )
tierno69f0d382020-05-07 13:08:09 +00001431 else:
1432 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001433 self.logger.error(
1434 logging_text
1435 + "RO_action_id={} delete error: {}".format(action_id, e)
1436 )
tierno69f0d382020-05-07 13:08:09 +00001437
1438 if failed_detail:
1439 stage[2] = "Error deleting from VIM"
1440 else:
1441 stage[2] = "Deleted from VIM"
1442 db_nsr_update["detailed-status"] = " ".join(stage)
1443 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1444 self._write_op_status(nslcmop_id, stage)
1445
1446 if failed_detail:
1447 raise LcmException("; ".join(failed_detail))
1448 return
1449
garciadeblas5697b8b2021-03-24 09:17:02 +01001450 async def instantiate_RO(
1451 self,
1452 logging_text,
1453 nsr_id,
1454 nsd,
1455 db_nsr,
1456 db_nslcmop,
1457 db_vnfrs,
1458 db_vnfds,
1459 n2vc_key_list,
1460 stage,
1461 ):
tiernoe95ed362020-04-23 08:24:57 +00001462 """
1463 Instantiate at RO
1464 :param logging_text: preffix text to use at logging
1465 :param nsr_id: nsr identity
1466 :param nsd: database content of ns descriptor
1467 :param db_nsr: database content of ns record
1468 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1469 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001470 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001471 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1472 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1473 :return: None or exception
1474 """
tiernoe876f672020-02-13 14:34:48 +00001475 try:
tiernoe876f672020-02-13 14:34:48 +00001476 start_deploy = time()
1477 ns_params = db_nslcmop.get("operationParams")
1478 if ns_params and ns_params.get("timeout_ns_deploy"):
1479 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1480 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001481 timeout_ns_deploy = self.timeout.get(
1482 "ns_deploy", self.timeout_ns_deploy
1483 )
quilesj7e13aeb2019-10-08 13:34:55 +02001484
tiernoe876f672020-02-13 14:34:48 +00001485 # Check for and optionally request placement optimization. Database will be updated if placement activated
1486 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001487 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1488 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1489 for vnfr in db_vnfrs.values():
1490 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1491 break
1492 else:
1493 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001494
garciadeblas5697b8b2021-03-24 09:17:02 +01001495 return await self._instantiate_ng_ro(
1496 logging_text,
1497 nsr_id,
1498 nsd,
1499 db_nsr,
1500 db_nslcmop,
1501 db_vnfrs,
1502 db_vnfds,
1503 n2vc_key_list,
1504 stage,
1505 start_deploy,
1506 timeout_ns_deploy,
1507 )
tierno2357f4e2020-10-19 16:38:59 +00001508 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001509 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001510 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001511 self.logger.error(
1512 "Error deploying at VIM {}".format(e),
1513 exc_info=not isinstance(
1514 e,
1515 (
1516 ROclient.ROClientException,
1517 LcmException,
1518 DbException,
1519 NgRoException,
1520 ),
1521 ),
1522 )
tiernoe876f672020-02-13 14:34:48 +00001523 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001524
tierno7ecbc342020-09-21 14:05:39 +00001525 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1526 """
1527 Wait for kdu to be up, get ip address
1528 :param logging_text: prefix use for logging
1529 :param nsr_id:
1530 :param vnfr_id:
1531 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001532 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001533 """
1534
1535 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1536 nb_tries = 0
1537
1538 while nb_tries < 360:
1539 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001540 kdur = next(
1541 (
1542 x
1543 for x in get_iterable(db_vnfr, "kdur")
1544 if x.get("kdu-name") == kdu_name
1545 ),
1546 None,
1547 )
tierno7ecbc342020-09-21 14:05:39 +00001548 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001549 raise LcmException(
1550 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1551 )
tierno7ecbc342020-09-21 14:05:39 +00001552 if kdur.get("status"):
1553 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001554 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001555 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001556 raise LcmException(
1557 "target KDU={} is in error state".format(kdu_name)
1558 )
tierno7ecbc342020-09-21 14:05:39 +00001559
1560 await asyncio.sleep(10, loop=self.loop)
1561 nb_tries += 1
1562 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1563
garciadeblas5697b8b2021-03-24 09:17:02 +01001564 async def wait_vm_up_insert_key_ro(
1565 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1566 ):
tiernoa5088192019-11-26 16:12:53 +00001567 """
1568 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1569 :param logging_text: prefix use for logging
1570 :param nsr_id:
1571 :param vnfr_id:
1572 :param vdu_id:
1573 :param vdu_index:
1574 :param pub_key: public ssh key to inject, None to skip
1575 :param user: user to apply the public ssh key
1576 :return: IP address
1577 """
quilesj7e13aeb2019-10-08 13:34:55 +02001578
tierno2357f4e2020-10-19 16:38:59 +00001579 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001580 ro_nsr_id = None
1581 ip_address = None
1582 nb_tries = 0
1583 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001584 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001585
tiernod8323042019-08-09 11:32:23 +00001586 while True:
quilesj3149f262019-12-03 10:58:10 +00001587 ro_retries += 1
1588 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001589 raise LcmException(
1590 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1591 )
quilesj3149f262019-12-03 10:58:10 +00001592
tiernod8323042019-08-09 11:32:23 +00001593 await asyncio.sleep(10, loop=self.loop)
quilesj7e13aeb2019-10-08 13:34:55 +02001594
1595 # get ip address
tiernod8323042019-08-09 11:32:23 +00001596 if not target_vdu_id:
1597 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001598
1599 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001600 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001601 raise LcmException(
1602 "Cannot inject ssh-key because target VNF is in error state"
1603 )
tiernod8323042019-08-09 11:32:23 +00001604 ip_address = db_vnfr.get("ip-address")
1605 if not ip_address:
1606 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001607 vdur = next(
1608 (
1609 x
1610 for x in get_iterable(db_vnfr, "vdur")
1611 if x.get("ip-address") == ip_address
1612 ),
1613 None,
1614 )
quilesj3149f262019-12-03 10:58:10 +00001615 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001616 vdur = next(
1617 (
1618 x
1619 for x in get_iterable(db_vnfr, "vdur")
1620 if x.get("vdu-id-ref") == vdu_id
1621 and x.get("count-index") == vdu_index
1622 ),
1623 None,
1624 )
quilesj3149f262019-12-03 10:58:10 +00001625
garciadeblas5697b8b2021-03-24 09:17:02 +01001626 if (
1627 not vdur and len(db_vnfr.get("vdur", ())) == 1
1628 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001629 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001630 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001631 raise LcmException(
1632 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1633 vnfr_id, vdu_id, vdu_index
1634 )
1635 )
tierno2357f4e2020-10-19 16:38:59 +00001636 # New generation RO stores information at "vim_info"
1637 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001638 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001639 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001640 target_vim = next(
1641 t for t in vdur["vim_info"]
1642 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001643 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001644 if (
1645 vdur.get("pdu-type")
1646 or vdur.get("status") == "ACTIVE"
1647 or ng_ro_status == "ACTIVE"
1648 ):
quilesj3149f262019-12-03 10:58:10 +00001649 ip_address = vdur.get("ip-address")
1650 if not ip_address:
1651 continue
1652 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001653 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001654 raise LcmException(
1655 "Cannot inject ssh-key because target VM is in error state"
1656 )
quilesj3149f262019-12-03 10:58:10 +00001657
tiernod8323042019-08-09 11:32:23 +00001658 if not target_vdu_id:
1659 continue
tiernod8323042019-08-09 11:32:23 +00001660
quilesj7e13aeb2019-10-08 13:34:55 +02001661 # inject public key into machine
1662 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001663 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001664 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001665 if vdur.get("pdu-type"):
1666 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1667 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001668 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001669 ro_vm_id = "{}-{}".format(
1670 db_vnfr["member-vnf-index-ref"], target_vdu_id
1671 ) # TODO add vdu_index
tierno69f0d382020-05-07 13:08:09 +00001672 if self.ng_ro:
garciadeblas5697b8b2021-03-24 09:17:02 +01001673 target = {
1674 "action": {
1675 "action": "inject_ssh_key",
1676 "key": pub_key,
1677 "user": user,
1678 },
1679 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1680 }
tierno2357f4e2020-10-19 16:38:59 +00001681 desc = await self.RO.deploy(nsr_id, target)
1682 action_id = desc["action_id"]
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02001683 await self._wait_ng_ro(
1684 nsr_id, action_id, timeout=600, operation="instantiation"
1685 )
tierno2357f4e2020-10-19 16:38:59 +00001686 break
tierno69f0d382020-05-07 13:08:09 +00001687 else:
tierno2357f4e2020-10-19 16:38:59 +00001688 # wait until NS is deployed at RO
1689 if not ro_nsr_id:
1690 db_nsrs = self.db.get_one("nsrs", {"_id": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001691 ro_nsr_id = deep_get(
1692 db_nsrs, ("_admin", "deployed", "RO", "nsr_id")
1693 )
tierno2357f4e2020-10-19 16:38:59 +00001694 if not ro_nsr_id:
1695 continue
tierno69f0d382020-05-07 13:08:09 +00001696 result_dict = await self.RO.create_action(
1697 item="ns",
1698 item_id_name=ro_nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001699 descriptor={
1700 "add_public_key": pub_key,
1701 "vms": [ro_vm_id],
1702 "user": user,
1703 },
tierno69f0d382020-05-07 13:08:09 +00001704 )
1705 # result_dict contains the format {VM-id: {vim_result: 200, description: text}}
1706 if not result_dict or not isinstance(result_dict, dict):
garciadeblas5697b8b2021-03-24 09:17:02 +01001707 raise LcmException(
1708 "Unknown response from RO when injecting key"
1709 )
tierno69f0d382020-05-07 13:08:09 +00001710 for result in result_dict.values():
1711 if result.get("vim_result") == 200:
1712 break
1713 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001714 raise ROclient.ROClientException(
1715 "error injecting key: {}".format(
1716 result.get("description")
1717 )
1718 )
tierno69f0d382020-05-07 13:08:09 +00001719 break
1720 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001721 raise LcmException(
1722 "Reaching max tries injecting key. Error: {}".format(e)
1723 )
quilesj7e13aeb2019-10-08 13:34:55 +02001724 except ROclient.ROClientException as e:
tiernoa5088192019-11-26 16:12:53 +00001725 if not nb_tries:
garciadeblas5697b8b2021-03-24 09:17:02 +01001726 self.logger.debug(
1727 logging_text
1728 + "error injecting key: {}. Retrying until {} seconds".format(
1729 e, 20 * 10
1730 )
1731 )
quilesj7e13aeb2019-10-08 13:34:55 +02001732 nb_tries += 1
tiernoa5088192019-11-26 16:12:53 +00001733 if nb_tries >= 20:
garciadeblas5697b8b2021-03-24 09:17:02 +01001734 raise LcmException(
1735 "Reaching max tries injecting key. Error: {}".format(e)
1736 )
quilesj7e13aeb2019-10-08 13:34:55 +02001737 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001738 break
1739
1740 return ip_address
1741
tierno5ee02052019-12-05 19:55:02 +00001742 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1743 """
1744 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1745 """
1746 my_vca = vca_deployed_list[vca_index]
1747 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001748 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001749 return
1750 timeout = 300
1751 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001752 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1753 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1754 configuration_status_list = db_nsr["configurationStatus"]
1755 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001756 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001757 # myself
tierno5ee02052019-12-05 19:55:02 +00001758 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001759 if not my_vca.get("member-vnf-index") or (
1760 vca_deployed.get("member-vnf-index")
1761 == my_vca.get("member-vnf-index")
1762 ):
quilesj3655ae02019-12-12 16:08:35 +00001763 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001764 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001765 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001766 elif internal_status == "BROKEN":
1767 raise LcmException(
1768 "Configuration aborted because dependent charm/s has failed"
1769 )
quilesj3655ae02019-12-12 16:08:35 +00001770 else:
1771 break
tierno5ee02052019-12-05 19:55:02 +00001772 else:
quilesj3655ae02019-12-12 16:08:35 +00001773 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001774 return
1775 await asyncio.sleep(10)
1776 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001777
1778 raise LcmException("Configuration aborted because dependent charm/s timeout")
1779
David Garciac1fe90a2021-03-31 19:12:02 +02001780 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001781 vca_id = None
1782 if db_vnfr:
1783 vca_id = deep_get(db_vnfr, ("vca-id",))
1784 elif db_nsr:
1785 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1786 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1787 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001788
garciadeblas5697b8b2021-03-24 09:17:02 +01001789 async def instantiate_N2VC(
1790 self,
1791 logging_text,
1792 vca_index,
1793 nsi_id,
1794 db_nsr,
1795 db_vnfr,
1796 vdu_id,
1797 kdu_name,
1798 vdu_index,
1799 config_descriptor,
1800 deploy_params,
1801 base_folder,
1802 nslcmop_id,
1803 stage,
1804 vca_type,
1805 vca_name,
1806 ee_config_descriptor,
1807 ):
tiernod8323042019-08-09 11:32:23 +00001808 nsr_id = db_nsr["_id"]
1809 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001810 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001811 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001812 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001813 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001814 "collection": "nsrs",
1815 "filter": {"_id": nsr_id},
1816 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001817 }
tiernod8323042019-08-09 11:32:23 +00001818 step = ""
1819 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001820 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001821 element_under_configuration = nsr_id
1822
tiernod8323042019-08-09 11:32:23 +00001823 vnfr_id = None
1824 if db_vnfr:
1825 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001826 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001827
garciadeblas5697b8b2021-03-24 09:17:02 +01001828 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001829
aktas98488ed2021-07-29 17:42:49 +03001830 if vca_type == "native_charm":
1831 index_number = 0
1832 else:
1833 index_number = vdu_index or 0
1834
tiernod8323042019-08-09 11:32:23 +00001835 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001836 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001837 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001838 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001839 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001840 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001841 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001842 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001843 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001844 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001845 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001846 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001847 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001848 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001849
1850 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001851 if base_folder["pkg-dir"]:
1852 artifact_path = "{}/{}/{}/{}".format(
1853 base_folder["folder"],
1854 base_folder["pkg-dir"],
1855 "charms"
aticig15db6142022-01-24 12:51:26 +03001856 if vca_type
1857 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001858 else "helm-charts",
1859 vca_name,
1860 )
1861 else:
1862 artifact_path = "{}/Scripts/{}/{}/".format(
1863 base_folder["folder"],
1864 "charms"
aticig15db6142022-01-24 12:51:26 +03001865 if vca_type
1866 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001867 else "helm-charts",
1868 vca_name,
1869 )
bravof922c4172020-11-24 21:21:43 -03001870
1871 self.logger.debug("Artifact path > {}".format(artifact_path))
1872
tiernoa278b842020-07-08 15:33:55 +00001873 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001874 initial_config_primitive_list = config_descriptor.get(
1875 "initial-config-primitive"
1876 )
tiernoa278b842020-07-08 15:33:55 +00001877
garciadeblas5697b8b2021-03-24 09:17:02 +01001878 self.logger.debug(
1879 "Initial config primitive list > {}".format(
1880 initial_config_primitive_list
1881 )
1882 )
bravof922c4172020-11-24 21:21:43 -03001883
tiernoa278b842020-07-08 15:33:55 +00001884 # add config if not present for NS charm
1885 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001886 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001887 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1888 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1889 )
tiernod8323042019-08-09 11:32:23 +00001890
garciadeblas5697b8b2021-03-24 09:17:02 +01001891 self.logger.debug(
1892 "Initial config primitive list #2 > {}".format(
1893 initial_config_primitive_list
1894 )
1895 )
tierno588547c2020-07-01 15:30:20 +00001896 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001897 # find old ee_id if exists
1898 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001899
David Garciac1fe90a2021-03-31 19:12:02 +02001900 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001901 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001902 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
tierno588547c2020-07-01 15:30:20 +00001903 self._write_configuration_status(
1904 nsr_id=nsr_id,
1905 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001906 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001907 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001908 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001909 )
tiernod8323042019-08-09 11:32:23 +00001910
tierno588547c2020-07-01 15:30:20 +00001911 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001912 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001913
1914 ee_id = None
1915 credentials = None
1916 if vca_type == "k8s_proxy_charm":
1917 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001918 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001919 namespace=namespace,
1920 artifact_path=artifact_path,
1921 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001922 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001923 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001924 elif vca_type == "helm" or vca_type == "helm-v3":
1925 ee_id, credentials = await self.vca_map[
1926 vca_type
1927 ].create_execution_environment(
bravof922c4172020-11-24 21:21:43 -03001928 namespace=namespace,
1929 reuse_ee_id=ee_id,
1930 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001931 config=osm_config,
1932 artifact_path=artifact_path,
garciadeblas5697b8b2021-03-24 09:17:02 +01001933 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001934 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001935 else:
1936 ee_id, credentials = await self.vca_map[
1937 vca_type
1938 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001939 namespace=namespace,
1940 reuse_ee_id=ee_id,
1941 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001942 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001943 )
quilesj3655ae02019-12-12 16:08:35 +00001944
tierno588547c2020-07-01 15:30:20 +00001945 elif vca_type == "native_charm":
1946 step = "Waiting to VM being up and getting IP address"
1947 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001948 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1949 logging_text,
1950 nsr_id,
1951 vnfr_id,
1952 vdu_id,
1953 vdu_index,
1954 user=None,
1955 pub_key=None,
1956 )
tierno588547c2020-07-01 15:30:20 +00001957 credentials = {"hostname": rw_mgmt_ip}
1958 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001959 username = deep_get(
1960 config_descriptor, ("config-access", "ssh-access", "default-user")
1961 )
tierno588547c2020-07-01 15:30:20 +00001962 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1963 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001964 if not username and initial_config_primitive_list:
1965 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001966 for param in config_primitive.get("parameter", ()):
1967 if param["name"] == "ssh-username":
1968 username = param["value"]
1969 break
1970 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001971 raise LcmException(
1972 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1973 "'config-access.ssh-access.default-user'"
1974 )
tierno588547c2020-07-01 15:30:20 +00001975 credentials["username"] = username
1976 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001977
tierno588547c2020-07-01 15:30:20 +00001978 self._write_configuration_status(
1979 nsr_id=nsr_id,
1980 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001981 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001982 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001983 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001984 )
quilesj3655ae02019-12-12 16:08:35 +00001985
tierno588547c2020-07-01 15:30:20 +00001986 step = "register execution environment {}".format(credentials)
1987 self.logger.debug(logging_text + step)
1988 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001989 credentials=credentials,
1990 namespace=namespace,
1991 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001992 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001993 )
tierno3bedc9b2019-11-27 15:46:57 +00001994
tierno588547c2020-07-01 15:30:20 +00001995 # for compatibility with MON/POL modules, the need model and application name at database
1996 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001997 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001998 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1999 if len(ee_id_parts) >= 2:
2000 model_name = ee_id_parts[0]
2001 application_name = ee_id_parts[1]
2002 db_nsr_update[db_update_entry + "model"] = model_name
2003 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00002004
2005 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00002006 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00002007
tiernoc231a872020-01-21 08:49:05 +00002008 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00002009 nsr_id=nsr_id,
2010 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01002011 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00002012 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00002013 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01002014 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00002015 )
2016
tierno3bedc9b2019-11-27 15:46:57 +00002017 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02002018 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02002019 config = None
tierno588547c2020-07-01 15:30:20 +00002020 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01002021 config_primitive = next(
2022 (p for p in initial_config_primitive_list if p["name"] == "config"),
2023 None,
2024 )
tiernoa278b842020-07-08 15:33:55 +00002025 if config_primitive:
2026 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01002027 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00002028 )
tierno588547c2020-07-01 15:30:20 +00002029 num_units = 1
2030 if vca_type == "lxc_proxy_charm":
2031 if element_type == "NS":
2032 num_units = db_nsr.get("config-units") or 1
2033 elif element_type == "VNF":
2034 num_units = db_vnfr.get("config-units") or 1
2035 elif element_type == "VDU":
2036 for v in db_vnfr["vdur"]:
2037 if vdu_id == v["vdu-id-ref"]:
2038 num_units = v.get("config-units") or 1
2039 break
David Garciaaae391f2020-11-09 11:12:54 +01002040 if vca_type != "k8s_proxy_charm":
2041 await self.vca_map[vca_type].install_configuration_sw(
2042 ee_id=ee_id,
2043 artifact_path=artifact_path,
2044 db_dict=db_dict,
2045 config=config,
2046 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02002047 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002048 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01002049 )
quilesj7e13aeb2019-10-08 13:34:55 +02002050
quilesj63f90042020-01-17 09:53:55 +00002051 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01002052 self.update_db_2(
2053 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
2054 )
quilesj63f90042020-01-17 09:53:55 +00002055
2056 # add relations for this VCA (wait for other peers related with this VCA)
garciadeblas5697b8b2021-03-24 09:17:02 +01002057 await self._add_vca_relations(
2058 logging_text=logging_text,
2059 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002060 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02002061 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01002062 )
quilesj63f90042020-01-17 09:53:55 +00002063
quilesj7e13aeb2019-10-08 13:34:55 +02002064 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02002065 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002066 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00002067 pub_key = None
2068 user = None
tierno588547c2020-07-01 15:30:20 +00002069 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01002070 if deep_get(
2071 config_descriptor, ("config-access", "ssh-access", "required")
2072 ):
tierno588547c2020-07-01 15:30:20 +00002073 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00002074 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01002075 user = deep_get(
2076 config_descriptor,
2077 ("config-access", "ssh-access", "default-user"),
2078 )
tierno3bedc9b2019-11-27 15:46:57 +00002079 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02002080 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01002081 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02002082 )
quilesj7e13aeb2019-10-08 13:34:55 +02002083
garciadeblas5697b8b2021-03-24 09:17:02 +01002084 step = "Insert public key into VM user={} ssh_key={}".format(
2085 user, pub_key
2086 )
tierno3bedc9b2019-11-27 15:46:57 +00002087 else:
tierno588547c2020-07-01 15:30:20 +00002088 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00002089 step = "Waiting to VM being up and getting IP address"
2090 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02002091
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002092 # default rw_mgmt_ip to None, avoiding the non definition of the variable
2093 rw_mgmt_ip = None
2094
tierno3bedc9b2019-11-27 15:46:57 +00002095 # n2vc_redesign STEP 5.1
2096 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00002097 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00002098 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02002099 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01002100 logging_text, nsr_id, vnfr_id, kdu_name
2101 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002102 vnfd = self.db.get_one(
2103 "vnfds_revisions",
2104 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
2105 )
2106 kdu = get_kdu(vnfd, kdu_name)
2107 kdu_services = [
2108 service["name"] for service in get_kdu_services(kdu)
2109 ]
2110 exposed_services = []
2111 for service in services:
2112 if any(s in service["name"] for s in kdu_services):
2113 exposed_services.append(service)
2114 await self.vca_map[vca_type].exec_primitive(
2115 ee_id=ee_id,
2116 primitive_name="config",
2117 params_dict={
2118 "osm-config": json.dumps(
2119 OsmConfigBuilder(
2120 k8s={"services": exposed_services}
2121 ).build()
2122 )
2123 },
2124 vca_id=vca_id,
2125 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002126
2127 # This verification is needed in order to avoid trying to add a public key
2128 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
2129 # for a KNF and not for its KDUs, the previous verification gives False, and the code
2130 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
2131 # or it is a KNF)
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02002132 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002133 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2134 logging_text,
2135 nsr_id,
2136 vnfr_id,
2137 vdu_id,
2138 vdu_index,
2139 user=user,
2140 pub_key=pub_key,
2141 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002142
garciadeblas5697b8b2021-03-24 09:17:02 +01002143 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02002144
tiernoa5088192019-11-26 16:12:53 +00002145 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02002146 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00002147
2148 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01002149 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00002150
2151 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00002152 if initial_config_primitive_list:
2153 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00002154
2155 # stage, in function of element type: vdu, kdu, vnf or ns
2156 my_vca = vca_deployed_list[vca_index]
2157 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
2158 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01002159 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00002160 elif my_vca.get("member-vnf-index"):
2161 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01002162 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00002163 else:
2164 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01002165 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00002166
tiernoc231a872020-01-21 08:49:05 +00002167 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002168 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002169 )
2170
garciadeblas5697b8b2021-03-24 09:17:02 +01002171 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002172
tiernoe876f672020-02-13 14:34:48 +00002173 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002174 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002175 # adding information on the vca_deployed if it is a NS execution environment
2176 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002177 deploy_params["ns_config_info"] = json.dumps(
2178 self._get_ns_config_info(nsr_id)
2179 )
tiernod8323042019-08-09 11:32:23 +00002180 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002181 primitive_params_ = self._map_primitive_params(
2182 initial_config_primitive, {}, deploy_params
2183 )
tierno3bedc9b2019-11-27 15:46:57 +00002184
garciadeblas5697b8b2021-03-24 09:17:02 +01002185 step = "execute primitive '{}' params '{}'".format(
2186 initial_config_primitive["name"], primitive_params_
2187 )
tiernod8323042019-08-09 11:32:23 +00002188 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002189 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002190 ee_id=ee_id,
2191 primitive_name=initial_config_primitive["name"],
2192 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002193 db_dict=db_dict,
2194 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002195 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002196 )
tiernoe876f672020-02-13 14:34:48 +00002197 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2198 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002199 if config_descriptor.get("terminate-config-primitive"):
2200 self.update_db_2(
2201 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2202 )
tiernoe876f672020-02-13 14:34:48 +00002203 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002204
tiernod8323042019-08-09 11:32:23 +00002205 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002206
tiernob996d942020-07-03 14:52:28 +00002207 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002208 if vca_type == "helm" or vca_type == "helm-v3":
bravof73bac502021-05-11 07:38:47 -04002209 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002210 ee_id=ee_id,
2211 artifact_path=artifact_path,
2212 ee_config_descriptor=ee_config_descriptor,
2213 vnfr_id=vnfr_id,
2214 nsr_id=nsr_id,
2215 target_ip=rw_mgmt_ip,
2216 )
2217 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002218 self.update_db_2(
2219 "nsrs",
2220 nsr_id,
2221 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2222 )
tiernob996d942020-07-03 14:52:28 +00002223
bravof73bac502021-05-11 07:38:47 -04002224 for job in prometheus_jobs:
2225 self.db.set_one(
2226 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002227 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002228 job,
2229 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002230 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002231 )
2232
quilesj7e13aeb2019-10-08 13:34:55 +02002233 step = "instantiated at VCA"
2234 self.logger.debug(logging_text + step)
2235
tiernoc231a872020-01-21 08:49:05 +00002236 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002237 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002238 )
2239
tiernod8323042019-08-09 11:32:23 +00002240 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002241 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002242 if not isinstance(
2243 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2244 ):
2245 self.logger.error(
2246 "Exception while {} : {}".format(step, e), exc_info=True
2247 )
tiernoc231a872020-01-21 08:49:05 +00002248 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002249 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002250 )
tiernoe876f672020-02-13 14:34:48 +00002251 raise LcmException("{} {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002252
garciadeblas5697b8b2021-03-24 09:17:02 +01002253 def _write_ns_status(
2254 self,
2255 nsr_id: str,
2256 ns_state: str,
2257 current_operation: str,
2258 current_operation_id: str,
2259 error_description: str = None,
2260 error_detail: str = None,
2261 other_update: dict = None,
2262 ):
tiernoe876f672020-02-13 14:34:48 +00002263 """
2264 Update db_nsr fields.
2265 :param nsr_id:
2266 :param ns_state:
2267 :param current_operation:
2268 :param current_operation_id:
2269 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002270 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002271 :param other_update: Other required changes at database if provided, will be cleared
2272 :return:
2273 """
quilesj4cda56b2019-12-05 10:02:20 +00002274 try:
tiernoe876f672020-02-13 14:34:48 +00002275 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002276 db_dict[
2277 "_admin.nslcmop"
2278 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002279 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002280 db_dict["_admin.operation-type"] = (
2281 current_operation if current_operation != "IDLE" else None
2282 )
quilesj4cda56b2019-12-05 10:02:20 +00002283 db_dict["currentOperation"] = current_operation
2284 db_dict["currentOperationID"] = current_operation_id
2285 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002286 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002287
2288 if ns_state:
2289 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002290 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002291 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002292 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002293
garciadeblas5697b8b2021-03-24 09:17:02 +01002294 def _write_op_status(
2295 self,
2296 op_id: str,
2297 stage: list = None,
2298 error_message: str = None,
2299 queuePosition: int = 0,
2300 operation_state: str = None,
2301 other_update: dict = None,
2302 ):
quilesj3655ae02019-12-12 16:08:35 +00002303 try:
tiernoe876f672020-02-13 14:34:48 +00002304 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002305 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002306 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002307 db_dict["stage"] = stage[0]
2308 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002309 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002310 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002311
2312 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002313 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002314 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002315 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002316 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002317 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002318 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002319 self.logger.warn(
2320 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2321 )
quilesj3655ae02019-12-12 16:08:35 +00002322
tierno51183952020-04-03 15:48:18 +00002323 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002324 try:
tierno51183952020-04-03 15:48:18 +00002325 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002326 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002327 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002328 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002329 db_nsr_update = {
2330 "configurationStatus.{}.status".format(index): status
2331 for index, v in enumerate(config_status)
2332 if v
2333 }
quilesj3655ae02019-12-12 16:08:35 +00002334 # update status
tierno51183952020-04-03 15:48:18 +00002335 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002336
tiernoe876f672020-02-13 14:34:48 +00002337 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002338 self.logger.warn(
2339 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2340 )
quilesj3655ae02019-12-12 16:08:35 +00002341
garciadeblas5697b8b2021-03-24 09:17:02 +01002342 def _write_configuration_status(
2343 self,
2344 nsr_id: str,
2345 vca_index: int,
2346 status: str = None,
2347 element_under_configuration: str = None,
2348 element_type: str = None,
2349 other_update: dict = None,
2350 ):
quilesj3655ae02019-12-12 16:08:35 +00002351 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2352 # .format(vca_index, status))
2353
2354 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002355 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002356 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002357 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002358 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002359 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002360 db_dict[
2361 db_path + "elementUnderConfiguration"
2362 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002363 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002364 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002365 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002366 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002367 self.logger.warn(
2368 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2369 status, nsr_id, vca_index, e
2370 )
2371 )
quilesj4cda56b2019-12-05 10:02:20 +00002372
tierno38089af2020-04-16 07:56:58 +00002373 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2374 """
2375 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2376 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2377 Database is used because the result can be obtained from a different LCM worker in case of HA.
2378 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2379 :param db_nslcmop: database content of nslcmop
2380 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002381 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2382 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002383 """
tierno8790a3d2020-04-23 22:49:52 +00002384 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002385 nslcmop_id = db_nslcmop["_id"]
2386 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002387 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002388 self.logger.debug(
2389 logging_text + "Invoke and wait for placement optimization"
2390 )
2391 await self.msg.aiowrite(
2392 "pla", "get_placement", {"nslcmopId": nslcmop_id}, loop=self.loop
2393 )
magnussonle9198bb2020-01-21 13:00:51 +01002394 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002395 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002396 pla_result = None
2397 while not pla_result and wait >= 0:
2398 await asyncio.sleep(db_poll_interval)
2399 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002400 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002401 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002402
2403 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002404 raise LcmException(
2405 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2406 )
magnussonle9198bb2020-01-21 13:00:51 +01002407
garciadeblas5697b8b2021-03-24 09:17:02 +01002408 for pla_vnf in pla_result["vnf"]:
2409 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2410 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002411 continue
tierno8790a3d2020-04-23 22:49:52 +00002412 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002413 self.db.set_one(
2414 "vnfrs",
2415 {"_id": vnfr["_id"]},
2416 {"vim-account-id": pla_vnf["vimAccountId"]},
2417 )
tierno38089af2020-04-16 07:56:58 +00002418 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002419 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002420 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002421
2422 def update_nsrs_with_pla_result(self, params):
2423 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002424 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2425 self.update_db_2(
2426 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2427 )
magnussonle9198bb2020-01-21 13:00:51 +01002428 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002429 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002430
tierno59d22d22018-09-25 18:10:19 +02002431 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002432 """
2433
2434 :param nsr_id: ns instance to deploy
2435 :param nslcmop_id: operation to run
2436 :return:
2437 """
kuused124bfe2019-06-18 12:09:24 +02002438
2439 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002440 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002441 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002442 self.logger.debug(
2443 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2444 )
kuused124bfe2019-06-18 12:09:24 +02002445 return
2446
tierno59d22d22018-09-25 18:10:19 +02002447 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2448 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002449
tierno59d22d22018-09-25 18:10:19 +02002450 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002451
2452 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002453 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002454
2455 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002456 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002457
2458 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002459 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002460 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002461 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002462
tierno59d22d22018-09-25 18:10:19 +02002463 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002464 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002465 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002466 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002467 exc = None
tiernoe876f672020-02-13 14:34:48 +00002468 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002469 stage = [
2470 "Stage 1/5: preparation of the environment.",
2471 "Waiting for previous operations to terminate.",
2472 "",
2473 ]
tiernoe876f672020-02-13 14:34:48 +00002474 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002475 try:
kuused124bfe2019-06-18 12:09:24 +02002476 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002477 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002478
quilesj7e13aeb2019-10-08 13:34:55 +02002479 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002480 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002481 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002482 db_nsr_update["detailed-status"] = "creating"
2483 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002484 self._write_ns_status(
2485 nsr_id=nsr_id,
2486 ns_state="BUILDING",
2487 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002488 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002489 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002490 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002491 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002492
quilesj7e13aeb2019-10-08 13:34:55 +02002493 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002494 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002495 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002496 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2497 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2498 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2499 )
tierno744303e2020-01-13 16:46:31 +00002500 ns_params = db_nslcmop.get("operationParams")
2501 if ns_params and ns_params.get("timeout_ns_deploy"):
2502 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
2503 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01002504 timeout_ns_deploy = self.timeout.get(
2505 "ns_deploy", self.timeout_ns_deploy
2506 )
quilesj7e13aeb2019-10-08 13:34:55 +02002507
2508 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002509 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002510 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002511 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002512 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002513 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002514 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002515 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002516 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002517 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002518
quilesj7e13aeb2019-10-08 13:34:55 +02002519 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002520 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002521 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002522 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002523
quilesj7e13aeb2019-10-08 13:34:55 +02002524 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002525 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002526
2527 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002528 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002529 if vnfr.get("kdur"):
2530 kdur_list = []
2531 for kdur in vnfr["kdur"]:
2532 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002533 kdur["additionalParams"] = json.loads(
2534 kdur["additionalParams"]
2535 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002536 kdur_list.append(kdur)
2537 vnfr["kdur"] = kdur_list
2538
bravof922c4172020-11-24 21:21:43 -03002539 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2540 vnfd_id = vnfr["vnfd-id"]
2541 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002542 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002543
quilesj7e13aeb2019-10-08 13:34:55 +02002544 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002545 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002546 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002547 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2548 vnfd_id, vnfd_ref
2549 )
tiernoe876f672020-02-13 14:34:48 +00002550 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002551 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002552
quilesj7e13aeb2019-10-08 13:34:55 +02002553 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002554 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002555
2556 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002557 vca_deployed_list = None
2558 if db_nsr["_admin"].get("deployed"):
2559 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2560 if vca_deployed_list is None:
2561 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002562 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002563 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002564 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002565 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002566 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002567 elif isinstance(vca_deployed_list, dict):
2568 # maintain backward compatibility. Change a dict to list at database
2569 vca_deployed_list = list(vca_deployed_list.values())
2570 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002571 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002572
garciadeblas5697b8b2021-03-24 09:17:02 +01002573 if not isinstance(
2574 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2575 ):
tiernoa009e552019-01-30 16:45:44 +00002576 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2577 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002578
tiernobaa51102018-12-14 13:16:18 +00002579 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2580 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2581 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002582 self.db.set_list(
2583 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2584 )
quilesj3655ae02019-12-12 16:08:35 +00002585
2586 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002587 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2588 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002589
tiernob5203912020-08-11 11:20:13 +00002590 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002591 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002592 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002593 await self.deploy_kdus(
2594 logging_text=logging_text,
2595 nsr_id=nsr_id,
2596 nslcmop_id=nslcmop_id,
2597 db_vnfrs=db_vnfrs,
2598 db_vnfds=db_vnfds,
2599 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002600 )
tiernoe876f672020-02-13 14:34:48 +00002601
2602 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002603 # n2vc_redesign STEP 1 Get VCA public ssh-key
2604 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002605 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002606 n2vc_key_list = [n2vc_key]
2607 if self.vca_config.get("public_key"):
2608 n2vc_key_list.append(self.vca_config["public_key"])
tierno98ad6ea2019-05-30 17:16:28 +00002609
tiernoe876f672020-02-13 14:34:48 +00002610 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002611 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002612 self.instantiate_RO(
2613 logging_text=logging_text,
2614 nsr_id=nsr_id,
2615 nsd=nsd,
2616 db_nsr=db_nsr,
2617 db_nslcmop=db_nslcmop,
2618 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002619 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002620 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002621 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002622 )
tiernod8323042019-08-09 11:32:23 +00002623 )
2624 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002625 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002626
tiernod8323042019-08-09 11:32:23 +00002627 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002628 stage[1] = "Deploying Execution Environments."
2629 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002630
tiernod8323042019-08-09 11:32:23 +00002631 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002632 for vnf_profile in get_vnf_profiles(nsd):
2633 vnfd_id = vnf_profile["vnfd-id"]
2634 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2635 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002636 db_vnfr = db_vnfrs[member_vnf_index]
2637 base_folder = vnfd["_admin"]["storage"]
2638 vdu_id = None
2639 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002640 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002641 kdu_name = None
tierno59d22d22018-09-25 18:10:19 +02002642
tierno8a518872018-12-21 13:42:14 +00002643 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002644 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002645 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002646 deploy_params.update(
2647 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2648 )
tierno8a518872018-12-21 13:42:14 +00002649
bravofe5a31bc2021-02-17 19:09:12 -03002650 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002651 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002652 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002653 logging_text=logging_text
2654 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002655 db_nsr=db_nsr,
2656 db_vnfr=db_vnfr,
2657 nslcmop_id=nslcmop_id,
2658 nsr_id=nsr_id,
2659 nsi_id=nsi_id,
2660 vnfd_id=vnfd_id,
2661 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002662 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002663 member_vnf_index=member_vnf_index,
2664 vdu_index=vdu_index,
2665 vdu_name=vdu_name,
2666 deploy_params=deploy_params,
2667 descriptor_config=descriptor_config,
2668 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002669 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002670 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002671 )
tierno59d22d22018-09-25 18:10:19 +02002672
2673 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002674 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002675 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002676 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002677 vdur = find_in_list(
2678 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2679 )
bravof922c4172020-11-24 21:21:43 -03002680
tierno626e0152019-11-29 14:16:16 +00002681 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002682 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002683 else:
2684 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002685 deploy_params_vdu["OSM"] = get_osm_params(
2686 db_vnfr, vdu_id, vdu_count_index=0
2687 )
endika76ba9232021-06-21 18:55:07 +02002688 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002689
2690 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002691 self.logger.debug(
2692 "Descriptor config > {}".format(descriptor_config)
2693 )
tierno588547c2020-07-01 15:30:20 +00002694 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002695 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002696 kdu_name = None
bravof922c4172020-11-24 21:21:43 -03002697 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002698 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002699 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002700 logging_text=logging_text
2701 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2702 member_vnf_index, vdu_id, vdu_index
2703 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002704 db_nsr=db_nsr,
2705 db_vnfr=db_vnfr,
2706 nslcmop_id=nslcmop_id,
2707 nsr_id=nsr_id,
2708 nsi_id=nsi_id,
2709 vnfd_id=vnfd_id,
2710 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002711 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002712 member_vnf_index=member_vnf_index,
2713 vdu_index=vdu_index,
2714 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002715 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002716 descriptor_config=descriptor_config,
2717 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002718 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002719 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002720 )
bravof922c4172020-11-24 21:21:43 -03002721 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002722 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002723 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002724 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002725 vdu_id = None
2726 vdu_index = 0
2727 vdu_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002728 kdur = next(
2729 x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name
2730 )
bravof922c4172020-11-24 21:21:43 -03002731 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002732 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002733 deploy_params_kdu.update(
2734 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002735 )
tierno59d22d22018-09-25 18:10:19 +02002736
calvinosanch9f9c6f22019-11-04 13:37:39 +01002737 self._deploy_n2vc(
2738 logging_text=logging_text,
2739 db_nsr=db_nsr,
2740 db_vnfr=db_vnfr,
2741 nslcmop_id=nslcmop_id,
2742 nsr_id=nsr_id,
2743 nsi_id=nsi_id,
2744 vnfd_id=vnfd_id,
2745 vdu_id=vdu_id,
2746 kdu_name=kdu_name,
2747 member_vnf_index=member_vnf_index,
2748 vdu_index=vdu_index,
2749 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002750 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002751 descriptor_config=descriptor_config,
2752 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002753 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002754 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002755 )
tierno59d22d22018-09-25 18:10:19 +02002756
tierno1b633412019-02-25 16:48:23 +00002757 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002758 descriptor_config = nsd.get("ns-configuration")
2759 if descriptor_config and descriptor_config.get("juju"):
2760 vnfd_id = None
2761 db_vnfr = None
2762 member_vnf_index = None
2763 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002764 kdu_name = None
tiernod8323042019-08-09 11:32:23 +00002765 vdu_index = 0
2766 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002767
tiernod8323042019-08-09 11:32:23 +00002768 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002769 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002770 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002771 deploy_params.update(
2772 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2773 )
tiernod8323042019-08-09 11:32:23 +00002774 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002775 self._deploy_n2vc(
2776 logging_text=logging_text,
2777 db_nsr=db_nsr,
2778 db_vnfr=db_vnfr,
2779 nslcmop_id=nslcmop_id,
2780 nsr_id=nsr_id,
2781 nsi_id=nsi_id,
2782 vnfd_id=vnfd_id,
2783 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002784 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002785 member_vnf_index=member_vnf_index,
2786 vdu_index=vdu_index,
2787 vdu_name=vdu_name,
2788 deploy_params=deploy_params,
2789 descriptor_config=descriptor_config,
2790 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002791 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002792 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002793 )
tierno1b633412019-02-25 16:48:23 +00002794
tiernoe876f672020-02-13 14:34:48 +00002795 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002796
garciadeblas5697b8b2021-03-24 09:17:02 +01002797 except (
2798 ROclient.ROClientException,
2799 DbException,
2800 LcmException,
2801 N2VCException,
2802 ) as e:
2803 self.logger.error(
2804 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
2805 )
tierno59d22d22018-09-25 18:10:19 +02002806 exc = e
2807 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01002808 self.logger.error(
2809 logging_text + "Cancelled Exception while '{}'".format(stage[1])
2810 )
tierno59d22d22018-09-25 18:10:19 +02002811 exc = "Operation was cancelled"
2812 except Exception as e:
2813 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01002814 self.logger.critical(
2815 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
2816 exc_info=True,
2817 )
tierno59d22d22018-09-25 18:10:19 +02002818 finally:
2819 if exc:
tiernoe876f672020-02-13 14:34:48 +00002820 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00002821 try:
tiernoe876f672020-02-13 14:34:48 +00002822 # wait for pending tasks
2823 if tasks_dict_info:
2824 stage[1] = "Waiting for instantiate pending tasks."
2825 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01002826 error_list += await self._wait_for_tasks(
2827 logging_text,
2828 tasks_dict_info,
2829 timeout_ns_deploy,
2830 stage,
2831 nslcmop_id,
2832 nsr_id=nsr_id,
2833 )
tiernoe876f672020-02-13 14:34:48 +00002834 stage[1] = stage[2] = ""
2835 except asyncio.CancelledError:
2836 error_list.append("Cancelled")
2837 # TODO cancel all tasks
2838 except Exception as exc:
2839 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00002840
tiernoe876f672020-02-13 14:34:48 +00002841 # update operation-status
2842 db_nsr_update["operational-status"] = "running"
2843 # let's begin with VCA 'configured' status (later we can change it)
2844 db_nsr_update["config-status"] = "configured"
2845 for task, task_name in tasks_dict_info.items():
2846 if not task.done() or task.cancelled() or task.exception():
2847 if task_name.startswith(self.task_name_deploy_vca):
2848 # A N2VC task is pending
2849 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00002850 else:
tiernoe876f672020-02-13 14:34:48 +00002851 # RO or KDU task is pending
2852 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00002853
tiernoe876f672020-02-13 14:34:48 +00002854 # update status at database
2855 if error_list:
tiernoa2143262020-03-27 16:20:40 +00002856 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00002857 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01002858 error_description_nslcmop = "{} Detail: {}".format(
2859 stage[0], error_detail
2860 )
2861 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
2862 nslcmop_id, stage[0]
2863 )
quilesj3655ae02019-12-12 16:08:35 +00002864
garciadeblas5697b8b2021-03-24 09:17:02 +01002865 db_nsr_update["detailed-status"] = (
2866 error_description_nsr + " Detail: " + error_detail
2867 )
tiernoe876f672020-02-13 14:34:48 +00002868 db_nslcmop_update["detailed-status"] = error_detail
2869 nslcmop_operation_state = "FAILED"
2870 ns_state = "BROKEN"
2871 else:
tiernoa2143262020-03-27 16:20:40 +00002872 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00002873 error_description_nsr = error_description_nslcmop = None
2874 ns_state = "READY"
2875 db_nsr_update["detailed-status"] = "Done"
2876 db_nslcmop_update["detailed-status"] = "Done"
2877 nslcmop_operation_state = "COMPLETED"
quilesj4cda56b2019-12-05 10:02:20 +00002878
tiernoe876f672020-02-13 14:34:48 +00002879 if db_nsr:
2880 self._write_ns_status(
2881 nsr_id=nsr_id,
2882 ns_state=ns_state,
2883 current_operation="IDLE",
2884 current_operation_id=None,
2885 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00002886 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01002887 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002888 )
tiernoa17d4f42020-04-28 09:59:23 +00002889 self._write_op_status(
2890 op_id=nslcmop_id,
2891 stage="",
2892 error_message=error_description_nslcmop,
2893 operation_state=nslcmop_operation_state,
2894 other_update=db_nslcmop_update,
2895 )
quilesj3655ae02019-12-12 16:08:35 +00002896
tierno59d22d22018-09-25 18:10:19 +02002897 if nslcmop_operation_state:
2898 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002899 await self.msg.aiowrite(
2900 "ns",
2901 "instantiated",
2902 {
2903 "nsr_id": nsr_id,
2904 "nslcmop_id": nslcmop_id,
2905 "operationState": nslcmop_operation_state,
2906 },
2907 loop=self.loop,
2908 )
tierno59d22d22018-09-25 18:10:19 +02002909 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002910 self.logger.error(
2911 logging_text + "kafka_write notification Exception {}".format(e)
2912 )
tierno59d22d22018-09-25 18:10:19 +02002913
2914 self.logger.debug(logging_text + "Exit")
2915 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
2916
Gabriel Cuba09482b22022-09-19 21:39:21 -05002917 def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
David Garciab4ebcd02021-10-28 02:00:43 +02002918 if vnfd_id not in cached_vnfds:
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02002919 cached_vnfds[vnfd_id] = self.db.get_one(
2920 "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
2921 )
David Garciab4ebcd02021-10-28 02:00:43 +02002922 return cached_vnfds[vnfd_id]
2923
2924 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
2925 if vnf_profile_id not in cached_vnfrs:
2926 cached_vnfrs[vnf_profile_id] = self.db.get_one(
2927 "vnfrs",
2928 {
2929 "member-vnf-index-ref": vnf_profile_id,
2930 "nsr-id-ref": nsr_id,
2931 },
2932 )
2933 return cached_vnfrs[vnf_profile_id]
2934
2935 def _is_deployed_vca_in_relation(
2936 self, vca: DeployedVCA, relation: Relation
2937 ) -> bool:
2938 found = False
2939 for endpoint in (relation.provider, relation.requirer):
2940 if endpoint["kdu-resource-profile-id"]:
2941 continue
2942 found = (
2943 vca.vnf_profile_id == endpoint.vnf_profile_id
2944 and vca.vdu_profile_id == endpoint.vdu_profile_id
2945 and vca.execution_environment_ref == endpoint.execution_environment_ref
2946 )
2947 if found:
2948 break
2949 return found
2950
2951 def _update_ee_relation_data_with_implicit_data(
2952 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
2953 ):
2954 ee_relation_data = safe_get_ee_relation(
2955 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
2956 )
2957 ee_relation_level = EELevel.get_level(ee_relation_data)
2958 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
2959 "execution-environment-ref"
2960 ]:
2961 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
2962 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cuba09482b22022-09-19 21:39:21 -05002963 project = nsd["_admin"]["projects_read"][0]
2964 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02002965 entity_id = (
2966 vnfd_id
2967 if ee_relation_level == EELevel.VNF
2968 else ee_relation_data["vdu-profile-id"]
2969 )
2970 ee = get_juju_ee_ref(db_vnfd, entity_id)
2971 if not ee:
2972 raise Exception(
2973 f"not execution environments found for ee_relation {ee_relation_data}"
2974 )
2975 ee_relation_data["execution-environment-ref"] = ee["id"]
2976 return ee_relation_data
2977
2978 def _get_ns_relations(
2979 self,
2980 nsr_id: str,
2981 nsd: Dict[str, Any],
2982 vca: DeployedVCA,
2983 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01002984 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02002985 relations = []
2986 db_ns_relations = get_ns_configuration_relation_list(nsd)
2987 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01002988 provider_dict = None
2989 requirer_dict = None
2990 if all(key in r for key in ("provider", "requirer")):
2991 provider_dict = r["provider"]
2992 requirer_dict = r["requirer"]
2993 elif "entities" in r:
2994 provider_id = r["entities"][0]["id"]
2995 provider_dict = {
2996 "nsr-id": nsr_id,
2997 "endpoint": r["entities"][0]["endpoint"],
2998 }
2999 if provider_id != nsd["id"]:
3000 provider_dict["vnf-profile-id"] = provider_id
3001 requirer_id = r["entities"][1]["id"]
3002 requirer_dict = {
3003 "nsr-id": nsr_id,
3004 "endpoint": r["entities"][1]["endpoint"],
3005 }
3006 if requirer_id != nsd["id"]:
3007 requirer_dict["vnf-profile-id"] = requirer_id
3008 else:
aticig15db6142022-01-24 12:51:26 +03003009 raise Exception(
3010 "provider/requirer or entities must be included in the relation."
3011 )
David Garciab4ebcd02021-10-28 02:00:43 +02003012 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003013 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003014 )
3015 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003016 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003017 )
3018 provider = EERelation(relation_provider)
3019 requirer = EERelation(relation_requirer)
3020 relation = Relation(r["name"], provider, requirer)
3021 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3022 if vca_in_relation:
3023 relations.append(relation)
3024 return relations
3025
3026 def _get_vnf_relations(
3027 self,
3028 nsr_id: str,
3029 nsd: Dict[str, Any],
3030 vca: DeployedVCA,
3031 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003032 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003033 relations = []
3034 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3035 vnf_profile_id = vnf_profile["id"]
3036 vnfd_id = vnf_profile["vnfd-id"]
Gabriel Cuba09482b22022-09-19 21:39:21 -05003037 project = nsd["_admin"]["projects_read"][0]
3038 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003039 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3040 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003041 provider_dict = None
3042 requirer_dict = None
3043 if all(key in r for key in ("provider", "requirer")):
3044 provider_dict = r["provider"]
3045 requirer_dict = r["requirer"]
3046 elif "entities" in r:
3047 provider_id = r["entities"][0]["id"]
3048 provider_dict = {
3049 "nsr-id": nsr_id,
3050 "vnf-profile-id": vnf_profile_id,
3051 "endpoint": r["entities"][0]["endpoint"],
3052 }
3053 if provider_id != vnfd_id:
3054 provider_dict["vdu-profile-id"] = provider_id
3055 requirer_id = r["entities"][1]["id"]
3056 requirer_dict = {
3057 "nsr-id": nsr_id,
3058 "vnf-profile-id": vnf_profile_id,
3059 "endpoint": r["entities"][1]["endpoint"],
3060 }
3061 if requirer_id != vnfd_id:
3062 requirer_dict["vdu-profile-id"] = requirer_id
3063 else:
aticig15db6142022-01-24 12:51:26 +03003064 raise Exception(
3065 "provider/requirer or entities must be included in the relation."
3066 )
David Garciab4ebcd02021-10-28 02:00:43 +02003067 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003068 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003069 )
3070 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003071 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003072 )
3073 provider = EERelation(relation_provider)
3074 requirer = EERelation(relation_requirer)
3075 relation = Relation(r["name"], provider, requirer)
3076 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3077 if vca_in_relation:
3078 relations.append(relation)
3079 return relations
3080
3081 def _get_kdu_resource_data(
3082 self,
3083 ee_relation: EERelation,
3084 db_nsr: Dict[str, Any],
3085 cached_vnfds: Dict[str, Any],
3086 ) -> DeployedK8sResource:
3087 nsd = get_nsd(db_nsr)
3088 vnf_profiles = get_vnf_profiles(nsd)
3089 vnfd_id = find_in_list(
3090 vnf_profiles,
3091 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3092 )["vnfd-id"]
Gabriel Cuba09482b22022-09-19 21:39:21 -05003093 project = nsd["_admin"]["projects_read"][0]
3094 db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
David Garciab4ebcd02021-10-28 02:00:43 +02003095 kdu_resource_profile = get_kdu_resource_profile(
3096 db_vnfd, ee_relation.kdu_resource_profile_id
3097 )
3098 kdu_name = kdu_resource_profile["kdu-name"]
3099 deployed_kdu, _ = get_deployed_kdu(
3100 db_nsr.get("_admin", ()).get("deployed", ()),
3101 kdu_name,
3102 ee_relation.vnf_profile_id,
3103 )
3104 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3105 return deployed_kdu
3106
3107 def _get_deployed_component(
3108 self,
3109 ee_relation: EERelation,
3110 db_nsr: Dict[str, Any],
3111 cached_vnfds: Dict[str, Any],
3112 ) -> DeployedComponent:
3113 nsr_id = db_nsr["_id"]
3114 deployed_component = None
3115 ee_level = EELevel.get_level(ee_relation)
3116 if ee_level == EELevel.NS:
3117 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3118 if vca:
3119 deployed_component = DeployedVCA(nsr_id, vca)
3120 elif ee_level == EELevel.VNF:
3121 vca = get_deployed_vca(
3122 db_nsr,
3123 {
3124 "vdu_id": None,
3125 "member-vnf-index": ee_relation.vnf_profile_id,
3126 "ee_descriptor_id": ee_relation.execution_environment_ref,
3127 },
3128 )
3129 if vca:
3130 deployed_component = DeployedVCA(nsr_id, vca)
3131 elif ee_level == EELevel.VDU:
3132 vca = get_deployed_vca(
3133 db_nsr,
3134 {
3135 "vdu_id": ee_relation.vdu_profile_id,
3136 "member-vnf-index": ee_relation.vnf_profile_id,
3137 "ee_descriptor_id": ee_relation.execution_environment_ref,
3138 },
3139 )
3140 if vca:
3141 deployed_component = DeployedVCA(nsr_id, vca)
3142 elif ee_level == EELevel.KDU:
3143 kdu_resource_data = self._get_kdu_resource_data(
3144 ee_relation, db_nsr, cached_vnfds
3145 )
3146 if kdu_resource_data:
3147 deployed_component = DeployedK8sResource(kdu_resource_data)
3148 return deployed_component
3149
3150 async def _add_relation(
3151 self,
3152 relation: Relation,
3153 vca_type: str,
3154 db_nsr: Dict[str, Any],
3155 cached_vnfds: Dict[str, Any],
3156 cached_vnfrs: Dict[str, Any],
3157 ) -> bool:
3158 deployed_provider = self._get_deployed_component(
3159 relation.provider, db_nsr, cached_vnfds
3160 )
3161 deployed_requirer = self._get_deployed_component(
3162 relation.requirer, db_nsr, cached_vnfds
3163 )
3164 if (
3165 deployed_provider
3166 and deployed_requirer
3167 and deployed_provider.config_sw_installed
3168 and deployed_requirer.config_sw_installed
3169 ):
3170 provider_db_vnfr = (
3171 self._get_vnfr(
3172 relation.provider.nsr_id,
3173 relation.provider.vnf_profile_id,
3174 cached_vnfrs,
3175 )
3176 if relation.provider.vnf_profile_id
3177 else None
3178 )
3179 requirer_db_vnfr = (
3180 self._get_vnfr(
3181 relation.requirer.nsr_id,
3182 relation.requirer.vnf_profile_id,
3183 cached_vnfrs,
3184 )
3185 if relation.requirer.vnf_profile_id
3186 else None
3187 )
3188 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3189 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3190 provider_relation_endpoint = RelationEndpoint(
3191 deployed_provider.ee_id,
3192 provider_vca_id,
3193 relation.provider.endpoint,
3194 )
3195 requirer_relation_endpoint = RelationEndpoint(
3196 deployed_requirer.ee_id,
3197 requirer_vca_id,
3198 relation.requirer.endpoint,
3199 )
3200 await self.vca_map[vca_type].add_relation(
3201 provider=provider_relation_endpoint,
3202 requirer=requirer_relation_endpoint,
3203 )
3204 # remove entry from relations list
3205 return True
3206 return False
3207
David Garciac1fe90a2021-03-31 19:12:02 +02003208 async def _add_vca_relations(
3209 self,
3210 logging_text,
3211 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003212 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003213 vca_index: int,
3214 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003215 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003216 # steps:
3217 # 1. find all relations for this VCA
3218 # 2. wait for other peers related
3219 # 3. add relations
3220
3221 try:
quilesj63f90042020-01-17 09:53:55 +00003222 # STEP 1: find all relations for this VCA
3223
3224 # read nsr record
3225 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003226 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003227
3228 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003229 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3230 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003231
David Garciab4ebcd02021-10-28 02:00:43 +02003232 cached_vnfds = {}
3233 cached_vnfrs = {}
3234 relations = []
3235 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3236 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003237
3238 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003239 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003240 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003241 return True
3242
David Garciab4ebcd02021-10-28 02:00:43 +02003243 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003244
3245 # add all relations
3246 start = time()
3247 while True:
3248 # check timeout
3249 now = time()
3250 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003251 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003252 return False
3253
David Garciab4ebcd02021-10-28 02:00:43 +02003254 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003255 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3256
David Garciab4ebcd02021-10-28 02:00:43 +02003257 # for each relation, find the VCA's related
3258 for relation in relations.copy():
3259 added = await self._add_relation(
3260 relation,
3261 vca_type,
3262 db_nsr,
3263 cached_vnfds,
3264 cached_vnfrs,
3265 )
3266 if added:
3267 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003268
David Garciab4ebcd02021-10-28 02:00:43 +02003269 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003270 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003271 break
David Garciab4ebcd02021-10-28 02:00:43 +02003272 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003273
3274 return True
3275
3276 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003277 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003278 return False
3279
garciadeblas5697b8b2021-03-24 09:17:02 +01003280 async def _install_kdu(
3281 self,
3282 nsr_id: str,
3283 nsr_db_path: str,
3284 vnfr_data: dict,
3285 kdu_index: int,
3286 kdud: dict,
3287 vnfd: dict,
3288 k8s_instance_info: dict,
3289 k8params: dict = None,
3290 timeout: int = 600,
3291 vca_id: str = None,
3292 ):
tiernob9018152020-04-16 14:18:24 +00003293 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003294 k8sclustertype = k8s_instance_info["k8scluster-type"]
3295 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003296 db_dict_install = {
3297 "collection": "nsrs",
3298 "filter": {"_id": nsr_id},
3299 "path": nsr_db_path,
3300 }
lloretgalleg7c121132020-07-08 07:53:22 +00003301
romeromonser4554a702021-05-28 12:00:08 +02003302 if k8s_instance_info.get("kdu-deployment-name"):
3303 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3304 else:
3305 kdu_instance = self.k8scluster_map[
3306 k8sclustertype
3307 ].generate_kdu_instance_name(
3308 db_dict=db_dict_install,
3309 kdu_model=k8s_instance_info["kdu-model"],
3310 kdu_name=k8s_instance_info["kdu-name"],
3311 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003312
3313 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003314 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003315 item="nsrs",
3316 _id=nsr_id,
3317 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003318 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003319
3320 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3321 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3322 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3323 # namespace, this first verification could be removed, and the next step would be done for any kind
3324 # of KNF.
3325 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3326 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3327 if k8sclustertype in ("juju", "juju-bundle"):
3328 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3329 # that the user passed a namespace which he wants its KDU to be deployed in)
3330 if (
3331 self.db.count(
3332 table="nsrs",
3333 q_filter={
3334 "_id": nsr_id,
3335 "_admin.projects_write": k8s_instance_info["namespace"],
3336 "_admin.projects_read": k8s_instance_info["namespace"],
3337 },
3338 )
3339 > 0
3340 ):
3341 self.logger.debug(
3342 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3343 )
3344 self.update_db_2(
3345 item="nsrs",
3346 _id=nsr_id,
3347 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3348 )
3349 k8s_instance_info["namespace"] = kdu_instance
3350
David Garciad64e2742021-02-25 20:19:18 +01003351 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003352 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3353 kdu_model=k8s_instance_info["kdu-model"],
3354 atomic=True,
3355 params=k8params,
3356 db_dict=db_dict_install,
3357 timeout=timeout,
3358 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003359 namespace=k8s_instance_info["namespace"],
3360 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003361 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003362 )
lloretgalleg7c121132020-07-08 07:53:22 +00003363
3364 # Obtain services to obtain management service ip
3365 services = await self.k8scluster_map[k8sclustertype].get_services(
3366 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3367 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003368 namespace=k8s_instance_info["namespace"],
3369 )
lloretgalleg7c121132020-07-08 07:53:22 +00003370
3371 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003372 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003373 kdu_config = get_configuration(vnfd, kdud["name"])
3374 if kdu_config:
3375 target_ee_list = kdu_config.get("execution-environment-list", [])
3376 else:
3377 target_ee_list = []
3378
lloretgalleg7c121132020-07-08 07:53:22 +00003379 if services:
tierno7ecbc342020-09-21 14:05:39 +00003380 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003381 mgmt_services = [
3382 service
3383 for service in kdud.get("service", [])
3384 if service.get("mgmt-service")
3385 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003386 for mgmt_service in mgmt_services:
3387 for service in services:
3388 if service["name"].startswith(mgmt_service["name"]):
3389 # Mgmt service found, Obtain service ip
3390 ip = service.get("external_ip", service.get("cluster_ip"))
3391 if isinstance(ip, list) and len(ip) == 1:
3392 ip = ip[0]
3393
garciadeblas5697b8b2021-03-24 09:17:02 +01003394 vnfr_update_dict[
3395 "kdur.{}.ip-address".format(kdu_index)
3396 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003397
3398 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003399 service_external_cp = mgmt_service.get(
3400 "external-connection-point-ref"
3401 )
lloretgalleg7c121132020-07-08 07:53:22 +00003402 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003403 if (
3404 deep_get(vnfd, ("mgmt-interface", "cp"))
3405 == service_external_cp
3406 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003407 vnfr_update_dict["ip-address"] = ip
3408
bravof6ec62b72021-02-25 17:20:35 -03003409 if find_in_list(
3410 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003411 lambda ee: ee.get(
3412 "external-connection-point-ref", ""
3413 )
3414 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003415 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003416 vnfr_update_dict[
3417 "kdur.{}.ip-address".format(kdu_index)
3418 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003419 break
3420 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003421 self.logger.warn(
3422 "Mgmt service name: {} not found".format(
3423 mgmt_service["name"]
3424 )
3425 )
lloretgalleg7c121132020-07-08 07:53:22 +00003426
tierno7ecbc342020-09-21 14:05:39 +00003427 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3428 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003429
bravof9a256db2021-02-22 18:02:07 -03003430 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003431 if (
3432 kdu_config
3433 and kdu_config.get("initial-config-primitive")
3434 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3435 ):
3436 initial_config_primitive_list = kdu_config.get(
3437 "initial-config-primitive"
3438 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003439 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3440
3441 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003442 primitive_params_ = self._map_primitive_params(
3443 initial_config_primitive, {}, {}
3444 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003445
3446 await asyncio.wait_for(
3447 self.k8scluster_map[k8sclustertype].exec_primitive(
3448 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3449 kdu_instance=kdu_instance,
3450 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003451 params=primitive_params_,
3452 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003453 vca_id=vca_id,
3454 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003455 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003456 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003457
tiernob9018152020-04-16 14:18:24 +00003458 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003459 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003460 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003461 self.update_db_2(
3462 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3463 )
3464 self.update_db_2(
3465 "vnfrs",
3466 vnfr_data.get("_id"),
3467 {"kdur.{}.status".format(kdu_index): "ERROR"},
3468 )
tiernob9018152020-04-16 14:18:24 +00003469 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00003470 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00003471 pass
lloretgalleg7c121132020-07-08 07:53:22 +00003472 # reraise original error
3473 raise
3474
3475 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003476
garciadeblas5697b8b2021-03-24 09:17:02 +01003477 async def deploy_kdus(
3478 self,
3479 logging_text,
3480 nsr_id,
3481 nslcmop_id,
3482 db_vnfrs,
3483 db_vnfds,
3484 task_instantiation_info,
3485 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003486 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003487
garciadeblas5697b8b2021-03-24 09:17:02 +01003488 k8scluster_id_2_uuic = {
3489 "helm-chart-v3": {},
3490 "helm-chart": {},
3491 "juju-bundle": {},
3492 }
tierno626e0152019-11-29 14:16:16 +00003493
tierno16f4a4e2020-07-20 09:05:51 +00003494 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003495 nonlocal k8scluster_id_2_uuic
3496 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3497 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3498
tierno16f4a4e2020-07-20 09:05:51 +00003499 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003500 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3501 "k8scluster", cluster_id
3502 )
tierno16f4a4e2020-07-20 09:05:51 +00003503 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003504 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3505 task_name, cluster_id
3506 )
tierno16f4a4e2020-07-20 09:05:51 +00003507 self.logger.debug(logging_text + text)
3508 await asyncio.wait(task_dependency, timeout=3600)
3509
garciadeblas5697b8b2021-03-24 09:17:02 +01003510 db_k8scluster = self.db.get_one(
3511 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3512 )
tierno626e0152019-11-29 14:16:16 +00003513 if not db_k8scluster:
3514 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003515
tierno626e0152019-11-29 14:16:16 +00003516 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3517 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003518 if cluster_type == "helm-chart-v3":
3519 try:
3520 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003521 k8s_credentials = yaml.safe_dump(
3522 db_k8scluster.get("credentials")
3523 )
3524 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3525 k8s_credentials, reuse_cluster_uuid=cluster_id
3526 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003527 db_k8scluster_update = {}
3528 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3529 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003530 db_k8scluster_update[
3531 "_admin.helm-chart-v3.created"
3532 ] = uninstall_sw
3533 db_k8scluster_update[
3534 "_admin.helm-chart-v3.operationalState"
3535 ] = "ENABLED"
3536 self.update_db_2(
3537 "k8sclusters", cluster_id, db_k8scluster_update
3538 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003539 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003540 self.logger.error(
3541 logging_text
3542 + "error initializing helm-v3 cluster: {}".format(str(e))
3543 )
3544 raise LcmException(
3545 "K8s cluster '{}' has not been initialized for '{}'".format(
3546 cluster_id, cluster_type
3547 )
3548 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003549 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003550 raise LcmException(
3551 "K8s cluster '{}' has not been initialized for '{}'".format(
3552 cluster_id, cluster_type
3553 )
3554 )
tierno626e0152019-11-29 14:16:16 +00003555 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3556 return k8s_id
3557
3558 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003559 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003560 try:
tierno626e0152019-11-29 14:16:16 +00003561 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003562 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003563
tierno626e0152019-11-29 14:16:16 +00003564 index = 0
tiernoe876f672020-02-13 14:34:48 +00003565 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003566 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003567
tierno626e0152019-11-29 14:16:16 +00003568 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003569 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003570 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3571 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003572 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003573 vnfd_id = vnfr_data.get("vnfd-id")
3574 vnfd_with_id = find_in_list(
3575 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3576 )
3577 kdud = next(
3578 kdud
3579 for kdud in vnfd_with_id["kdu"]
3580 if kdud["name"] == kdur["kdu-name"]
3581 )
tiernode1584f2020-04-07 09:07:33 +00003582 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003583 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003584 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003585 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003586 # Default version: helm3, if helm-version is v2 assign v2
3587 k8sclustertype = "helm-chart-v3"
3588 self.logger.debug("kdur: {}".format(kdur))
garciadeblas5697b8b2021-03-24 09:17:02 +01003589 if (
3590 kdur.get("helm-version")
3591 and kdur.get("helm-version") == "v2"
3592 ):
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003593 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00003594 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003595 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003596 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003597 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003598 raise LcmException(
3599 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3600 "juju-bundle. Maybe an old NBI version is running".format(
3601 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3602 )
3603 )
quilesjacde94f2020-01-23 10:07:08 +00003604 # check if kdumodel is a file and exists
3605 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003606 vnfd_with_id = find_in_list(
3607 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3608 )
3609 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003610 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003611 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003612 if storage["pkg-dir"]:
3613 filename = "{}/{}/{}s/{}".format(
3614 storage["folder"],
3615 storage["pkg-dir"],
3616 k8sclustertype,
3617 kdumodel,
3618 )
3619 else:
3620 filename = "{}/Scripts/{}s/{}".format(
3621 storage["folder"],
3622 k8sclustertype,
3623 kdumodel,
3624 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003625 if self.fs.file_exists(
3626 filename, mode="file"
3627 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003628 kdumodel = self.fs.path + filename
3629 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003630 raise
garciadeblas5697b8b2021-03-24 09:17:02 +01003631 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00003632 pass
lloretgallegedc5f332020-02-20 11:50:50 +01003633
tiernoe876f672020-02-13 14:34:48 +00003634 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003635 step = "Synchronize repos for k8s cluster '{}'".format(
3636 k8s_cluster_id
3637 )
tierno16f4a4e2020-07-20 09:05:51 +00003638 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003639
lloretgalleg7c121132020-07-08 07:53:22 +00003640 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003641 if (
3642 k8sclustertype == "helm-chart"
3643 and cluster_uuid not in updated_cluster_list
3644 ) or (
3645 k8sclustertype == "helm-chart-v3"
3646 and cluster_uuid not in updated_v3_cluster_list
3647 ):
tiernoe876f672020-02-13 14:34:48 +00003648 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003649 self.k8scluster_map[k8sclustertype].synchronize_repos(
3650 cluster_uuid=cluster_uuid
3651 )
3652 )
tiernoe876f672020-02-13 14:34:48 +00003653 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003654 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003655 unset = {
3656 "_admin.helm_charts_added." + item: None
3657 for item in del_repo_list
3658 }
3659 updated = {
3660 "_admin.helm_charts_added." + item: name
3661 for item, name in added_repo_dict.items()
3662 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003663 updated_cluster_list.append(cluster_uuid)
3664 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003665 unset = {
3666 "_admin.helm_charts_v3_added." + item: None
3667 for item in del_repo_list
3668 }
3669 updated = {
3670 "_admin.helm_charts_v3_added." + item: name
3671 for item, name in added_repo_dict.items()
3672 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003673 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003674 self.logger.debug(
3675 logging_text + "repos synchronized on k8s cluster "
3676 "'{}' to_delete: {}, to_add: {}".format(
3677 k8s_cluster_id, del_repo_list, added_repo_dict
3678 )
3679 )
3680 self.db.set_one(
3681 "k8sclusters",
3682 {"_id": k8s_cluster_id},
3683 updated,
3684 unset=unset,
3685 )
lloretgallegedc5f332020-02-20 11:50:50 +01003686
lloretgalleg7c121132020-07-08 07:53:22 +00003687 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003688 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3689 vnfr_data["member-vnf-index-ref"],
3690 kdur["kdu-name"],
3691 k8s_cluster_id,
3692 )
3693 k8s_instance_info = {
3694 "kdu-instance": None,
3695 "k8scluster-uuid": cluster_uuid,
3696 "k8scluster-type": k8sclustertype,
3697 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3698 "kdu-name": kdur["kdu-name"],
3699 "kdu-model": kdumodel,
3700 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003701 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003702 }
tiernob9018152020-04-16 14:18:24 +00003703 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003704 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003705 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003706 vnfd_with_id = find_in_list(
3707 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3708 )
tiernoa2143262020-03-27 16:20:40 +00003709 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003710 self._install_kdu(
3711 nsr_id,
3712 db_path,
3713 vnfr_data,
3714 kdu_index,
3715 kdud,
3716 vnfd_with_id,
3717 k8s_instance_info,
3718 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003719 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003720 vca_id=vca_id,
3721 )
3722 )
3723 self.lcm_tasks.register(
3724 "ns",
3725 nsr_id,
3726 nslcmop_id,
3727 "instantiate_KDU-{}".format(index),
3728 task,
3729 )
3730 task_instantiation_info[task] = "Deploying KDU {}".format(
3731 kdur["kdu-name"]
3732 )
tiernoe876f672020-02-13 14:34:48 +00003733
tierno626e0152019-11-29 14:16:16 +00003734 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003735
tiernoe876f672020-02-13 14:34:48 +00003736 except (LcmException, asyncio.CancelledError):
3737 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003738 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003739 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3740 if isinstance(e, (N2VCException, DbException)):
3741 self.logger.error(logging_text + msg)
3742 else:
3743 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003744 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003745 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003746 if db_nsr_update:
3747 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003748
garciadeblas5697b8b2021-03-24 09:17:02 +01003749 def _deploy_n2vc(
3750 self,
3751 logging_text,
3752 db_nsr,
3753 db_vnfr,
3754 nslcmop_id,
3755 nsr_id,
3756 nsi_id,
3757 vnfd_id,
3758 vdu_id,
3759 kdu_name,
3760 member_vnf_index,
3761 vdu_index,
3762 vdu_name,
3763 deploy_params,
3764 descriptor_config,
3765 base_folder,
3766 task_instantiation_info,
3767 stage,
3768 ):
quilesj7e13aeb2019-10-08 13:34:55 +02003769 # launch instantiate_N2VC in a asyncio task and register task object
3770 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
3771 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02003772 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00003773
garciadeblas5697b8b2021-03-24 09:17:02 +01003774 self.logger.debug(
3775 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
3776 )
bravof9a256db2021-02-22 18:02:07 -03003777 if "execution-environment-list" in descriptor_config:
3778 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02003779 elif "juju" in descriptor_config:
3780 ee_list = [descriptor_config] # ns charms
tierno588547c2020-07-01 15:30:20 +00003781 else: # other types as script are not supported
3782 ee_list = []
3783
3784 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003785 self.logger.debug(
3786 logging_text
3787 + "_deploy_n2vc ee_item juju={}, helm={}".format(
3788 ee_item.get("juju"), ee_item.get("helm-chart")
3789 )
3790 )
tiernoa278b842020-07-08 15:33:55 +00003791 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00003792 if ee_item.get("juju"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003793 vca_name = ee_item["juju"].get("charm")
3794 vca_type = (
3795 "lxc_proxy_charm"
3796 if ee_item["juju"].get("charm") is not None
3797 else "native_charm"
3798 )
3799 if ee_item["juju"].get("cloud") == "k8s":
tierno588547c2020-07-01 15:30:20 +00003800 vca_type = "k8s_proxy_charm"
garciadeblas5697b8b2021-03-24 09:17:02 +01003801 elif ee_item["juju"].get("proxy") is False:
tierno588547c2020-07-01 15:30:20 +00003802 vca_type = "native_charm"
3803 elif ee_item.get("helm-chart"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003804 vca_name = ee_item["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003805 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
3806 vca_type = "helm"
3807 else:
3808 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00003809 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003810 self.logger.debug(
3811 logging_text + "skipping non juju neither charm configuration"
3812 )
quilesj7e13aeb2019-10-08 13:34:55 +02003813 continue
quilesj3655ae02019-12-12 16:08:35 +00003814
tierno588547c2020-07-01 15:30:20 +00003815 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01003816 for vca_index, vca_deployed in enumerate(
3817 db_nsr["_admin"]["deployed"]["VCA"]
3818 ):
tierno588547c2020-07-01 15:30:20 +00003819 if not vca_deployed:
3820 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01003821 if (
3822 vca_deployed.get("member-vnf-index") == member_vnf_index
3823 and vca_deployed.get("vdu_id") == vdu_id
3824 and vca_deployed.get("kdu_name") == kdu_name
3825 and vca_deployed.get("vdu_count_index", 0) == vdu_index
3826 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
3827 ):
tierno588547c2020-07-01 15:30:20 +00003828 break
3829 else:
3830 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01003831 target = (
3832 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
3833 )
tiernoa278b842020-07-08 15:33:55 +00003834 if vdu_id:
3835 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
3836 elif kdu_name:
3837 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00003838 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00003839 "target_element": target,
3840 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00003841 "member-vnf-index": member_vnf_index,
3842 "vdu_id": vdu_id,
3843 "kdu_name": kdu_name,
3844 "vdu_count_index": vdu_index,
3845 "operational-status": "init", # TODO revise
3846 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01003847 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00003848 "vnfd_id": vnfd_id,
3849 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00003850 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01003851 "ee_descriptor_id": ee_descriptor_id,
tierno588547c2020-07-01 15:30:20 +00003852 }
3853 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00003854
tierno588547c2020-07-01 15:30:20 +00003855 # create VCA and configurationStatus in db
3856 db_dict = {
3857 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01003858 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00003859 }
3860 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02003861
tierno588547c2020-07-01 15:30:20 +00003862 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
3863
bravof922c4172020-11-24 21:21:43 -03003864 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
3865 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
3866 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
3867
tierno588547c2020-07-01 15:30:20 +00003868 # Launch task
3869 task_n2vc = asyncio.ensure_future(
3870 self.instantiate_N2VC(
3871 logging_text=logging_text,
3872 vca_index=vca_index,
3873 nsi_id=nsi_id,
3874 db_nsr=db_nsr,
3875 db_vnfr=db_vnfr,
3876 vdu_id=vdu_id,
3877 kdu_name=kdu_name,
3878 vdu_index=vdu_index,
3879 deploy_params=deploy_params,
3880 config_descriptor=descriptor_config,
3881 base_folder=base_folder,
3882 nslcmop_id=nslcmop_id,
3883 stage=stage,
3884 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00003885 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003886 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00003887 )
quilesj7e13aeb2019-10-08 13:34:55 +02003888 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003889 self.lcm_tasks.register(
3890 "ns",
3891 nsr_id,
3892 nslcmop_id,
3893 "instantiate_N2VC-{}".format(vca_index),
3894 task_n2vc,
3895 )
3896 task_instantiation_info[
3897 task_n2vc
3898 ] = self.task_name_deploy_vca + " {}.{}".format(
3899 member_vnf_index or "", vdu_id or ""
3900 )
tiernobaa51102018-12-14 13:16:18 +00003901
tiernoc9556972019-07-05 15:25:25 +00003902 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02003903 def _create_nslcmop(nsr_id, operation, params):
3904 """
3905 Creates a ns-lcm-opp content to be stored at database.
3906 :param nsr_id: internal id of the instance
3907 :param operation: instantiate, terminate, scale, action, ...
3908 :param params: user parameters for the operation
3909 :return: dictionary following SOL005 format
3910 """
3911 # Raise exception if invalid arguments
3912 if not (nsr_id and operation and params):
3913 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01003914 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided"
3915 )
kuuse0ca67472019-05-13 15:59:27 +02003916 now = time()
3917 _id = str(uuid4())
3918 nslcmop = {
3919 "id": _id,
3920 "_id": _id,
3921 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
3922 "operationState": "PROCESSING",
3923 "statusEnteredTime": now,
3924 "nsInstanceId": nsr_id,
3925 "lcmOperationType": operation,
3926 "startTime": now,
3927 "isAutomaticInvocation": False,
3928 "operationParams": params,
3929 "isCancelPending": False,
3930 "links": {
3931 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
3932 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01003933 },
kuuse0ca67472019-05-13 15:59:27 +02003934 }
3935 return nslcmop
3936
calvinosanch9f9c6f22019-11-04 13:37:39 +01003937 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00003938 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003939 for key, value in params.items():
3940 if str(value).startswith("!!yaml "):
3941 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01003942 return params
3943
kuuse8b998e42019-07-30 15:22:16 +02003944 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01003945 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02003946 primitive_params = {}
3947 params = {
3948 "member_vnf_index": vnf_index,
3949 "primitive": primitive,
3950 "primitive_params": primitive_params,
3951 }
3952 desc_params = {}
3953 return self._map_primitive_params(seq, params, desc_params)
3954
kuuseac3a8882019-10-03 10:48:06 +02003955 # sub-operations
3956
tierno51183952020-04-03 15:48:18 +00003957 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01003958 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
3959 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02003960 # b. Skip sub-operation
3961 # _ns_execute_primitive() or RO.create_action() will NOT be executed
3962 return self.SUBOPERATION_STATUS_SKIP
3963 else:
tierno7c4e24c2020-05-13 08:41:35 +00003964 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003965 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00003966 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01003967 operationState = "PROCESSING"
3968 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02003969 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01003970 db_nslcmop, op_index, operationState, detailed_status
3971 )
kuuseac3a8882019-10-03 10:48:06 +02003972 # Return the sub-operation index
3973 # _ns_execute_primitive() or RO.create_action() will be called from scale()
3974 # with arguments extracted from the sub-operation
3975 return op_index
3976
3977 # Find a sub-operation where all keys in a matching dictionary must match
3978 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
3979 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00003980 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01003981 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02003982 for i, op in enumerate(op_list):
3983 if all(op.get(k) == match[k] for k in match):
3984 return i
3985 return self.SUBOPERATION_STATUS_NOT_FOUND
3986
3987 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01003988 def _update_suboperation_status(
3989 self, db_nslcmop, op_index, operationState, detailed_status
3990 ):
kuuseac3a8882019-10-03 10:48:06 +02003991 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01003992 q_filter = {"_id": db_nslcmop["_id"]}
3993 update_dict = {
3994 "_admin.operations.{}.operationState".format(op_index): operationState,
3995 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
3996 }
3997 self.db.set_one(
3998 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
3999 )
kuuseac3a8882019-10-03 10:48:06 +02004000
4001 # Add sub-operation, return the index of the added sub-operation
4002 # Optionally, set operationState, detailed-status, and operationType
4003 # Status and type are currently set for 'scale' sub-operations:
4004 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4005 # 'detailed-status' : status message
4006 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4007 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004008 def _add_suboperation(
4009 self,
4010 db_nslcmop,
4011 vnf_index,
4012 vdu_id,
4013 vdu_count_index,
4014 vdu_name,
4015 primitive,
4016 mapped_primitive_params,
4017 operationState=None,
4018 detailed_status=None,
4019 operationType=None,
4020 RO_nsr_id=None,
4021 RO_scaling_info=None,
4022 ):
tiernoe876f672020-02-13 14:34:48 +00004023 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004024 return self.SUBOPERATION_STATUS_NOT_FOUND
4025 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004026 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4027 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004028 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004029 new_op = {
4030 "member_vnf_index": vnf_index,
4031 "vdu_id": vdu_id,
4032 "vdu_count_index": vdu_count_index,
4033 "primitive": primitive,
4034 "primitive_params": mapped_primitive_params,
4035 }
kuuseac3a8882019-10-03 10:48:06 +02004036 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004037 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004038 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004039 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004040 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004041 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004042 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004043 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004044 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004045 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004046 if not op_list:
4047 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004048 db_nslcmop_admin.update({"operations": [new_op]})
4049 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004050 else:
4051 # Existing operations, append operation to list
4052 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004053
garciadeblas5697b8b2021-03-24 09:17:02 +01004054 db_nslcmop_update = {"_admin.operations": op_list}
4055 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004056 op_index = len(op_list) - 1
4057 return op_index
4058
4059 # Helper methods for scale() sub-operations
4060
4061 # pre-scale/post-scale:
4062 # Check for 3 different cases:
4063 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4064 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004065 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004066 def _check_or_add_scale_suboperation(
4067 self,
4068 db_nslcmop,
4069 vnf_index,
4070 vnf_config_primitive,
4071 primitive_params,
4072 operationType,
4073 RO_nsr_id=None,
4074 RO_scaling_info=None,
4075 ):
kuuseac3a8882019-10-03 10:48:06 +02004076 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004077 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004078 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004079 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004080 "member_vnf_index": vnf_index,
4081 "RO_nsr_id": RO_nsr_id,
4082 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004083 }
4084 else:
4085 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004086 "member_vnf_index": vnf_index,
4087 "primitive": vnf_config_primitive,
4088 "primitive_params": primitive_params,
4089 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004090 }
4091 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004092 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004093 # a. New sub-operation
4094 # The sub-operation does not exist, add it.
4095 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4096 # The following parameters are set to None for all kind of scaling:
4097 vdu_id = None
4098 vdu_count_index = None
4099 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004100 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004101 vnf_config_primitive = None
4102 primitive_params = None
4103 else:
4104 RO_nsr_id = None
4105 RO_scaling_info = None
4106 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004107 operationState = "PROCESSING"
4108 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004109 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004110 self._add_suboperation(
4111 db_nslcmop,
4112 vnf_index,
4113 vdu_id,
4114 vdu_count_index,
4115 vdu_name,
4116 vnf_config_primitive,
4117 primitive_params,
4118 operationState,
4119 detailed_status,
4120 operationType,
4121 RO_nsr_id,
4122 RO_scaling_info,
4123 )
kuuseac3a8882019-10-03 10:48:06 +02004124 return self.SUBOPERATION_STATUS_NEW
4125 else:
4126 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4127 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004128 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004129
preethika.pdf7d8e02019-12-10 13:10:48 +00004130 # Function to return execution_environment id
4131
4132 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00004133 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00004134 for vca in vca_deployed_list:
4135 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
4136 return vca["ee_id"]
4137
David Garciac1fe90a2021-03-31 19:12:02 +02004138 async def destroy_N2VC(
4139 self,
4140 logging_text,
4141 db_nslcmop,
4142 vca_deployed,
4143 config_descriptor,
4144 vca_index,
4145 destroy_ee=True,
4146 exec_primitives=True,
4147 scaling_in=False,
4148 vca_id: str = None,
4149 ):
tiernoe876f672020-02-13 14:34:48 +00004150 """
4151 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4152 :param logging_text:
4153 :param db_nslcmop:
4154 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4155 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4156 :param vca_index: index in the database _admin.deployed.VCA
4157 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004158 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4159 not executed properly
aktas13251562021-02-12 22:19:10 +03004160 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004161 :return: None or exception
4162 """
tiernoe876f672020-02-13 14:34:48 +00004163
tierno588547c2020-07-01 15:30:20 +00004164 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004165 logging_text
4166 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004167 vca_index, vca_deployed, config_descriptor, destroy_ee
4168 )
4169 )
4170
4171 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4172
4173 # execute terminate_primitives
4174 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004175 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004176 config_descriptor.get("terminate-config-primitive"),
4177 vca_deployed.get("ee_descriptor_id"),
4178 )
tierno588547c2020-07-01 15:30:20 +00004179 vdu_id = vca_deployed.get("vdu_id")
4180 vdu_count_index = vca_deployed.get("vdu_count_index")
4181 vdu_name = vca_deployed.get("vdu_name")
4182 vnf_index = vca_deployed.get("member-vnf-index")
4183 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004184 for seq in terminate_primitives:
4185 # For each sequence in list, get primitive and call _ns_execute_primitive()
4186 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004187 vnf_index, seq.get("name")
4188 )
tierno588547c2020-07-01 15:30:20 +00004189 self.logger.debug(logging_text + step)
4190 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004191 primitive = seq.get("name")
4192 mapped_primitive_params = self._get_terminate_primitive_params(
4193 seq, vnf_index
4194 )
tierno588547c2020-07-01 15:30:20 +00004195
4196 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004197 self._add_suboperation(
4198 db_nslcmop,
4199 vnf_index,
4200 vdu_id,
4201 vdu_count_index,
4202 vdu_name,
4203 primitive,
4204 mapped_primitive_params,
4205 )
tierno588547c2020-07-01 15:30:20 +00004206 # Sub-operations: Call _ns_execute_primitive() instead of action()
4207 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004208 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004209 vca_deployed["ee_id"],
4210 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004211 mapped_primitive_params,
4212 vca_type=vca_type,
4213 vca_id=vca_id,
4214 )
tierno588547c2020-07-01 15:30:20 +00004215 except LcmException:
4216 # this happens when VCA is not deployed. In this case it is not needed to terminate
4217 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004218 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004219 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004220 raise LcmException(
4221 "terminate_primitive {} for vnf_member_index={} fails with "
4222 "error {}".format(seq.get("name"), vnf_index, result_detail)
4223 )
tierno588547c2020-07-01 15:30:20 +00004224 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004225 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4226 vca_index
4227 )
4228 self.update_db_2(
4229 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4230 )
tiernoe876f672020-02-13 14:34:48 +00004231
bravof73bac502021-05-11 07:38:47 -04004232 # Delete Prometheus Jobs if any
4233 # This uses NSR_ID, so it will destroy any jobs under this index
4234 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004235
tiernoe876f672020-02-13 14:34:48 +00004236 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004237 await self.vca_map[vca_type].delete_execution_environment(
4238 vca_deployed["ee_id"],
4239 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004240 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004241 vca_id=vca_id,
4242 )
kuuse0ca67472019-05-13 15:59:27 +02004243
David Garciac1fe90a2021-03-31 19:12:02 +02004244 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004245 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004246 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004247 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004248 await self.n2vc.delete_namespace(
4249 namespace=namespace,
4250 total_timeout=self.timeout_charm_delete,
4251 vca_id=vca_id,
4252 )
tiernof59ad6c2020-04-08 12:50:52 +00004253 except N2VCNotFound: # already deleted. Skip
4254 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004255 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004256
garciadeblas5697b8b2021-03-24 09:17:02 +01004257 async def _terminate_RO(
4258 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4259 ):
tiernoe876f672020-02-13 14:34:48 +00004260 """
4261 Terminates a deployment from RO
4262 :param logging_text:
4263 :param nsr_deployed: db_nsr._admin.deployed
4264 :param nsr_id:
4265 :param nslcmop_id:
4266 :param stage: list of string with the content to write on db_nslcmop.detailed-status.
4267 this method will update only the index 2, but it will write on database the concatenated content of the list
4268 :return:
4269 """
4270 db_nsr_update = {}
4271 failed_detail = []
4272 ro_nsr_id = ro_delete_action = None
4273 if nsr_deployed and nsr_deployed.get("RO"):
4274 ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
4275 ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
4276 try:
4277 if ro_nsr_id:
4278 stage[2] = "Deleting ns from VIM."
4279 db_nsr_update["detailed-status"] = " ".join(stage)
4280 self._write_op_status(nslcmop_id, stage)
4281 self.logger.debug(logging_text + stage[2])
4282 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4283 self._write_op_status(nslcmop_id, stage)
4284 desc = await self.RO.delete("ns", ro_nsr_id)
4285 ro_delete_action = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004286 db_nsr_update[
4287 "_admin.deployed.RO.nsr_delete_action_id"
4288 ] = ro_delete_action
tiernoe876f672020-02-13 14:34:48 +00004289 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
4290 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4291 if ro_delete_action:
4292 # wait until NS is deleted from VIM
4293 stage[2] = "Waiting ns deleted from VIM."
4294 detailed_status_old = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004295 self.logger.debug(
4296 logging_text
4297 + stage[2]
4298 + " RO_id={} ro_delete_action={}".format(
4299 ro_nsr_id, ro_delete_action
4300 )
4301 )
tiernoe876f672020-02-13 14:34:48 +00004302 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4303 self._write_op_status(nslcmop_id, stage)
kuused124bfe2019-06-18 12:09:24 +02004304
tiernoe876f672020-02-13 14:34:48 +00004305 delete_timeout = 20 * 60 # 20 minutes
4306 while delete_timeout > 0:
4307 desc = await self.RO.show(
4308 "ns",
4309 item_id_name=ro_nsr_id,
4310 extra_item="action",
garciadeblas5697b8b2021-03-24 09:17:02 +01004311 extra_item_id=ro_delete_action,
4312 )
tiernoe876f672020-02-13 14:34:48 +00004313
4314 # deploymentStatus
4315 self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
4316
4317 ns_status, ns_status_info = self.RO.check_action_status(desc)
4318 if ns_status == "ERROR":
4319 raise ROclient.ROClientException(ns_status_info)
4320 elif ns_status == "BUILD":
4321 stage[2] = "Deleting from VIM {}".format(ns_status_info)
4322 elif ns_status == "ACTIVE":
4323 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
4324 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4325 break
4326 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004327 assert (
4328 False
4329 ), "ROclient.check_action_status returns unknown {}".format(
4330 ns_status
4331 )
tiernoe876f672020-02-13 14:34:48 +00004332 if stage[2] != detailed_status_old:
4333 detailed_status_old = stage[2]
4334 db_nsr_update["detailed-status"] = " ".join(stage)
4335 self._write_op_status(nslcmop_id, stage)
4336 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4337 await asyncio.sleep(5, loop=self.loop)
4338 delete_timeout -= 5
4339 else: # delete_timeout <= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01004340 raise ROclient.ROClientException(
4341 "Timeout waiting ns deleted from VIM"
4342 )
tiernoe876f672020-02-13 14:34:48 +00004343
4344 except Exception as e:
4345 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01004346 if (
4347 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4348 ): # not found
tiernoe876f672020-02-13 14:34:48 +00004349 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
4350 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4351 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004352 self.logger.debug(
4353 logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id)
4354 )
4355 elif (
4356 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4357 ): # conflict
tiernoa2143262020-03-27 16:20:40 +00004358 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01004359 self.logger.debug(
4360 logging_text
4361 + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e)
4362 )
tiernoe876f672020-02-13 14:34:48 +00004363 else:
tiernoa2143262020-03-27 16:20:40 +00004364 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01004365 self.logger.error(
4366 logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e)
4367 )
tiernoe876f672020-02-13 14:34:48 +00004368
4369 # Delete nsd
4370 if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
4371 ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
4372 try:
4373 stage[2] = "Deleting nsd from RO."
4374 db_nsr_update["detailed-status"] = " ".join(stage)
4375 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4376 self._write_op_status(nslcmop_id, stage)
4377 await self.RO.delete("nsd", ro_nsd_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01004378 self.logger.debug(
4379 logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id)
4380 )
tiernoe876f672020-02-13 14:34:48 +00004381 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
4382 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004383 if (
4384 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4385 ): # not found
tiernoe876f672020-02-13 14:34:48 +00004386 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004387 self.logger.debug(
4388 logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id)
4389 )
4390 elif (
4391 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4392 ): # conflict
4393 failed_detail.append(
4394 "ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e)
4395 )
tiernoe876f672020-02-13 14:34:48 +00004396 self.logger.debug(logging_text + failed_detail[-1])
4397 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004398 failed_detail.append(
4399 "ro_nsd_id={} delete error: {}".format(ro_nsd_id, e)
4400 )
tiernoe876f672020-02-13 14:34:48 +00004401 self.logger.error(logging_text + failed_detail[-1])
4402
4403 if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
4404 for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
4405 if not vnf_deployed or not vnf_deployed["id"]:
4406 continue
4407 try:
4408 ro_vnfd_id = vnf_deployed["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004409 stage[
4410 2
4411 ] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
4412 vnf_deployed["member-vnf-index"], ro_vnfd_id
4413 )
tiernoe876f672020-02-13 14:34:48 +00004414 db_nsr_update["detailed-status"] = " ".join(stage)
4415 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4416 self._write_op_status(nslcmop_id, stage)
4417 await self.RO.delete("vnfd", ro_vnfd_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01004418 self.logger.debug(
4419 logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id)
4420 )
tiernoe876f672020-02-13 14:34:48 +00004421 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
4422 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004423 if (
4424 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4425 ): # not found
4426 db_nsr_update[
4427 "_admin.deployed.RO.vnfd.{}.id".format(index)
4428 ] = None
4429 self.logger.debug(
4430 logging_text
4431 + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id)
4432 )
4433 elif (
4434 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4435 ): # conflict
4436 failed_detail.append(
4437 "ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e)
4438 )
tiernoe876f672020-02-13 14:34:48 +00004439 self.logger.debug(logging_text + failed_detail[-1])
4440 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004441 failed_detail.append(
4442 "ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e)
4443 )
tiernoe876f672020-02-13 14:34:48 +00004444 self.logger.error(logging_text + failed_detail[-1])
4445
tiernoa2143262020-03-27 16:20:40 +00004446 if failed_detail:
4447 stage[2] = "Error deleting from VIM"
4448 else:
4449 stage[2] = "Deleted from VIM"
tiernoe876f672020-02-13 14:34:48 +00004450 db_nsr_update["detailed-status"] = " ".join(stage)
4451 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4452 self._write_op_status(nslcmop_id, stage)
4453
4454 if failed_detail:
tiernoa2143262020-03-27 16:20:40 +00004455 raise LcmException("; ".join(failed_detail))
tiernoe876f672020-02-13 14:34:48 +00004456
4457 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004458 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004459 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004460 if not task_is_locked_by_me:
4461 return
4462
tierno59d22d22018-09-25 18:10:19 +02004463 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4464 self.logger.debug(logging_text + "Enter")
tiernoe876f672020-02-13 14:34:48 +00004465 timeout_ns_terminate = self.timeout_ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004466 db_nsr = None
4467 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004468 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004469 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004470 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004471 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004472 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004473 tasks_dict_info = {}
4474 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004475 stage = [
4476 "Stage 1/3: Preparing task.",
4477 "Waiting for previous operations to terminate.",
4478 "",
4479 ]
tiernoe876f672020-02-13 14:34:48 +00004480 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004481 try:
kuused124bfe2019-06-18 12:09:24 +02004482 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004483 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004484
tiernoe876f672020-02-13 14:34:48 +00004485 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4486 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4487 operation_params = db_nslcmop.get("operationParams") or {}
4488 if operation_params.get("timeout_ns_terminate"):
4489 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4490 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4491 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4492
4493 db_nsr_update["operational-status"] = "terminating"
4494 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004495 self._write_ns_status(
4496 nsr_id=nsr_id,
4497 ns_state="TERMINATING",
4498 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004499 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004500 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004501 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004502 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004503 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004504 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4505 return
tierno59d22d22018-09-25 18:10:19 +02004506
tiernoe876f672020-02-13 14:34:48 +00004507 stage[1] = "Getting vnf descriptors from db."
4508 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004509 db_vnfrs_dict = {
4510 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4511 }
tiernoe876f672020-02-13 14:34:48 +00004512 db_vnfds_from_id = {}
4513 db_vnfds_from_member_index = {}
4514 # Loop over VNFRs
4515 for vnfr in db_vnfrs_list:
4516 vnfd_id = vnfr["vnfd-id"]
4517 if vnfd_id not in db_vnfds_from_id:
4518 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4519 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004520 db_vnfds_from_member_index[
4521 vnfr["member-vnf-index-ref"]
4522 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004523
tiernoe876f672020-02-13 14:34:48 +00004524 # Destroy individual execution environments when there are terminating primitives.
4525 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004526 # TODO - check before calling _destroy_N2VC
4527 # if not operation_params.get("skip_terminate_primitives"):#
4528 # or not vca.get("needed_terminate"):
4529 stage[0] = "Stage 2/3 execute terminating primitives."
4530 self.logger.debug(logging_text + stage[0])
4531 stage[1] = "Looking execution environment that needs terminate."
4532 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004533
tierno588547c2020-07-01 15:30:20 +00004534 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004535 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004536 vca_member_vnf_index = vca.get("member-vnf-index")
4537 vca_id = self.get_vca_id(
4538 db_vnfrs_dict.get(vca_member_vnf_index)
4539 if vca_member_vnf_index
4540 else None,
4541 db_nsr,
4542 )
tierno588547c2020-07-01 15:30:20 +00004543 if not vca or not vca.get("ee_id"):
4544 continue
4545 if not vca.get("member-vnf-index"):
4546 # ns
4547 config_descriptor = db_nsr.get("ns-configuration")
4548 elif vca.get("vdu_id"):
4549 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004550 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004551 elif vca.get("kdu_name"):
4552 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004553 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004554 else:
bravofe5a31bc2021-02-17 19:09:12 -03004555 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004556 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004557 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004558 exec_terminate_primitives = not operation_params.get(
4559 "skip_terminate_primitives"
4560 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004561 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4562 # pending native charms
garciadeblas5697b8b2021-03-24 09:17:02 +01004563 destroy_ee = (
4564 True if vca_type in ("helm", "helm-v3", "native_charm") else False
4565 )
tierno86e33612020-09-16 14:13:06 +00004566 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4567 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004568 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004569 self.destroy_N2VC(
4570 logging_text,
4571 db_nslcmop,
4572 vca,
4573 config_descriptor,
4574 vca_index,
4575 destroy_ee,
4576 exec_terminate_primitives,
4577 vca_id=vca_id,
4578 )
4579 )
tierno588547c2020-07-01 15:30:20 +00004580 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004581
tierno588547c2020-07-01 15:30:20 +00004582 # wait for pending tasks of terminate primitives
4583 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004584 self.logger.debug(
4585 logging_text
4586 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4587 )
4588 error_list = await self._wait_for_tasks(
4589 logging_text,
4590 tasks_dict_info,
4591 min(self.timeout_charm_delete, timeout_ns_terminate),
4592 stage,
4593 nslcmop_id,
4594 )
tierno86e33612020-09-16 14:13:06 +00004595 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004596 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004597 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004598
tiernoe876f672020-02-13 14:34:48 +00004599 # remove All execution environments at once
4600 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004601
tierno49676be2020-04-07 16:34:35 +00004602 if nsr_deployed.get("VCA"):
4603 stage[1] = "Deleting all execution environments."
4604 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02004605 vca_id = self.get_vca_id({}, db_nsr)
4606 task_delete_ee = asyncio.ensure_future(
4607 asyncio.wait_for(
4608 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
garciadeblas5697b8b2021-03-24 09:17:02 +01004609 timeout=self.timeout_charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004610 )
4611 )
tierno49676be2020-04-07 16:34:35 +00004612 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
4613 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02004614
tiernoe876f672020-02-13 14:34:48 +00004615 # Delete from k8scluster
4616 stage[1] = "Deleting KDUs."
4617 self.logger.debug(logging_text + stage[1])
4618 # print(nsr_deployed)
4619 for kdu in get_iterable(nsr_deployed, "K8s"):
4620 if not kdu or not kdu.get("kdu-instance"):
4621 continue
4622 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004623 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004624 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4625 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004626 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004627 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4628 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004629 kdu_instance=kdu_instance,
4630 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004631 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004632 )
4633 )
tiernoe876f672020-02-13 14:34:48 +00004634 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004635 self.logger.error(
4636 logging_text
4637 + "Unknown k8s deployment type {}".format(
4638 kdu.get("k8scluster-type")
4639 )
4640 )
tiernoe876f672020-02-13 14:34:48 +00004641 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004642 tasks_dict_info[
4643 task_delete_kdu_instance
4644 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004645
4646 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004647 stage[1] = "Deleting ns from VIM."
tierno69f0d382020-05-07 13:08:09 +00004648 if self.ng_ro:
4649 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004650 self._terminate_ng_ro(
4651 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4652 )
4653 )
tierno69f0d382020-05-07 13:08:09 +00004654 else:
4655 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004656 self._terminate_RO(
4657 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4658 )
4659 )
tiernoe876f672020-02-13 14:34:48 +00004660 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004661
tiernoe876f672020-02-13 14:34:48 +00004662 # rest of staff will be done at finally
4663
garciadeblas5697b8b2021-03-24 09:17:02 +01004664 except (
4665 ROclient.ROClientException,
4666 DbException,
4667 LcmException,
4668 N2VCException,
4669 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004670 self.logger.error(logging_text + "Exit Exception {}".format(e))
4671 exc = e
4672 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004673 self.logger.error(
4674 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4675 )
tiernoe876f672020-02-13 14:34:48 +00004676 exc = "Operation was cancelled"
4677 except Exception as e:
4678 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004679 self.logger.critical(
4680 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4681 exc_info=True,
4682 )
tiernoe876f672020-02-13 14:34:48 +00004683 finally:
4684 if exc:
4685 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004686 try:
tiernoe876f672020-02-13 14:34:48 +00004687 # wait for pending tasks
4688 if tasks_dict_info:
4689 stage[1] = "Waiting for terminate pending tasks."
4690 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004691 error_list += await self._wait_for_tasks(
4692 logging_text,
4693 tasks_dict_info,
4694 timeout_ns_terminate,
4695 stage,
4696 nslcmop_id,
4697 )
tiernoe876f672020-02-13 14:34:48 +00004698 stage[1] = stage[2] = ""
4699 except asyncio.CancelledError:
4700 error_list.append("Cancelled")
4701 # TODO cancell all tasks
4702 except Exception as exc:
4703 error_list.append(str(exc))
4704 # update status at database
4705 if error_list:
4706 error_detail = "; ".join(error_list)
4707 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004708 error_description_nslcmop = "{} Detail: {}".format(
4709 stage[0], error_detail
4710 )
4711 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4712 nslcmop_id, stage[0]
4713 )
tierno59d22d22018-09-25 18:10:19 +02004714
tierno59d22d22018-09-25 18:10:19 +02004715 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004716 db_nsr_update["detailed-status"] = (
4717 error_description_nsr + " Detail: " + error_detail
4718 )
tiernoe876f672020-02-13 14:34:48 +00004719 db_nslcmop_update["detailed-status"] = error_detail
4720 nslcmop_operation_state = "FAILED"
4721 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004722 else:
tiernoa2143262020-03-27 16:20:40 +00004723 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004724 error_description_nsr = error_description_nslcmop = None
4725 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004726 db_nsr_update["operational-status"] = "terminated"
4727 db_nsr_update["detailed-status"] = "Done"
4728 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4729 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004730 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004731
tiernoe876f672020-02-13 14:34:48 +00004732 if db_nsr:
4733 self._write_ns_status(
4734 nsr_id=nsr_id,
4735 ns_state=ns_state,
4736 current_operation="IDLE",
4737 current_operation_id=None,
4738 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004739 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004740 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004741 )
tiernoa17d4f42020-04-28 09:59:23 +00004742 self._write_op_status(
4743 op_id=nslcmop_id,
4744 stage="",
4745 error_message=error_description_nslcmop,
4746 operation_state=nslcmop_operation_state,
4747 other_update=db_nslcmop_update,
4748 )
lloretgalleg6d488782020-07-22 10:13:46 +00004749 if ns_state == "NOT_INSTANTIATED":
4750 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004751 self.db.set_list(
4752 "vnfrs",
4753 {"nsr-id-ref": nsr_id},
4754 {"_admin.nsState": "NOT_INSTANTIATED"},
4755 )
lloretgalleg6d488782020-07-22 10:13:46 +00004756 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004757 self.logger.warn(
4758 logging_text
4759 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4760 nsr_id, e
4761 )
4762 )
tiernoa17d4f42020-04-28 09:59:23 +00004763 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004764 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004765 if nslcmop_operation_state:
4766 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004767 await self.msg.aiowrite(
4768 "ns",
4769 "terminated",
4770 {
4771 "nsr_id": nsr_id,
4772 "nslcmop_id": nslcmop_id,
4773 "operationState": nslcmop_operation_state,
4774 "autoremove": autoremove,
4775 },
4776 loop=self.loop,
4777 )
tierno59d22d22018-09-25 18:10:19 +02004778 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004779 self.logger.error(
4780 logging_text + "kafka_write notification Exception {}".format(e)
4781 )
quilesj7e13aeb2019-10-08 13:34:55 +02004782
tierno59d22d22018-09-25 18:10:19 +02004783 self.logger.debug(logging_text + "Exit")
4784 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4785
garciadeblas5697b8b2021-03-24 09:17:02 +01004786 async def _wait_for_tasks(
4787 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4788 ):
tiernoe876f672020-02-13 14:34:48 +00004789 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004790 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004791 error_list = []
4792 pending_tasks = list(created_tasks_info.keys())
4793 num_tasks = len(pending_tasks)
4794 num_done = 0
4795 stage[1] = "{}/{}.".format(num_done, num_tasks)
4796 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004797 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004798 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004799 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004800 done, pending_tasks = await asyncio.wait(
4801 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4802 )
tiernoe876f672020-02-13 14:34:48 +00004803 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004804 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004805 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004806 new_error = created_tasks_info[task] + ": Timeout"
4807 error_detail_list.append(new_error)
4808 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004809 break
4810 for task in done:
4811 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004812 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004813 else:
4814 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004815 if exc:
4816 if isinstance(exc, asyncio.TimeoutError):
4817 exc = "Timeout"
4818 new_error = created_tasks_info[task] + ": {}".format(exc)
4819 error_list.append(created_tasks_info[task])
4820 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004821 if isinstance(
4822 exc,
4823 (
4824 str,
4825 DbException,
4826 N2VCException,
4827 ROclient.ROClientException,
4828 LcmException,
4829 K8sException,
4830 NgRoException,
4831 ),
4832 ):
tierno067e04a2020-03-31 12:53:13 +00004833 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004834 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004835 exc_traceback = "".join(
4836 traceback.format_exception(None, exc, exc.__traceback__)
4837 )
4838 self.logger.error(
4839 logging_text
4840 + created_tasks_info[task]
4841 + " "
4842 + exc_traceback
4843 )
tierno067e04a2020-03-31 12:53:13 +00004844 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004845 self.logger.debug(
4846 logging_text + created_tasks_info[task] + ": Done"
4847 )
tiernoe876f672020-02-13 14:34:48 +00004848 stage[1] = "{}/{}.".format(num_done, num_tasks)
4849 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004850 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004851 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004852 self.update_db_2(
4853 "nsrs",
4854 nsr_id,
4855 {
4856 "errorDescription": "Error at: " + ", ".join(error_list),
4857 "errorDetail": ". ".join(error_detail_list),
4858 },
4859 )
tiernoe876f672020-02-13 14:34:48 +00004860 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004861 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004862
tiernoda1ff8c2020-10-22 14:12:46 +00004863 @staticmethod
4864 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004865 """
4866 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4867 The default-value is used. If it is between < > it look for a value at instantiation_params
4868 :param primitive_desc: portion of VNFD/NSD that describes primitive
4869 :param params: Params provided by user
4870 :param instantiation_params: Instantiation params provided by user
4871 :return: a dictionary with the calculated params
4872 """
4873 calculated_params = {}
4874 for parameter in primitive_desc.get("parameter", ()):
4875 param_name = parameter["name"]
4876 if param_name in params:
4877 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004878 elif "default-value" in parameter or "value" in parameter:
4879 if "value" in parameter:
4880 calculated_params[param_name] = parameter["value"]
4881 else:
4882 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004883 if (
4884 isinstance(calculated_params[param_name], str)
4885 and calculated_params[param_name].startswith("<")
4886 and calculated_params[param_name].endswith(">")
4887 ):
tierno98ad6ea2019-05-30 17:16:28 +00004888 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004889 calculated_params[param_name] = instantiation_params[
4890 calculated_params[param_name][1:-1]
4891 ]
tiernoda964822019-01-14 15:53:47 +00004892 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004893 raise LcmException(
4894 "Parameter {} needed to execute primitive {} not provided".format(
4895 calculated_params[param_name], primitive_desc["name"]
4896 )
4897 )
tiernoda964822019-01-14 15:53:47 +00004898 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004899 raise LcmException(
4900 "Parameter {} needed to execute primitive {} not provided".format(
4901 param_name, primitive_desc["name"]
4902 )
4903 )
tierno59d22d22018-09-25 18:10:19 +02004904
tiernoda964822019-01-14 15:53:47 +00004905 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004906 calculated_params[param_name] = yaml.safe_dump(
4907 calculated_params[param_name], default_flow_style=True, width=256
4908 )
4909 elif isinstance(calculated_params[param_name], str) and calculated_params[
4910 param_name
4911 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004912 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004913 if parameter.get("data-type") == "INTEGER":
4914 try:
4915 calculated_params[param_name] = int(calculated_params[param_name])
4916 except ValueError: # error converting string to int
4917 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004918 "Parameter {} of primitive {} must be integer".format(
4919 param_name, primitive_desc["name"]
4920 )
4921 )
tiernofa40e692020-10-14 14:59:36 +00004922 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004923 calculated_params[param_name] = not (
4924 (str(calculated_params[param_name])).lower() == "false"
4925 )
tiernoc3f2a822019-11-05 13:45:04 +00004926
4927 # add always ns_config_info if primitive name is config
4928 if primitive_desc["name"] == "config":
4929 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004930 calculated_params["ns_config_info"] = instantiation_params[
4931 "ns_config_info"
4932 ]
tiernoda964822019-01-14 15:53:47 +00004933 return calculated_params
4934
garciadeblas5697b8b2021-03-24 09:17:02 +01004935 def _look_for_deployed_vca(
4936 self,
4937 deployed_vca,
4938 member_vnf_index,
4939 vdu_id,
4940 vdu_count_index,
4941 kdu_name=None,
4942 ee_descriptor_id=None,
4943 ):
tiernoe876f672020-02-13 14:34:48 +00004944 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4945 for vca in deployed_vca:
4946 if not vca:
4947 continue
4948 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4949 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004950 if (
4951 vdu_count_index is not None
4952 and vdu_count_index != vca["vdu_count_index"]
4953 ):
tiernoe876f672020-02-13 14:34:48 +00004954 continue
4955 if kdu_name and kdu_name != vca["kdu_name"]:
4956 continue
tiernoa278b842020-07-08 15:33:55 +00004957 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4958 continue
tiernoe876f672020-02-13 14:34:48 +00004959 break
4960 else:
4961 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004962 raise LcmException(
4963 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4964 " is not deployed".format(
4965 member_vnf_index,
4966 vdu_id,
4967 vdu_count_index,
4968 kdu_name,
4969 ee_descriptor_id,
4970 )
4971 )
tiernoe876f672020-02-13 14:34:48 +00004972 # get ee_id
4973 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004974 vca_type = vca.get(
4975 "type", "lxc_proxy_charm"
4976 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004977 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004978 raise LcmException(
4979 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4980 "execution environment".format(
4981 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4982 )
4983 )
tierno588547c2020-07-01 15:30:20 +00004984 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004985
David Garciac1fe90a2021-03-31 19:12:02 +02004986 async def _ns_execute_primitive(
4987 self,
4988 ee_id,
4989 primitive,
4990 primitive_params,
4991 retries=0,
4992 retries_interval=30,
4993 timeout=None,
4994 vca_type=None,
4995 db_dict=None,
4996 vca_id: str = None,
4997 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00004998 try:
tierno98ad6ea2019-05-30 17:16:28 +00004999 if primitive == "config":
5000 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005001
tierno588547c2020-07-01 15:30:20 +00005002 vca_type = vca_type or "lxc_proxy_charm"
5003
quilesj7e13aeb2019-10-08 13:34:55 +02005004 while retries >= 0:
5005 try:
tierno067e04a2020-03-31 12:53:13 +00005006 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005007 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005008 ee_id=ee_id,
5009 primitive_name=primitive,
5010 params_dict=primitive_params,
5011 progress_timeout=self.timeout_progress_primitive,
tierno588547c2020-07-01 15:30:20 +00005012 total_timeout=self.timeout_primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005013 db_dict=db_dict,
5014 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005015 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005016 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005017 timeout=timeout or self.timeout_primitive,
5018 )
quilesj7e13aeb2019-10-08 13:34:55 +02005019 # execution was OK
5020 break
tierno067e04a2020-03-31 12:53:13 +00005021 except asyncio.CancelledError:
5022 raise
5023 except Exception as e: # asyncio.TimeoutError
5024 if isinstance(e, asyncio.TimeoutError):
5025 e = "Timeout"
quilesj7e13aeb2019-10-08 13:34:55 +02005026 retries -= 1
5027 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005028 self.logger.debug(
5029 "Error executing action {} on {} -> {}".format(
5030 primitive, ee_id, e
5031 )
5032 )
quilesj7e13aeb2019-10-08 13:34:55 +02005033 # wait and retry
5034 await asyncio.sleep(retries_interval, loop=self.loop)
tierno73d8bd02019-11-18 17:33:27 +00005035 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005036 return "FAILED", str(e)
quilesj7e13aeb2019-10-08 13:34:55 +02005037
garciadeblas5697b8b2021-03-24 09:17:02 +01005038 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005039
tierno067e04a2020-03-31 12:53:13 +00005040 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005041 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005042 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005043 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005044
ksaikiranr3fde2c72021-03-15 10:39:06 +05305045 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5046 """
5047 Updating the vca_status with latest juju information in nsrs record
5048 :param: nsr_id: Id of the nsr
5049 :param: nslcmop_id: Id of the nslcmop
5050 :return: None
5051 """
5052
5053 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5054 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005055 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005056 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005057 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5058 cluster_uuid, kdu_instance, cluster_type = (
5059 k8s["k8scluster-uuid"],
5060 k8s["kdu-instance"],
5061 k8s["k8scluster-type"],
5062 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005063 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005064 cluster_uuid=cluster_uuid,
5065 kdu_instance=kdu_instance,
5066 filter={"_id": nsr_id},
5067 vca_id=vca_id,
5068 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005069 )
ksaikiranr656b6dd2021-02-19 10:25:18 +05305070 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005071 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305072 table, filter = "nsrs", {"_id": nsr_id}
5073 path = "_admin.deployed.VCA.{}.".format(vca_index)
5074 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305075
5076 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5077 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5078
tierno59d22d22018-09-25 18:10:19 +02005079 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005080 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005081 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005082 if not task_is_locked_by_me:
5083 return
5084
tierno59d22d22018-09-25 18:10:19 +02005085 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5086 self.logger.debug(logging_text + "Enter")
5087 # get all needed from database
5088 db_nsr = None
5089 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005090 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005091 db_nslcmop_update = {}
5092 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005093 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005094 exc = None
5095 try:
kuused124bfe2019-06-18 12:09:24 +02005096 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005097 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005098 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005099
quilesj4cda56b2019-12-05 10:02:20 +00005100 self._write_ns_status(
5101 nsr_id=nsr_id,
5102 ns_state=None,
5103 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005104 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005105 )
5106
tierno59d22d22018-09-25 18:10:19 +02005107 step = "Getting information from database"
5108 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5109 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005110 if db_nslcmop["operationParams"].get("primitive_params"):
5111 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5112 db_nslcmop["operationParams"]["primitive_params"]
5113 )
tiernoda964822019-01-14 15:53:47 +00005114
tiernoe4f7e6c2018-11-27 14:55:30 +00005115 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005116 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005117 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005118 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005119 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005120 primitive = db_nslcmop["operationParams"]["primitive"]
5121 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005122 timeout_ns_action = db_nslcmop["operationParams"].get(
5123 "timeout_ns_action", self.timeout_primitive
5124 )
tierno59d22d22018-09-25 18:10:19 +02005125
tierno1b633412019-02-25 16:48:23 +00005126 if vnf_index:
5127 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005128 db_vnfr = self.db.get_one(
5129 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5130 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005131 if db_vnfr.get("kdur"):
5132 kdur_list = []
5133 for kdur in db_vnfr["kdur"]:
5134 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005135 kdur["additionalParams"] = json.loads(
5136 kdur["additionalParams"]
5137 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005138 kdur_list.append(kdur)
5139 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005140 step = "Getting vnfd from database"
5141 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005142
5143 # Sync filesystem before running a primitive
5144 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005145 else:
tierno067e04a2020-03-31 12:53:13 +00005146 step = "Getting nsd from database"
5147 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005148
David Garciac1fe90a2021-03-31 19:12:02 +02005149 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005150 # for backward compatibility
5151 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5152 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5153 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5154 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5155
tiernoda964822019-01-14 15:53:47 +00005156 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005157 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005158 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005159 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005160 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005161 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005162 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005163 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005164 else:
tiernoa278b842020-07-08 15:33:55 +00005165 descriptor_configuration = db_nsd.get("ns-configuration")
5166
garciadeblas5697b8b2021-03-24 09:17:02 +01005167 if descriptor_configuration and descriptor_configuration.get(
5168 "config-primitive"
5169 ):
tiernoa278b842020-07-08 15:33:55 +00005170 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005171 if config_primitive["name"] == primitive:
5172 config_primitive_desc = config_primitive
5173 break
tiernoda964822019-01-14 15:53:47 +00005174
garciadeblas6bed6b32020-07-20 11:05:42 +00005175 if not config_primitive_desc:
5176 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005177 raise LcmException(
5178 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5179 primitive
5180 )
5181 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005182 primitive_name = primitive
5183 ee_descriptor_id = None
5184 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005185 primitive_name = config_primitive_desc.get(
5186 "execution-environment-primitive", primitive
5187 )
5188 ee_descriptor_id = config_primitive_desc.get(
5189 "execution-environment-ref"
5190 )
tierno1b633412019-02-25 16:48:23 +00005191
tierno1b633412019-02-25 16:48:23 +00005192 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005193 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005194 vdur = next(
5195 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5196 )
bravof922c4172020-11-24 21:21:43 -03005197 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005198 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005199 kdur = next(
5200 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5201 )
bravof922c4172020-11-24 21:21:43 -03005202 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005203 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005204 desc_params = parse_yaml_strings(
5205 db_vnfr.get("additionalParamsForVnf")
5206 )
tierno1b633412019-02-25 16:48:23 +00005207 else:
bravof922c4172020-11-24 21:21:43 -03005208 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005209 if kdu_name and get_configuration(db_vnfd, kdu_name):
5210 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005211 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005212 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005213 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005214 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005215 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005216 kdu = find_in_list(
5217 nsr_deployed["K8s"],
5218 lambda kdu: kdu_name == kdu["kdu-name"]
5219 and kdu["member-vnf-index"] == vnf_index,
5220 )
5221 kdu_action = (
5222 True
5223 if primitive_name in actions
5224 and kdu["k8scluster-type"] not in ("helm-chart", "helm-chart-v3")
5225 else False
5226 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005227
tiernoda964822019-01-14 15:53:47 +00005228 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005229 if kdu_name and (
5230 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5231 ):
tierno067e04a2020-03-31 12:53:13 +00005232 # kdur and desc_params already set from before
5233 if primitive_params:
5234 desc_params.update(primitive_params)
5235 # TODO Check if we will need something at vnf level
5236 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005237 if (
5238 kdu_name == kdu["kdu-name"]
5239 and kdu["member-vnf-index"] == vnf_index
5240 ):
tierno067e04a2020-03-31 12:53:13 +00005241 break
5242 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005243 raise LcmException(
5244 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5245 )
quilesj7e13aeb2019-10-08 13:34:55 +02005246
tierno067e04a2020-03-31 12:53:13 +00005247 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005248 msg = "unknown k8scluster-type '{}'".format(
5249 kdu.get("k8scluster-type")
5250 )
tierno067e04a2020-03-31 12:53:13 +00005251 raise LcmException(msg)
5252
garciadeblas5697b8b2021-03-24 09:17:02 +01005253 db_dict = {
5254 "collection": "nsrs",
5255 "filter": {"_id": nsr_id},
5256 "path": "_admin.deployed.K8s.{}".format(index),
5257 }
5258 self.logger.debug(
5259 logging_text
5260 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5261 )
tiernoa278b842020-07-08 15:33:55 +00005262 step = "Executing kdu {}".format(primitive_name)
5263 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00005264 if desc_params.get("kdu_model"):
5265 kdu_model = desc_params.get("kdu_model")
5266 del desc_params["kdu_model"]
5267 else:
5268 kdu_model = kdu.get("kdu-model")
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005269 if kdu_model.count("/") < 2:
5270 parts = kdu_model.split(sep=":")
5271 if len(parts) == 2:
5272 kdu_model = parts[0]
limon5ea888c2022-10-28 10:39:16 +02005273 if desc_params.get("kdu_atomic_upgrade"):
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005274 atomic_upgrade = desc_params.get(
5275 "kdu_atomic_upgrade"
5276 ).lower() in ("yes", "true", "1")
limon5ea888c2022-10-28 10:39:16 +02005277 del desc_params["kdu_atomic_upgrade"]
5278 else:
5279 atomic_upgrade = True
tierno067e04a2020-03-31 12:53:13 +00005280
5281 detailed_status = await asyncio.wait_for(
5282 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5283 cluster_uuid=kdu.get("k8scluster-uuid"),
5284 kdu_instance=kdu.get("kdu-instance"),
limon5ea888c2022-10-28 10:39:16 +02005285 atomic=atomic_upgrade,
garciadeblas5697b8b2021-03-24 09:17:02 +01005286 kdu_model=kdu_model,
5287 params=desc_params,
5288 db_dict=db_dict,
5289 timeout=timeout_ns_action,
5290 ),
5291 timeout=timeout_ns_action + 10,
5292 )
5293 self.logger.debug(
5294 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5295 )
tiernoa278b842020-07-08 15:33:55 +00005296 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005297 detailed_status = await asyncio.wait_for(
5298 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5299 cluster_uuid=kdu.get("k8scluster-uuid"),
5300 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005301 db_dict=db_dict,
5302 ),
5303 timeout=timeout_ns_action,
5304 )
tiernoa278b842020-07-08 15:33:55 +00005305 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005306 detailed_status = await asyncio.wait_for(
5307 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5308 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005309 kdu_instance=kdu.get("kdu-instance"),
5310 vca_id=vca_id,
5311 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005312 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005313 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005314 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005315 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5316 kdu["kdu-name"], nsr_id
5317 )
5318 params = self._map_primitive_params(
5319 config_primitive_desc, primitive_params, desc_params
5320 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005321
5322 detailed_status = await asyncio.wait_for(
5323 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5324 cluster_uuid=kdu.get("k8scluster-uuid"),
5325 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005326 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005327 params=params,
5328 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005329 timeout=timeout_ns_action,
5330 vca_id=vca_id,
5331 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005332 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005333 )
tierno067e04a2020-03-31 12:53:13 +00005334
5335 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005336 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005337 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005338 detailed_status = ""
5339 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005340 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005341 ee_id, vca_type = self._look_for_deployed_vca(
5342 nsr_deployed["VCA"],
5343 member_vnf_index=vnf_index,
5344 vdu_id=vdu_id,
5345 vdu_count_index=vdu_count_index,
5346 ee_descriptor_id=ee_descriptor_id,
5347 )
5348 for vca_index, vca_deployed in enumerate(
5349 db_nsr["_admin"]["deployed"]["VCA"]
5350 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305351 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005352 db_dict = {
5353 "collection": "nsrs",
5354 "filter": {"_id": nsr_id},
5355 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5356 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305357 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005358 (
5359 nslcmop_operation_state,
5360 detailed_status,
5361 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005362 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005363 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005364 primitive_params=self._map_primitive_params(
5365 config_primitive_desc, primitive_params, desc_params
5366 ),
tierno588547c2020-07-01 15:30:20 +00005367 timeout=timeout_ns_action,
5368 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005369 db_dict=db_dict,
5370 vca_id=vca_id,
5371 )
tierno067e04a2020-03-31 12:53:13 +00005372
5373 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005374 error_description_nslcmop = (
5375 detailed_status if nslcmop_operation_state == "FAILED" else ""
5376 )
5377 self.logger.debug(
5378 logging_text
5379 + " task Done with result {} {}".format(
5380 nslcmop_operation_state, detailed_status
5381 )
5382 )
tierno59d22d22018-09-25 18:10:19 +02005383 return # database update is called inside finally
5384
tiernof59ad6c2020-04-08 12:50:52 +00005385 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005386 self.logger.error(logging_text + "Exit Exception {}".format(e))
5387 exc = e
5388 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005389 self.logger.error(
5390 logging_text + "Cancelled Exception while '{}'".format(step)
5391 )
tierno59d22d22018-09-25 18:10:19 +02005392 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005393 except asyncio.TimeoutError:
5394 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5395 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005396 except Exception as e:
5397 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005398 self.logger.critical(
5399 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5400 exc_info=True,
5401 )
tierno59d22d22018-09-25 18:10:19 +02005402 finally:
tierno067e04a2020-03-31 12:53:13 +00005403 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005404 db_nslcmop_update[
5405 "detailed-status"
5406 ] = (
5407 detailed_status
5408 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005409 nslcmop_operation_state = "FAILED"
5410 if db_nsr:
5411 self._write_ns_status(
5412 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005413 ns_state=db_nsr[
5414 "nsState"
5415 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005416 current_operation="IDLE",
5417 current_operation_id=None,
5418 # error_description=error_description_nsr,
5419 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005420 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005421 )
5422
garciadeblas5697b8b2021-03-24 09:17:02 +01005423 self._write_op_status(
5424 op_id=nslcmop_id,
5425 stage="",
5426 error_message=error_description_nslcmop,
5427 operation_state=nslcmop_operation_state,
5428 other_update=db_nslcmop_update,
5429 )
tierno067e04a2020-03-31 12:53:13 +00005430
tierno59d22d22018-09-25 18:10:19 +02005431 if nslcmop_operation_state:
5432 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005433 await self.msg.aiowrite(
5434 "ns",
5435 "actioned",
5436 {
5437 "nsr_id": nsr_id,
5438 "nslcmop_id": nslcmop_id,
5439 "operationState": nslcmop_operation_state,
5440 },
5441 loop=self.loop,
5442 )
tierno59d22d22018-09-25 18:10:19 +02005443 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005444 self.logger.error(
5445 logging_text + "kafka_write notification Exception {}".format(e)
5446 )
tierno59d22d22018-09-25 18:10:19 +02005447 self.logger.debug(logging_text + "Exit")
5448 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005449 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005450
elumalaica7ece02022-04-12 12:47:32 +05305451 async def terminate_vdus(
5452 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5453 ):
5454 """This method terminates VDUs
5455
5456 Args:
5457 db_vnfr: VNF instance record
5458 member_vnf_index: VNF index to identify the VDUs to be removed
5459 db_nsr: NS instance record
5460 update_db_nslcmops: Nslcmop update record
5461 """
5462 vca_scaling_info = []
5463 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5464 scaling_info["scaling_direction"] = "IN"
5465 scaling_info["vdu-delete"] = {}
5466 scaling_info["kdu-delete"] = {}
5467 db_vdur = db_vnfr.get("vdur")
5468 vdur_list = copy(db_vdur)
5469 count_index = 0
5470 for index, vdu in enumerate(vdur_list):
5471 vca_scaling_info.append(
5472 {
5473 "osm_vdu_id": vdu["vdu-id-ref"],
5474 "member-vnf-index": member_vnf_index,
5475 "type": "delete",
5476 "vdu_index": count_index,
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005477 }
5478 )
elumalaica7ece02022-04-12 12:47:32 +05305479 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5480 scaling_info["vdu"].append(
5481 {
5482 "name": vdu.get("name") or vdu.get("vdu-name"),
5483 "vdu_id": vdu["vdu-id-ref"],
5484 "interface": [],
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005485 }
5486 )
elumalaica7ece02022-04-12 12:47:32 +05305487 for interface in vdu["interfaces"]:
5488 scaling_info["vdu"][index]["interface"].append(
5489 {
5490 "name": interface["name"],
5491 "ip_address": interface["ip-address"],
5492 "mac_address": interface.get("mac-address"),
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005493 }
5494 )
elumalaica7ece02022-04-12 12:47:32 +05305495 self.logger.info("NS update scaling info{}".format(scaling_info))
5496 stage[2] = "Terminating VDUs"
5497 if scaling_info.get("vdu-delete"):
5498 # scale_process = "RO"
5499 if self.ro_config.get("ng"):
5500 await self._scale_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005501 logging_text,
5502 db_nsr,
5503 update_db_nslcmops,
5504 db_vnfr,
5505 scaling_info,
5506 stage,
elumalaica7ece02022-04-12 12:47:32 +05305507 )
5508
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005509 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305510 """This method is to Remove VNF instances from NS.
5511
5512 Args:
5513 nsr_id: NS instance id
5514 nslcmop_id: nslcmop id of update
5515 vnf_instance_id: id of the VNF instance to be removed
5516
5517 Returns:
5518 result: (str, str) COMPLETED/FAILED, details
5519 """
5520 try:
5521 db_nsr_update = {}
5522 logging_text = "Task ns={} update ".format(nsr_id)
5523 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5524 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5525 if check_vnfr_count > 1:
5526 stage = ["", "", ""]
5527 step = "Getting nslcmop from database"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005528 self.logger.debug(
5529 step + " after having waited for previous tasks to be completed"
5530 )
elumalaica7ece02022-04-12 12:47:32 +05305531 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5532 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5533 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5534 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5535 """ db_vnfr = self.db.get_one(
5536 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5537
5538 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005539 await self.terminate_vdus(
5540 db_vnfr,
5541 member_vnf_index,
5542 db_nsr,
5543 update_db_nslcmops,
5544 stage,
5545 logging_text,
5546 )
elumalaica7ece02022-04-12 12:47:32 +05305547
5548 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5549 constituent_vnfr.remove(db_vnfr.get("_id"))
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005550 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5551 "constituent-vnfr-ref"
5552 )
elumalaica7ece02022-04-12 12:47:32 +05305553 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5554 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5555 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5556 return "COMPLETED", "Done"
5557 else:
5558 step = "Terminate VNF Failed with"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005559 raise LcmException(
5560 "{} Cannot terminate the last VNF in this NS.".format(
5561 vnf_instance_id
5562 )
5563 )
elumalaica7ece02022-04-12 12:47:32 +05305564 except (LcmException, asyncio.CancelledError):
5565 raise
5566 except Exception as e:
5567 self.logger.debug("Error removing VNF {}".format(e))
5568 return "FAILED", "Error removing VNF {}".format(e)
5569
elumalaib9e357c2022-04-27 09:58:38 +05305570 async def _ns_redeploy_vnf(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005571 self,
5572 nsr_id,
5573 nslcmop_id,
5574 db_vnfd,
5575 db_vnfr,
5576 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305577 ):
5578 """This method updates and redeploys VNF instances
5579
5580 Args:
5581 nsr_id: NS instance id
5582 nslcmop_id: nslcmop id
5583 db_vnfd: VNF descriptor
5584 db_vnfr: VNF instance record
5585 db_nsr: NS instance record
5586
5587 Returns:
5588 result: (str, str) COMPLETED/FAILED, details
5589 """
5590 try:
5591 count_index = 0
5592 stage = ["", "", ""]
5593 logging_text = "Task ns={} update ".format(nsr_id)
5594 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5595 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5596
5597 # Terminate old VNF resources
5598 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005599 await self.terminate_vdus(
5600 db_vnfr,
5601 member_vnf_index,
5602 db_nsr,
5603 update_db_nslcmops,
5604 stage,
5605 logging_text,
5606 )
elumalaib9e357c2022-04-27 09:58:38 +05305607
5608 # old_vnfd_id = db_vnfr["vnfd-id"]
5609 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5610 new_db_vnfd = db_vnfd
5611 # new_vnfd_ref = new_db_vnfd["id"]
5612 # new_vnfd_id = vnfd_id
5613
5614 # Create VDUR
5615 new_vnfr_cp = []
5616 for cp in new_db_vnfd.get("ext-cpd", ()):
5617 vnf_cp = {
5618 "name": cp.get("id"),
5619 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5620 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5621 "id": cp.get("id"),
5622 }
5623 new_vnfr_cp.append(vnf_cp)
5624 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5625 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5626 # new_vnfr_update = {"vnfd-ref": new_vnfd_ref, "vnfd-id": new_vnfd_id, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""}
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005627 new_vnfr_update = {
5628 "revision": latest_vnfd_revision,
5629 "connection-point": new_vnfr_cp,
5630 "vdur": new_vdur,
5631 "ip-address": "",
5632 }
elumalaib9e357c2022-04-27 09:58:38 +05305633 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5634 updated_db_vnfr = self.db.get_one(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005635 "vnfrs",
5636 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305637 )
5638
5639 # Instantiate new VNF resources
5640 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5641 vca_scaling_info = []
5642 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5643 scaling_info["scaling_direction"] = "OUT"
5644 scaling_info["vdu-create"] = {}
5645 scaling_info["kdu-create"] = {}
5646 vdud_instantiate_list = db_vnfd["vdu"]
5647 for index, vdud in enumerate(vdud_instantiate_list):
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005648 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305649 if cloud_init_text:
5650 additional_params = (
5651 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5652 or {}
5653 )
5654 cloud_init_list = []
5655 if cloud_init_text:
5656 # TODO Information of its own ip is not available because db_vnfr is not updated.
5657 additional_params["OSM"] = get_osm_params(
5658 updated_db_vnfr, vdud["id"], 1
5659 )
5660 cloud_init_list.append(
5661 self._parse_cloud_init(
5662 cloud_init_text,
5663 additional_params,
5664 db_vnfd["id"],
5665 vdud["id"],
5666 )
5667 )
5668 vca_scaling_info.append(
5669 {
5670 "osm_vdu_id": vdud["id"],
5671 "member-vnf-index": member_vnf_index,
5672 "type": "create",
5673 "vdu_index": count_index,
5674 }
5675 )
5676 scaling_info["vdu-create"][vdud["id"]] = count_index
5677 if self.ro_config.get("ng"):
5678 self.logger.debug(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005679 "New Resources to be deployed: {}".format(scaling_info)
5680 )
elumalaib9e357c2022-04-27 09:58:38 +05305681 await self._scale_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005682 logging_text,
5683 db_nsr,
5684 update_db_nslcmops,
5685 updated_db_vnfr,
5686 scaling_info,
5687 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305688 )
5689 return "COMPLETED", "Done"
5690 except (LcmException, asyncio.CancelledError):
5691 raise
5692 except Exception as e:
5693 self.logger.debug("Error updating VNF {}".format(e))
5694 return "FAILED", "Error updating VNF {}".format(e)
5695
aticigdffa6212022-04-12 15:27:53 +03005696 async def _ns_charm_upgrade(
5697 self,
5698 ee_id,
5699 charm_id,
5700 charm_type,
5701 path,
5702 timeout: float = None,
5703 ) -> (str, str):
5704 """This method upgrade charms in VNF instances
5705
5706 Args:
5707 ee_id: Execution environment id
5708 path: Local path to the charm
5709 charm_id: charm-id
5710 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5711 timeout: (Float) Timeout for the ns update operation
5712
5713 Returns:
5714 result: (str, str) COMPLETED/FAILED, details
5715 """
5716 try:
5717 charm_type = charm_type or "lxc_proxy_charm"
5718 output = await self.vca_map[charm_type].upgrade_charm(
5719 ee_id=ee_id,
5720 path=path,
5721 charm_id=charm_id,
5722 charm_type=charm_type,
5723 timeout=timeout or self.timeout_ns_update,
5724 )
5725
5726 if output:
5727 return "COMPLETED", output
5728
5729 except (LcmException, asyncio.CancelledError):
5730 raise
5731
5732 except Exception as e:
aticigdffa6212022-04-12 15:27:53 +03005733 self.logger.debug("Error upgrading charm {}".format(path))
5734
5735 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5736
5737 async def update(self, nsr_id, nslcmop_id):
5738 """Update NS according to different update types
5739
5740 This method performs upgrade of VNF instances then updates the revision
5741 number in VNF record
5742
5743 Args:
5744 nsr_id: Network service will be updated
5745 nslcmop_id: ns lcm operation id
5746
5747 Returns:
5748 It may raise DbException, LcmException, N2VCException, K8sException
5749
5750 """
5751 # Try to lock HA task here
5752 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5753 if not task_is_locked_by_me:
5754 return
5755
5756 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5757 self.logger.debug(logging_text + "Enter")
5758
5759 # Set the required variables to be filled up later
5760 db_nsr = None
5761 db_nslcmop_update = {}
5762 vnfr_update = {}
5763 nslcmop_operation_state = None
5764 db_nsr_update = {}
5765 error_description_nslcmop = ""
5766 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305767 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005768 detailed_status = ""
5769
5770 try:
5771 # wait for any previous tasks in process
5772 step = "Waiting for previous operations to terminate"
5773 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5774 self._write_ns_status(
5775 nsr_id=nsr_id,
5776 ns_state=None,
5777 current_operation="UPDATING",
5778 current_operation_id=nslcmop_id,
5779 )
5780
5781 step = "Getting nslcmop from database"
5782 db_nslcmop = self.db.get_one(
5783 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5784 )
5785 update_type = db_nslcmop["operationParams"]["updateType"]
5786
5787 step = "Getting nsr from database"
5788 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5789 old_operational_status = db_nsr["operational-status"]
5790 db_nsr_update["operational-status"] = "updating"
5791 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5792 nsr_deployed = db_nsr["_admin"].get("deployed")
5793
5794 if update_type == "CHANGE_VNFPKG":
aticigdffa6212022-04-12 15:27:53 +03005795 # Get the input parameters given through update request
5796 vnf_instance_id = db_nslcmop["operationParams"][
5797 "changeVnfPackageData"
5798 ].get("vnfInstanceId")
5799
5800 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5801 "vnfdId"
5802 )
5803 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5804
5805 step = "Getting vnfr from database"
5806 db_vnfr = self.db.get_one(
5807 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5808 )
5809
5810 step = "Getting vnfds from database"
5811 # Latest VNFD
5812 latest_vnfd = self.db.get_one(
5813 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5814 )
5815 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5816
5817 # Current VNFD
5818 current_vnf_revision = db_vnfr.get("revision", 1)
5819 current_vnfd = self.db.get_one(
5820 "vnfds_revisions",
5821 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5822 fail_on_empty=False,
5823 )
5824 # Charm artifact paths will be filled up later
5825 (
5826 current_charm_artifact_path,
5827 target_charm_artifact_path,
5828 charm_artifact_paths,
5829 ) = ([], [], [])
5830
5831 step = "Checking if revision has changed in VNFD"
5832 if current_vnf_revision != latest_vnfd_revision:
elumalaib9e357c2022-04-27 09:58:38 +05305833 change_type = "policy_updated"
5834
aticigdffa6212022-04-12 15:27:53 +03005835 # There is new revision of VNFD, update operation is required
5836 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005837 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005838
5839 step = "Removing the VNFD packages if they exist in the local path"
5840 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5841 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5842
5843 step = "Get the VNFD packages from FSMongo"
5844 self.fs.sync(from_path=latest_vnfd_path)
5845 self.fs.sync(from_path=current_vnfd_path)
5846
5847 step = (
5848 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5849 )
5850 base_folder = latest_vnfd["_admin"]["storage"]
5851
5852 for charm_index, charm_deployed in enumerate(
5853 get_iterable(nsr_deployed, "VCA")
5854 ):
5855 vnf_index = db_vnfr.get("member-vnf-index-ref")
5856
5857 # Getting charm-id and charm-type
5858 if charm_deployed.get("member-vnf-index") == vnf_index:
5859 charm_id = self.get_vca_id(db_vnfr, db_nsr)
5860 charm_type = charm_deployed.get("type")
5861
5862 # Getting ee-id
5863 ee_id = charm_deployed.get("ee_id")
5864
5865 step = "Getting descriptor config"
5866 descriptor_config = get_configuration(
5867 current_vnfd, current_vnfd["id"]
5868 )
5869
5870 if "execution-environment-list" in descriptor_config:
5871 ee_list = descriptor_config.get(
5872 "execution-environment-list", []
5873 )
5874 else:
5875 ee_list = []
5876
5877 # There could be several charm used in the same VNF
5878 for ee_item in ee_list:
5879 if ee_item.get("juju"):
aticigdffa6212022-04-12 15:27:53 +03005880 step = "Getting charm name"
5881 charm_name = ee_item["juju"].get("charm")
5882
5883 step = "Setting Charm artifact paths"
5884 current_charm_artifact_path.append(
5885 get_charm_artifact_path(
5886 base_folder,
5887 charm_name,
5888 charm_type,
5889 current_vnf_revision,
5890 )
5891 )
5892 target_charm_artifact_path.append(
5893 get_charm_artifact_path(
5894 base_folder,
5895 charm_name,
5896 charm_type,
aticigd7083542022-05-30 20:45:55 +03005897 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005898 )
5899 )
5900
5901 charm_artifact_paths = zip(
5902 current_charm_artifact_path, target_charm_artifact_path
5903 )
5904
5905 step = "Checking if software version has changed in VNFD"
5906 if find_software_version(current_vnfd) != find_software_version(
5907 latest_vnfd
5908 ):
aticigdffa6212022-04-12 15:27:53 +03005909 step = "Checking if existing VNF has charm"
5910 for current_charm_path, target_charm_path in list(
5911 charm_artifact_paths
5912 ):
5913 if current_charm_path:
5914 raise LcmException(
5915 "Software version change is not supported as VNF instance {} has charm.".format(
5916 vnf_instance_id
5917 )
5918 )
5919
5920 # There is no change in the charm package, then redeploy the VNF
5921 # based on new descriptor
5922 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05305923 member_vnf_index = db_vnfr["member-vnf-index-ref"]
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02005924 (result, detailed_status) = await self._ns_redeploy_vnf(
5925 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05305926 )
5927 if result == "FAILED":
5928 nslcmop_operation_state = result
5929 error_description_nslcmop = detailed_status
5930 db_nslcmop_update["detailed-status"] = detailed_status
5931 self.logger.debug(
5932 logging_text
5933 + " step {} Done with result {} {}".format(
5934 step, nslcmop_operation_state, detailed_status
5935 )
5936 )
aticigdffa6212022-04-12 15:27:53 +03005937
5938 else:
5939 step = "Checking if any charm package has changed or not"
5940 for current_charm_path, target_charm_path in list(
5941 charm_artifact_paths
5942 ):
5943 if (
5944 current_charm_path
5945 and target_charm_path
5946 and self.check_charm_hash_changed(
5947 current_charm_path, target_charm_path
5948 )
5949 ):
aticigdffa6212022-04-12 15:27:53 +03005950 step = "Checking whether VNF uses juju bundle"
5951 if check_juju_bundle_existence(current_vnfd):
aticigdffa6212022-04-12 15:27:53 +03005952 raise LcmException(
5953 "Charm upgrade is not supported for the instance which"
5954 " uses juju-bundle: {}".format(
5955 check_juju_bundle_existence(current_vnfd)
5956 )
5957 )
5958
5959 step = "Upgrading Charm"
5960 (
5961 result,
5962 detailed_status,
5963 ) = await self._ns_charm_upgrade(
5964 ee_id=ee_id,
5965 charm_id=charm_id,
5966 charm_type=charm_type,
5967 path=self.fs.path + target_charm_path,
5968 timeout=timeout_seconds,
5969 )
5970
5971 if result == "FAILED":
5972 nslcmop_operation_state = result
5973 error_description_nslcmop = detailed_status
5974
5975 db_nslcmop_update["detailed-status"] = detailed_status
5976 self.logger.debug(
5977 logging_text
5978 + " step {} Done with result {} {}".format(
5979 step, nslcmop_operation_state, detailed_status
5980 )
5981 )
5982
5983 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05305984 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5985 result = "COMPLETED"
5986 detailed_status = "Done"
5987 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03005988
5989 # If nslcmop_operation_state is None, so any operation is not failed.
5990 if not nslcmop_operation_state:
5991 nslcmop_operation_state = "COMPLETED"
5992
5993 # If update CHANGE_VNFPKG nslcmop_operation is successful
5994 # vnf revision need to be updated
5995 vnfr_update["revision"] = latest_vnfd_revision
5996 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
5997
5998 self.logger.debug(
5999 logging_text
6000 + " task Done with result {} {}".format(
6001 nslcmop_operation_state, detailed_status
6002 )
6003 )
6004 elif update_type == "REMOVE_VNF":
6005 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306006 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6007 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6008 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6009 step = "Removing VNF"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02006010 (result, detailed_status) = await self.remove_vnf(
6011 nsr_id, nslcmop_id, vnf_instance_id
6012 )
elumalaica7ece02022-04-12 12:47:32 +05306013 if result == "FAILED":
6014 nslcmop_operation_state = result
6015 error_description_nslcmop = detailed_status
6016 db_nslcmop_update["detailed-status"] = detailed_status
6017 change_type = "vnf_terminated"
6018 if not nslcmop_operation_state:
6019 nslcmop_operation_state = "COMPLETED"
6020 self.logger.debug(
6021 logging_text
6022 + " task Done with result {} {}".format(
6023 nslcmop_operation_state, detailed_status
6024 )
6025 )
aticigdffa6212022-04-12 15:27:53 +03006026
k4.rahulb827de92022-05-02 16:35:02 +00006027 elif update_type == "OPERATE_VNF":
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02006028 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6029 "vnfInstanceId"
6030 ]
6031 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6032 "changeStateTo"
6033 ]
6034 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6035 "additionalParam"
6036 ]
k4.rahulb827de92022-05-02 16:35:02 +00006037 (result, detailed_status) = await self.rebuild_start_stop(
6038 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02006039 )
k4.rahulb827de92022-05-02 16:35:02 +00006040 if result == "FAILED":
6041 nslcmop_operation_state = result
6042 error_description_nslcmop = detailed_status
6043 db_nslcmop_update["detailed-status"] = detailed_status
6044 if not nslcmop_operation_state:
6045 nslcmop_operation_state = "COMPLETED"
6046 self.logger.debug(
6047 logging_text
6048 + " task Done with result {} {}".format(
6049 nslcmop_operation_state, detailed_status
6050 )
6051 )
6052
aticigdffa6212022-04-12 15:27:53 +03006053 # If nslcmop_operation_state is None, so any operation is not failed.
6054 # All operations are executed in overall.
6055 if not nslcmop_operation_state:
6056 nslcmop_operation_state = "COMPLETED"
6057 db_nsr_update["operational-status"] = old_operational_status
6058
6059 except (DbException, LcmException, N2VCException, K8sException) as e:
6060 self.logger.error(logging_text + "Exit Exception {}".format(e))
6061 exc = e
6062 except asyncio.CancelledError:
6063 self.logger.error(
6064 logging_text + "Cancelled Exception while '{}'".format(step)
6065 )
6066 exc = "Operation was cancelled"
6067 except asyncio.TimeoutError:
6068 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6069 exc = "Timeout"
6070 except Exception as e:
6071 exc = traceback.format_exc()
6072 self.logger.critical(
6073 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6074 exc_info=True,
6075 )
6076 finally:
6077 if exc:
6078 db_nslcmop_update[
6079 "detailed-status"
6080 ] = (
6081 detailed_status
6082 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6083 nslcmop_operation_state = "FAILED"
6084 db_nsr_update["operational-status"] = old_operational_status
6085 if db_nsr:
6086 self._write_ns_status(
6087 nsr_id=nsr_id,
6088 ns_state=db_nsr["nsState"],
6089 current_operation="IDLE",
6090 current_operation_id=None,
6091 other_update=db_nsr_update,
6092 )
6093
6094 self._write_op_status(
6095 op_id=nslcmop_id,
6096 stage="",
6097 error_message=error_description_nslcmop,
6098 operation_state=nslcmop_operation_state,
6099 other_update=db_nslcmop_update,
6100 )
6101
6102 if nslcmop_operation_state:
6103 try:
elumalaica7ece02022-04-12 12:47:32 +05306104 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306105 "nsr_id": nsr_id,
6106 "nslcmop_id": nslcmop_id,
6107 "operationState": nslcmop_operation_state,
6108 }
6109 if change_type in ("vnf_terminated", "policy_updated"):
elumalaica7ece02022-04-12 12:47:32 +05306110 msg.update({"vnf_member_index": member_vnf_index})
6111 await self.msg.aiowrite("ns", change_type, msg, loop=self.loop)
aticigdffa6212022-04-12 15:27:53 +03006112 except Exception as e:
6113 self.logger.error(
6114 logging_text + "kafka_write notification Exception {}".format(e)
6115 )
6116 self.logger.debug(logging_text + "Exit")
6117 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6118 return nslcmop_operation_state, detailed_status
6119
tierno59d22d22018-09-25 18:10:19 +02006120 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006121 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006122 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006123 if not task_is_locked_by_me:
6124 return
6125
tierno59d22d22018-09-25 18:10:19 +02006126 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006127 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006128 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006129 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006130 self.logger.debug(logging_text + "Enter")
6131 # get all needed from database
6132 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006133 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006134 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006135 exc = None
tierno9ab95942018-10-10 16:44:22 +02006136 # in case of error, indicates what part of scale was failed to put nsr at error status
6137 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006138 old_operational_status = ""
6139 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006140 nsi_id = None
tierno59d22d22018-09-25 18:10:19 +02006141 try:
kuused124bfe2019-06-18 12:09:24 +02006142 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006143 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006144 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6145 self._write_ns_status(
6146 nsr_id=nsr_id,
6147 ns_state=None,
6148 current_operation="SCALING",
6149 current_operation_id=nslcmop_id,
6150 )
quilesj4cda56b2019-12-05 10:02:20 +00006151
ikalyvas02d9e7b2019-05-27 18:16:01 +03006152 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006153 self.logger.debug(
6154 step + " after having waited for previous tasks to be completed"
6155 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006156 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006157
ikalyvas02d9e7b2019-05-27 18:16:01 +03006158 step = "Getting nsr from database"
6159 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006160 old_operational_status = db_nsr["operational-status"]
6161 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006162
tierno59d22d22018-09-25 18:10:19 +02006163 step = "Parsing scaling parameters"
6164 db_nsr_update["operational-status"] = "scaling"
6165 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006166 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006167
garciadeblas5697b8b2021-03-24 09:17:02 +01006168 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6169 "scaleByStepData"
6170 ]["member-vnf-index"]
6171 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6172 "scaleByStepData"
6173 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006174 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006175 # for backward compatibility
6176 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6177 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6178 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6179 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6180
tierno59d22d22018-09-25 18:10:19 +02006181 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006182 db_vnfr = self.db.get_one(
6183 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6184 )
bravof922c4172020-11-24 21:21:43 -03006185
David Garciac1fe90a2021-03-31 19:12:02 +02006186 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6187
tierno59d22d22018-09-25 18:10:19 +02006188 step = "Getting vnfd from database"
6189 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006190
aktas13251562021-02-12 22:19:10 +03006191 base_folder = db_vnfd["_admin"]["storage"]
6192
tierno59d22d22018-09-25 18:10:19 +02006193 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006194 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006195 get_scaling_aspect(db_vnfd),
6196 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006197 )
6198 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006199 raise LcmException(
6200 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6201 "at vnfd:scaling-group-descriptor".format(scaling_group)
6202 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006203
tierno15b1cf12019-08-29 13:21:40 +00006204 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006205 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006206 nb_scale_op = 0
6207 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006208 self.update_db_2(
6209 "nsrs",
6210 nsr_id,
6211 {
6212 "_admin.scaling-group": [
6213 {"name": scaling_group, "nb-scale-op": 0}
6214 ]
6215 },
6216 )
tierno59d22d22018-09-25 18:10:19 +02006217 admin_scale_index = 0
6218 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006219 for admin_scale_index, admin_scale_info in enumerate(
6220 db_nsr["_admin"]["scaling-group"]
6221 ):
tierno59d22d22018-09-25 18:10:19 +02006222 if admin_scale_info["name"] == scaling_group:
6223 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6224 break
tierno9ab95942018-10-10 16:44:22 +02006225 else: # not found, set index one plus last element and add new entry with the name
6226 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006227 db_nsr_update[
6228 "_admin.scaling-group.{}.name".format(admin_scale_index)
6229 ] = scaling_group
aktas5f75f102021-03-15 11:26:10 +03006230
6231 vca_scaling_info = []
6232 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006233 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006234 if "aspect-delta-details" not in scaling_descriptor:
6235 raise LcmException(
6236 "Aspect delta details not fount in scaling descriptor {}".format(
6237 scaling_descriptor["name"]
6238 )
6239 )
tierno59d22d22018-09-25 18:10:19 +02006240 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006241 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006242
aktas5f75f102021-03-15 11:26:10 +03006243 scaling_info["scaling_direction"] = "OUT"
6244 scaling_info["vdu-create"] = {}
6245 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006246 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006247 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006248 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006249 # vdu_index also provides the number of instance of the targeted vdu
6250 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
garciadeblas5697b8b2021-03-24 09:17:02 +01006251 cloud_init_text = self._get_vdu_cloud_init_content(
6252 vdud, db_vnfd
6253 )
tierno72ef84f2020-10-06 08:22:07 +00006254 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006255 additional_params = (
6256 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6257 or {}
6258 )
bravof832f8992020-12-07 12:57:31 -03006259 cloud_init_list = []
6260
6261 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6262 max_instance_count = 10
6263 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006264 max_instance_count = vdu_profile.get(
6265 "max-number-of-instances", 10
6266 )
6267
6268 default_instance_num = get_number_of_instances(
6269 db_vnfd, vdud["id"]
6270 )
aktas5f75f102021-03-15 11:26:10 +03006271 instances_number = vdu_delta.get("number-of-instances", 1)
6272 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006273
aktas5f75f102021-03-15 11:26:10 +03006274 new_instance_count = nb_scale_op + default_instance_num
6275 # Control if new count is over max and vdu count is less than max.
6276 # Then assign new instance count
6277 if new_instance_count > max_instance_count > vdu_count:
6278 instances_number = new_instance_count - max_instance_count
6279 else:
6280 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006281
aktas5f75f102021-03-15 11:26:10 +03006282 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006283 raise LcmException(
6284 "reached the limit of {} (max-instance-count) "
6285 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006286 "scaling-group-descriptor '{}'".format(
6287 nb_scale_op, scaling_group
6288 )
bravof922c4172020-11-24 21:21:43 -03006289 )
bravof832f8992020-12-07 12:57:31 -03006290 for x in range(vdu_delta.get("number-of-instances", 1)):
6291 if cloud_init_text:
6292 # TODO Information of its own ip is not available because db_vnfr is not updated.
6293 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006294 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006295 )
bravof832f8992020-12-07 12:57:31 -03006296 cloud_init_list.append(
6297 self._parse_cloud_init(
6298 cloud_init_text,
6299 additional_params,
6300 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006301 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006302 )
6303 )
aktas5f75f102021-03-15 11:26:10 +03006304 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006305 {
6306 "osm_vdu_id": vdu_delta["id"],
6307 "member-vnf-index": vnf_index,
6308 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006309 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006310 }
6311 )
aktas5f75f102021-03-15 11:26:10 +03006312 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6313 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006314 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006315 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006316 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006317
6318 # Might have different kdus in the same delta
6319 # Should have list for each kdu
6320 if not scaling_info["kdu-create"].get(kdu_name, None):
6321 scaling_info["kdu-create"][kdu_name] = []
6322
6323 kdur = get_kdur(db_vnfr, kdu_name)
6324 if kdur.get("helm-chart"):
6325 k8s_cluster_type = "helm-chart-v3"
6326 self.logger.debug("kdur: {}".format(kdur))
6327 if (
6328 kdur.get("helm-version")
6329 and kdur.get("helm-version") == "v2"
6330 ):
6331 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006332 elif kdur.get("juju-bundle"):
6333 k8s_cluster_type = "juju-bundle"
6334 else:
6335 raise LcmException(
6336 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6337 "juju-bundle. Maybe an old NBI version is running".format(
6338 db_vnfr["member-vnf-index-ref"], kdu_name
6339 )
6340 )
6341
6342 max_instance_count = 10
6343 if kdu_profile and "max-number-of-instances" in kdu_profile:
6344 max_instance_count = kdu_profile.get(
6345 "max-number-of-instances", 10
6346 )
6347
6348 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6349 deployed_kdu, _ = get_deployed_kdu(
6350 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006351 )
aktas5f75f102021-03-15 11:26:10 +03006352 if deployed_kdu is None:
6353 raise LcmException(
6354 "KDU '{}' for vnf '{}' not deployed".format(
6355 kdu_name, vnf_index
6356 )
6357 )
6358 kdu_instance = deployed_kdu.get("kdu-instance")
6359 instance_num = await self.k8scluster_map[
6360 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006361 ].get_scale_count(
6362 resource_name,
6363 kdu_instance,
6364 vca_id=vca_id,
6365 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6366 kdu_model=deployed_kdu.get("kdu-model"),
6367 )
aktas5f75f102021-03-15 11:26:10 +03006368 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006369 "number-of-instances", 1
6370 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006371
aktas5f75f102021-03-15 11:26:10 +03006372 # Control if new count is over max and instance_num is less than max.
6373 # Then assign max instance number to kdu replica count
6374 if kdu_replica_count > max_instance_count > instance_num:
6375 kdu_replica_count = max_instance_count
6376 if kdu_replica_count > max_instance_count:
6377 raise LcmException(
6378 "reached the limit of {} (max-instance-count) "
6379 "scaling-out operations for the "
6380 "scaling-group-descriptor '{}'".format(
6381 instance_num, scaling_group
6382 )
6383 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006384
aktas5f75f102021-03-15 11:26:10 +03006385 for x in range(kdu_delta.get("number-of-instances", 1)):
6386 vca_scaling_info.append(
6387 {
6388 "osm_kdu_id": kdu_name,
6389 "member-vnf-index": vnf_index,
6390 "type": "create",
6391 "kdu_index": instance_num + x - 1,
6392 }
6393 )
6394 scaling_info["kdu-create"][kdu_name].append(
6395 {
6396 "member-vnf-index": vnf_index,
6397 "type": "create",
6398 "k8s-cluster-type": k8s_cluster_type,
6399 "resource-name": resource_name,
6400 "scale": kdu_replica_count,
6401 }
6402 )
6403 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006404 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006405
6406 scaling_info["scaling_direction"] = "IN"
6407 scaling_info["vdu-delete"] = {}
6408 scaling_info["kdu-delete"] = {}
6409
bravof832f8992020-12-07 12:57:31 -03006410 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006411 for vdu_delta in delta.get("vdu-delta", {}):
6412 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006413 min_instance_count = 0
6414 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6415 if vdu_profile and "min-number-of-instances" in vdu_profile:
6416 min_instance_count = vdu_profile["min-number-of-instances"]
6417
garciadeblas5697b8b2021-03-24 09:17:02 +01006418 default_instance_num = get_number_of_instances(
6419 db_vnfd, vdu_delta["id"]
6420 )
aktas5f75f102021-03-15 11:26:10 +03006421 instance_num = vdu_delta.get("number-of-instances", 1)
6422 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006423
aktas5f75f102021-03-15 11:26:10 +03006424 new_instance_count = nb_scale_op + default_instance_num
6425
6426 if new_instance_count < min_instance_count < vdu_count:
6427 instances_number = min_instance_count - new_instance_count
6428 else:
6429 instances_number = instance_num
6430
6431 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006432 raise LcmException(
6433 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006434 "scaling-group-descriptor '{}'".format(
6435 nb_scale_op, scaling_group
6436 )
bravof832f8992020-12-07 12:57:31 -03006437 )
aktas13251562021-02-12 22:19:10 +03006438 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006439 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006440 {
6441 "osm_vdu_id": vdu_delta["id"],
6442 "member-vnf-index": vnf_index,
6443 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006444 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006445 }
6446 )
aktas5f75f102021-03-15 11:26:10 +03006447 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6448 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006449 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006450 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006451 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006452
6453 if not scaling_info["kdu-delete"].get(kdu_name, None):
6454 scaling_info["kdu-delete"][kdu_name] = []
6455
6456 kdur = get_kdur(db_vnfr, kdu_name)
6457 if kdur.get("helm-chart"):
6458 k8s_cluster_type = "helm-chart-v3"
6459 self.logger.debug("kdur: {}".format(kdur))
6460 if (
6461 kdur.get("helm-version")
6462 and kdur.get("helm-version") == "v2"
6463 ):
6464 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006465 elif kdur.get("juju-bundle"):
6466 k8s_cluster_type = "juju-bundle"
6467 else:
6468 raise LcmException(
6469 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6470 "juju-bundle. Maybe an old NBI version is running".format(
6471 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6472 )
6473 )
6474
6475 min_instance_count = 0
6476 if kdu_profile and "min-number-of-instances" in kdu_profile:
6477 min_instance_count = kdu_profile["min-number-of-instances"]
6478
6479 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6480 deployed_kdu, _ = get_deployed_kdu(
6481 nsr_deployed, kdu_name, vnf_index
6482 )
6483 if deployed_kdu is None:
6484 raise LcmException(
6485 "KDU '{}' for vnf '{}' not deployed".format(
6486 kdu_name, vnf_index
6487 )
6488 )
6489 kdu_instance = deployed_kdu.get("kdu-instance")
6490 instance_num = await self.k8scluster_map[
6491 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006492 ].get_scale_count(
6493 resource_name,
6494 kdu_instance,
6495 vca_id=vca_id,
6496 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6497 kdu_model=deployed_kdu.get("kdu-model"),
6498 )
aktas5f75f102021-03-15 11:26:10 +03006499 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006500 "number-of-instances", 1
6501 )
tierno59d22d22018-09-25 18:10:19 +02006502
aktas5f75f102021-03-15 11:26:10 +03006503 if kdu_replica_count < min_instance_count < instance_num:
6504 kdu_replica_count = min_instance_count
6505 if kdu_replica_count < min_instance_count:
6506 raise LcmException(
6507 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6508 "scaling-group-descriptor '{}'".format(
6509 instance_num, scaling_group
6510 )
6511 )
6512
6513 for x in range(kdu_delta.get("number-of-instances", 1)):
6514 vca_scaling_info.append(
6515 {
6516 "osm_kdu_id": kdu_name,
6517 "member-vnf-index": vnf_index,
6518 "type": "delete",
6519 "kdu_index": instance_num - x - 1,
6520 }
6521 )
6522 scaling_info["kdu-delete"][kdu_name].append(
6523 {
6524 "member-vnf-index": vnf_index,
6525 "type": "delete",
6526 "k8s-cluster-type": k8s_cluster_type,
6527 "resource-name": resource_name,
6528 "scale": kdu_replica_count,
6529 }
6530 )
6531
tierno59d22d22018-09-25 18:10:19 +02006532 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006533 vdu_delete = copy(scaling_info.get("vdu-delete"))
6534 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006535 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006536 if vdu_delete.get(vdur["vdu-id-ref"]):
6537 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006538 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006539 {
6540 "name": vdur.get("name") or vdur.get("vdu-name"),
6541 "vdu_id": vdur["vdu-id-ref"],
6542 "interface": [],
6543 }
6544 )
tierno59d22d22018-09-25 18:10:19 +02006545 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006546 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006547 {
6548 "name": interface["name"],
6549 "ip_address": interface["ip-address"],
6550 "mac_address": interface.get("mac-address"),
6551 }
6552 )
tierno2357f4e2020-10-19 16:38:59 +00006553 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006554
kuuseac3a8882019-10-03 10:48:06 +02006555 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006556 step = "Executing pre-scale vnf-config-primitive"
6557 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006558 for scaling_config_action in scaling_descriptor[
6559 "scaling-config-action"
6560 ]:
6561 if (
6562 scaling_config_action.get("trigger") == "pre-scale-in"
6563 and scaling_type == "SCALE_IN"
6564 ) or (
6565 scaling_config_action.get("trigger") == "pre-scale-out"
6566 and scaling_type == "SCALE_OUT"
6567 ):
6568 vnf_config_primitive = scaling_config_action[
6569 "vnf-config-primitive-name-ref"
6570 ]
6571 step = db_nslcmop_update[
6572 "detailed-status"
6573 ] = "executing pre-scale scaling-config-action '{}'".format(
6574 vnf_config_primitive
6575 )
tiernoda964822019-01-14 15:53:47 +00006576
tierno59d22d22018-09-25 18:10:19 +02006577 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006578 for config_primitive in (
6579 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6580 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006581 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006582 break
6583 else:
6584 raise LcmException(
6585 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006586 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006587 "primitive".format(scaling_group, vnf_config_primitive)
6588 )
tiernoda964822019-01-14 15:53:47 +00006589
aktas5f75f102021-03-15 11:26:10 +03006590 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006591 if db_vnfr.get("additionalParamsForVnf"):
6592 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006593
tierno9ab95942018-10-10 16:44:22 +02006594 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006595 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006596 primitive_params = self._map_primitive_params(
6597 config_primitive, {}, vnfr_params
6598 )
kuuseac3a8882019-10-03 10:48:06 +02006599
tierno7c4e24c2020-05-13 08:41:35 +00006600 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006601 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006602 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006603 vnf_index,
6604 vnf_config_primitive,
6605 primitive_params,
6606 "PRE-SCALE",
6607 )
tierno7c4e24c2020-05-13 08:41:35 +00006608 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006609 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006610 result = "COMPLETED"
6611 result_detail = "Done"
6612 self.logger.debug(
6613 logging_text
6614 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6615 vnf_config_primitive, result, result_detail
6616 )
6617 )
kuuseac3a8882019-10-03 10:48:06 +02006618 else:
tierno7c4e24c2020-05-13 08:41:35 +00006619 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006620 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006621 op_index = (
6622 len(db_nslcmop.get("_admin", {}).get("operations"))
6623 - 1
6624 )
6625 self.logger.debug(
6626 logging_text
6627 + "vnf_config_primitive={} New sub-operation".format(
6628 vnf_config_primitive
6629 )
6630 )
kuuseac3a8882019-10-03 10:48:06 +02006631 else:
tierno7c4e24c2020-05-13 08:41:35 +00006632 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006633 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6634 op_index
6635 ]
6636 vnf_index = op.get("member_vnf_index")
6637 vnf_config_primitive = op.get("primitive")
6638 primitive_params = op.get("primitive_params")
6639 self.logger.debug(
6640 logging_text
6641 + "vnf_config_primitive={} Sub-operation retry".format(
6642 vnf_config_primitive
6643 )
6644 )
tierno588547c2020-07-01 15:30:20 +00006645 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006646 ee_descriptor_id = config_primitive.get(
6647 "execution-environment-ref"
6648 )
6649 primitive_name = config_primitive.get(
6650 "execution-environment-primitive", vnf_config_primitive
6651 )
6652 ee_id, vca_type = self._look_for_deployed_vca(
6653 nsr_deployed["VCA"],
6654 member_vnf_index=vnf_index,
6655 vdu_id=None,
6656 vdu_count_index=None,
6657 ee_descriptor_id=ee_descriptor_id,
6658 )
kuuseac3a8882019-10-03 10:48:06 +02006659 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006660 ee_id,
6661 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006662 primitive_params,
6663 vca_type=vca_type,
6664 vca_id=vca_id,
6665 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006666 self.logger.debug(
6667 logging_text
6668 + "vnf_config_primitive={} Done with result {} {}".format(
6669 vnf_config_primitive, result, result_detail
6670 )
6671 )
kuuseac3a8882019-10-03 10:48:06 +02006672 # Update operationState = COMPLETED | FAILED
6673 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006674 db_nslcmop, op_index, result, result_detail
6675 )
kuuseac3a8882019-10-03 10:48:06 +02006676
tierno59d22d22018-09-25 18:10:19 +02006677 if result == "FAILED":
6678 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006679 db_nsr_update["config-status"] = old_config_status
6680 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006681 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006682
garciadeblas5697b8b2021-03-24 09:17:02 +01006683 db_nsr_update[
6684 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6685 ] = nb_scale_op
6686 db_nsr_update[
6687 "_admin.scaling-group.{}.time".format(admin_scale_index)
6688 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006689
aktas13251562021-02-12 22:19:10 +03006690 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006691 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006692 step = db_nslcmop_update[
6693 "detailed-status"
6694 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03006695 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006696 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006697 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006698 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01006699 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03006700 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01006701 )
aktas5f75f102021-03-15 11:26:10 +03006702 if vca_info.get("osm_vdu_id"):
6703 vdu_id = vca_info["osm_vdu_id"]
6704 vdu_index = int(vca_info["vdu_index"])
6705 stage[
6706 1
6707 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
6708 member_vnf_index, vdu_id, vdu_index
6709 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006710 stage[2] = step = "Scaling in VCA"
6711 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03006712 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
6713 config_update = db_nsr["configurationStatus"]
6714 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01006715 if (
6716 (vca or vca.get("ee_id"))
6717 and vca["member-vnf-index"] == member_vnf_index
6718 and vca["vdu_count_index"] == vdu_index
6719 ):
aktas13251562021-02-12 22:19:10 +03006720 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006721 config_descriptor = get_configuration(
6722 db_vnfd, vca.get("vdu_id")
6723 )
aktas13251562021-02-12 22:19:10 +03006724 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006725 config_descriptor = get_configuration(
6726 db_vnfd, vca.get("kdu_name")
6727 )
aktas13251562021-02-12 22:19:10 +03006728 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006729 config_descriptor = get_configuration(
6730 db_vnfd, db_vnfd["id"]
6731 )
6732 operation_params = (
6733 db_nslcmop.get("operationParams") or {}
6734 )
6735 exec_terminate_primitives = not operation_params.get(
6736 "skip_terminate_primitives"
6737 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02006738 task = asyncio.ensure_future(
6739 asyncio.wait_for(
6740 self.destroy_N2VC(
6741 logging_text,
6742 db_nslcmop,
6743 vca,
6744 config_descriptor,
6745 vca_index,
6746 destroy_ee=True,
6747 exec_primitives=exec_terminate_primitives,
6748 scaling_in=True,
6749 vca_id=vca_id,
6750 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01006751 timeout=self.timeout_charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02006752 )
6753 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006754 tasks_dict_info[task] = "Terminating VCA {}".format(
6755 vca.get("ee_id")
6756 )
aktas13251562021-02-12 22:19:10 +03006757 del vca_update[vca_index]
6758 del config_update[vca_index]
6759 # wait for pending tasks of terminate primitives
6760 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006761 self.logger.debug(
6762 logging_text
6763 + "Waiting for tasks {}".format(
6764 list(tasks_dict_info.keys())
6765 )
6766 )
6767 error_list = await self._wait_for_tasks(
6768 logging_text,
6769 tasks_dict_info,
6770 min(
6771 self.timeout_charm_delete, self.timeout_ns_terminate
6772 ),
6773 stage,
6774 nslcmop_id,
6775 )
aktas13251562021-02-12 22:19:10 +03006776 tasks_dict_info.clear()
6777 if error_list:
6778 raise LcmException("; ".join(error_list))
6779
6780 db_vca_and_config_update = {
6781 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01006782 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03006783 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006784 self.update_db_2(
6785 "nsrs", db_nsr["_id"], db_vca_and_config_update
6786 )
aktas13251562021-02-12 22:19:10 +03006787 scale_process = None
6788 # SCALE-IN VCA - END
6789
kuuseac3a8882019-10-03 10:48:06 +02006790 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006791 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02006792 scale_process = "RO"
tierno2357f4e2020-10-19 16:38:59 +00006793 if self.ro_config.get("ng"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006794 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03006795 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01006796 )
aktas5f75f102021-03-15 11:26:10 +03006797 scaling_info.pop("vdu-create", None)
6798 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02006799
tierno9ab95942018-10-10 16:44:22 +02006800 scale_process = None
aktas13251562021-02-12 22:19:10 +03006801 # SCALE RO - END
6802
aktas5f75f102021-03-15 11:26:10 +03006803 # SCALE KDU - BEGIN
6804 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
6805 scale_process = "KDU"
6806 await self._scale_kdu(
6807 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
6808 )
6809 scaling_info.pop("kdu-create", None)
6810 scaling_info.pop("kdu-delete", None)
6811
6812 scale_process = None
6813 # SCALE KDU - END
6814
6815 if db_nsr_update:
6816 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6817
aktas13251562021-02-12 22:19:10 +03006818 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006819 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006820 step = db_nslcmop_update[
6821 "detailed-status"
6822 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03006823 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006824 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006825 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006826 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01006827 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03006828 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01006829 )
aktas13251562021-02-12 22:19:10 +03006830 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03006831 if vca_info.get("osm_vdu_id"):
6832 vdu_index = int(vca_info["vdu_index"])
6833 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6834 if db_vnfr.get("additionalParamsForVnf"):
6835 deploy_params.update(
6836 parse_yaml_strings(
6837 db_vnfr["additionalParamsForVnf"].copy()
6838 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006839 )
aktas5f75f102021-03-15 11:26:10 +03006840 descriptor_config = get_configuration(
6841 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01006842 )
aktas5f75f102021-03-15 11:26:10 +03006843 if descriptor_config:
6844 vdu_id = None
6845 vdu_name = None
6846 kdu_name = None
6847 self._deploy_n2vc(
6848 logging_text=logging_text
6849 + "member_vnf_index={} ".format(member_vnf_index),
6850 db_nsr=db_nsr,
6851 db_vnfr=db_vnfr,
6852 nslcmop_id=nslcmop_id,
6853 nsr_id=nsr_id,
6854 nsi_id=nsi_id,
6855 vnfd_id=vnfd_id,
6856 vdu_id=vdu_id,
6857 kdu_name=kdu_name,
6858 member_vnf_index=member_vnf_index,
6859 vdu_index=vdu_index,
6860 vdu_name=vdu_name,
6861 deploy_params=deploy_params,
6862 descriptor_config=descriptor_config,
6863 base_folder=base_folder,
6864 task_instantiation_info=tasks_dict_info,
6865 stage=stage,
6866 )
6867 vdu_id = vca_info["osm_vdu_id"]
6868 vdur = find_in_list(
6869 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03006870 )
aktas5f75f102021-03-15 11:26:10 +03006871 descriptor_config = get_configuration(db_vnfd, vdu_id)
6872 if vdur.get("additionalParams"):
6873 deploy_params_vdu = parse_yaml_strings(
6874 vdur["additionalParams"]
6875 )
6876 else:
6877 deploy_params_vdu = deploy_params
6878 deploy_params_vdu["OSM"] = get_osm_params(
6879 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01006880 )
aktas5f75f102021-03-15 11:26:10 +03006881 if descriptor_config:
6882 vdu_name = None
6883 kdu_name = None
6884 stage[
6885 1
6886 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01006887 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03006888 )
6889 stage[2] = step = "Scaling out VCA"
6890 self._write_op_status(op_id=nslcmop_id, stage=stage)
6891 self._deploy_n2vc(
6892 logging_text=logging_text
6893 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
6894 member_vnf_index, vdu_id, vdu_index
6895 ),
6896 db_nsr=db_nsr,
6897 db_vnfr=db_vnfr,
6898 nslcmop_id=nslcmop_id,
6899 nsr_id=nsr_id,
6900 nsi_id=nsi_id,
6901 vnfd_id=vnfd_id,
6902 vdu_id=vdu_id,
6903 kdu_name=kdu_name,
6904 member_vnf_index=member_vnf_index,
6905 vdu_index=vdu_index,
6906 vdu_name=vdu_name,
6907 deploy_params=deploy_params_vdu,
6908 descriptor_config=descriptor_config,
6909 base_folder=base_folder,
6910 task_instantiation_info=tasks_dict_info,
6911 stage=stage,
6912 )
aktas13251562021-02-12 22:19:10 +03006913 # SCALE-UP VCA - END
6914 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02006915
kuuseac3a8882019-10-03 10:48:06 +02006916 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006917 # execute primitive service POST-SCALING
6918 step = "Executing post-scale vnf-config-primitive"
6919 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006920 for scaling_config_action in scaling_descriptor[
6921 "scaling-config-action"
6922 ]:
6923 if (
6924 scaling_config_action.get("trigger") == "post-scale-in"
6925 and scaling_type == "SCALE_IN"
6926 ) or (
6927 scaling_config_action.get("trigger") == "post-scale-out"
6928 and scaling_type == "SCALE_OUT"
6929 ):
6930 vnf_config_primitive = scaling_config_action[
6931 "vnf-config-primitive-name-ref"
6932 ]
6933 step = db_nslcmop_update[
6934 "detailed-status"
6935 ] = "executing post-scale scaling-config-action '{}'".format(
6936 vnf_config_primitive
6937 )
tiernoda964822019-01-14 15:53:47 +00006938
aktas5f75f102021-03-15 11:26:10 +03006939 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006940 if db_vnfr.get("additionalParamsForVnf"):
6941 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
6942
tierno59d22d22018-09-25 18:10:19 +02006943 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03006944 for config_primitive in (
6945 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6946 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006947 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006948 break
6949 else:
tiernoa278b842020-07-08 15:33:55 +00006950 raise LcmException(
6951 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
6952 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01006953 "config-primitive".format(
6954 scaling_group, vnf_config_primitive
6955 )
6956 )
tierno9ab95942018-10-10 16:44:22 +02006957 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006958 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006959 primitive_params = self._map_primitive_params(
6960 config_primitive, {}, vnfr_params
6961 )
tiernod6de1992018-10-11 13:05:52 +02006962
tierno7c4e24c2020-05-13 08:41:35 +00006963 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006964 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006965 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006966 vnf_index,
6967 vnf_config_primitive,
6968 primitive_params,
6969 "POST-SCALE",
6970 )
quilesj4cda56b2019-12-05 10:02:20 +00006971 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006972 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006973 result = "COMPLETED"
6974 result_detail = "Done"
6975 self.logger.debug(
6976 logging_text
6977 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6978 vnf_config_primitive, result, result_detail
6979 )
6980 )
kuuseac3a8882019-10-03 10:48:06 +02006981 else:
quilesj4cda56b2019-12-05 10:02:20 +00006982 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006983 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006984 op_index = (
6985 len(db_nslcmop.get("_admin", {}).get("operations"))
6986 - 1
6987 )
6988 self.logger.debug(
6989 logging_text
6990 + "vnf_config_primitive={} New sub-operation".format(
6991 vnf_config_primitive
6992 )
6993 )
kuuseac3a8882019-10-03 10:48:06 +02006994 else:
tierno7c4e24c2020-05-13 08:41:35 +00006995 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006996 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6997 op_index
6998 ]
6999 vnf_index = op.get("member_vnf_index")
7000 vnf_config_primitive = op.get("primitive")
7001 primitive_params = op.get("primitive_params")
7002 self.logger.debug(
7003 logging_text
7004 + "vnf_config_primitive={} Sub-operation retry".format(
7005 vnf_config_primitive
7006 )
7007 )
tierno588547c2020-07-01 15:30:20 +00007008 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007009 ee_descriptor_id = config_primitive.get(
7010 "execution-environment-ref"
7011 )
7012 primitive_name = config_primitive.get(
7013 "execution-environment-primitive", vnf_config_primitive
7014 )
7015 ee_id, vca_type = self._look_for_deployed_vca(
7016 nsr_deployed["VCA"],
7017 member_vnf_index=vnf_index,
7018 vdu_id=None,
7019 vdu_count_index=None,
7020 ee_descriptor_id=ee_descriptor_id,
7021 )
kuuseac3a8882019-10-03 10:48:06 +02007022 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007023 ee_id,
7024 primitive_name,
7025 primitive_params,
7026 vca_type=vca_type,
7027 vca_id=vca_id,
7028 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007029 self.logger.debug(
7030 logging_text
7031 + "vnf_config_primitive={} Done with result {} {}".format(
7032 vnf_config_primitive, result, result_detail
7033 )
7034 )
kuuseac3a8882019-10-03 10:48:06 +02007035 # Update operationState = COMPLETED | FAILED
7036 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007037 db_nslcmop, op_index, result, result_detail
7038 )
kuuseac3a8882019-10-03 10:48:06 +02007039
tierno59d22d22018-09-25 18:10:19 +02007040 if result == "FAILED":
7041 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007042 db_nsr_update["config-status"] = old_config_status
7043 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007044 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007045
garciadeblas5697b8b2021-03-24 09:17:02 +01007046 db_nsr_update[
7047 "detailed-status"
7048 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7049 db_nsr_update["operational-status"] = (
7050 "running"
7051 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007052 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007053 )
tiernod6de1992018-10-11 13:05:52 +02007054 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007055 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007056 except (
7057 ROclient.ROClientException,
7058 DbException,
7059 LcmException,
7060 NgRoException,
7061 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007062 self.logger.error(logging_text + "Exit Exception {}".format(e))
7063 exc = e
7064 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007065 self.logger.error(
7066 logging_text + "Cancelled Exception while '{}'".format(step)
7067 )
tierno59d22d22018-09-25 18:10:19 +02007068 exc = "Operation was cancelled"
7069 except Exception as e:
7070 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007071 self.logger.critical(
7072 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7073 exc_info=True,
7074 )
tierno59d22d22018-09-25 18:10:19 +02007075 finally:
garciadeblas5697b8b2021-03-24 09:17:02 +01007076 self._write_ns_status(
7077 nsr_id=nsr_id,
7078 ns_state=None,
7079 current_operation="IDLE",
7080 current_operation_id=None,
7081 )
aktas13251562021-02-12 22:19:10 +03007082 if tasks_dict_info:
7083 stage[1] = "Waiting for instantiate pending tasks."
7084 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01007085 exc = await self._wait_for_tasks(
7086 logging_text,
7087 tasks_dict_info,
7088 self.timeout_ns_deploy,
7089 stage,
7090 nslcmop_id,
7091 nsr_id=nsr_id,
7092 )
tierno59d22d22018-09-25 18:10:19 +02007093 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01007094 db_nslcmop_update[
7095 "detailed-status"
7096 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tiernoa17d4f42020-04-28 09:59:23 +00007097 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007098 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007099 db_nsr_update["operational-status"] = old_operational_status
7100 db_nsr_update["config-status"] = old_config_status
7101 db_nsr_update["detailed-status"] = ""
7102 if scale_process:
7103 if "VCA" in scale_process:
7104 db_nsr_update["config-status"] = "failed"
7105 if "RO" in scale_process:
7106 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007107 db_nsr_update[
7108 "detailed-status"
7109 ] = "FAILED scaling nslcmop={} {}: {}".format(
7110 nslcmop_id, step, exc
7111 )
tiernoa17d4f42020-04-28 09:59:23 +00007112 else:
7113 error_description_nslcmop = None
7114 nslcmop_operation_state = "COMPLETED"
7115 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00007116
garciadeblas5697b8b2021-03-24 09:17:02 +01007117 self._write_op_status(
7118 op_id=nslcmop_id,
7119 stage="",
7120 error_message=error_description_nslcmop,
7121 operation_state=nslcmop_operation_state,
7122 other_update=db_nslcmop_update,
7123 )
tiernoa17d4f42020-04-28 09:59:23 +00007124 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007125 self._write_ns_status(
7126 nsr_id=nsr_id,
7127 ns_state=None,
7128 current_operation="IDLE",
7129 current_operation_id=None,
7130 other_update=db_nsr_update,
7131 )
tiernoa17d4f42020-04-28 09:59:23 +00007132
tierno59d22d22018-09-25 18:10:19 +02007133 if nslcmop_operation_state:
7134 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007135 msg = {
7136 "nsr_id": nsr_id,
7137 "nslcmop_id": nslcmop_id,
7138 "operationState": nslcmop_operation_state,
7139 }
bravof922c4172020-11-24 21:21:43 -03007140 await self.msg.aiowrite("ns", "scaled", msg, loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02007141 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007142 self.logger.error(
7143 logging_text + "kafka_write notification Exception {}".format(e)
7144 )
tierno59d22d22018-09-25 18:10:19 +02007145 self.logger.debug(logging_text + "Exit")
7146 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007147
aktas5f75f102021-03-15 11:26:10 +03007148 async def _scale_kdu(
7149 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7150 ):
7151 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7152 for kdu_name in _scaling_info:
7153 for kdu_scaling_info in _scaling_info[kdu_name]:
7154 deployed_kdu, index = get_deployed_kdu(
7155 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7156 )
7157 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7158 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007159 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007160 scale = int(kdu_scaling_info["scale"])
7161 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7162
7163 db_dict = {
7164 "collection": "nsrs",
7165 "filter": {"_id": nsr_id},
7166 "path": "_admin.deployed.K8s.{}".format(index),
7167 }
7168
7169 step = "scaling application {}".format(
7170 kdu_scaling_info["resource-name"]
7171 )
7172 self.logger.debug(logging_text + step)
7173
7174 if kdu_scaling_info["type"] == "delete":
7175 kdu_config = get_configuration(db_vnfd, kdu_name)
7176 if (
7177 kdu_config
7178 and kdu_config.get("terminate-config-primitive")
7179 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7180 ):
7181 terminate_config_primitive_list = kdu_config.get(
7182 "terminate-config-primitive"
7183 )
7184 terminate_config_primitive_list.sort(
7185 key=lambda val: int(val["seq"])
7186 )
7187
7188 for (
7189 terminate_config_primitive
7190 ) in terminate_config_primitive_list:
7191 primitive_params_ = self._map_primitive_params(
7192 terminate_config_primitive, {}, {}
7193 )
7194 step = "execute terminate config primitive"
7195 self.logger.debug(logging_text + step)
7196 await asyncio.wait_for(
7197 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7198 cluster_uuid=cluster_uuid,
7199 kdu_instance=kdu_instance,
7200 primitive_name=terminate_config_primitive["name"],
7201 params=primitive_params_,
7202 db_dict=db_dict,
7203 vca_id=vca_id,
7204 ),
7205 timeout=600,
7206 )
7207
7208 await asyncio.wait_for(
7209 self.k8scluster_map[k8s_cluster_type].scale(
7210 kdu_instance,
7211 scale,
7212 kdu_scaling_info["resource-name"],
7213 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007214 cluster_uuid=cluster_uuid,
7215 kdu_model=kdu_model,
7216 atomic=True,
7217 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007218 ),
7219 timeout=self.timeout_vca_on_error,
7220 )
7221
7222 if kdu_scaling_info["type"] == "create":
7223 kdu_config = get_configuration(db_vnfd, kdu_name)
7224 if (
7225 kdu_config
7226 and kdu_config.get("initial-config-primitive")
7227 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7228 ):
7229 initial_config_primitive_list = kdu_config.get(
7230 "initial-config-primitive"
7231 )
7232 initial_config_primitive_list.sort(
7233 key=lambda val: int(val["seq"])
7234 )
7235
7236 for initial_config_primitive in initial_config_primitive_list:
7237 primitive_params_ = self._map_primitive_params(
7238 initial_config_primitive, {}, {}
7239 )
7240 step = "execute initial config primitive"
7241 self.logger.debug(logging_text + step)
7242 await asyncio.wait_for(
7243 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7244 cluster_uuid=cluster_uuid,
7245 kdu_instance=kdu_instance,
7246 primitive_name=initial_config_primitive["name"],
7247 params=primitive_params_,
7248 db_dict=db_dict,
7249 vca_id=vca_id,
7250 ),
7251 timeout=600,
7252 )
7253
garciadeblas5697b8b2021-03-24 09:17:02 +01007254 async def _scale_ng_ro(
7255 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7256 ):
tierno2357f4e2020-10-19 16:38:59 +00007257 nsr_id = db_nslcmop["nsInstanceId"]
7258 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7259 db_vnfrs = {}
7260
7261 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007262 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007263
7264 # for each vnf in ns, read vnfd
7265 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7266 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7267 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007268 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007269 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007270 # read from db
7271 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007272 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007273 n2vc_key = self.n2vc.get_public_key()
7274 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007275 self.scale_vnfr(
7276 db_vnfr,
7277 vdu_scaling_info.get("vdu-create"),
7278 vdu_scaling_info.get("vdu-delete"),
7279 mark_delete=True,
7280 )
tierno2357f4e2020-10-19 16:38:59 +00007281 # db_vnfr has been updated, update db_vnfrs to use it
7282 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007283 await self._instantiate_ng_ro(
7284 logging_text,
7285 nsr_id,
7286 db_nsd,
7287 db_nsr,
7288 db_nslcmop,
7289 db_vnfrs,
7290 db_vnfds,
7291 n2vc_key_list,
7292 stage=stage,
7293 start_deploy=time(),
7294 timeout_ns_deploy=self.timeout_ns_deploy,
7295 )
tierno2357f4e2020-10-19 16:38:59 +00007296 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007297 self.scale_vnfr(
7298 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7299 )
tierno2357f4e2020-10-19 16:38:59 +00007300
bravof73bac502021-05-11 07:38:47 -04007301 async def extract_prometheus_scrape_jobs(
aticig15db6142022-01-24 12:51:26 +03007302 self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip
garciadeblas5697b8b2021-03-24 09:17:02 +01007303 ):
tiernob996d942020-07-03 14:52:28 +00007304 # look if exist a file called 'prometheus*.j2' and
7305 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007306 job_file = next(
7307 (
7308 f
7309 for f in artifact_content
7310 if f.startswith("prometheus") and f.endswith(".j2")
7311 ),
7312 None,
7313 )
tiernob996d942020-07-03 14:52:28 +00007314 if not job_file:
7315 return
7316 with self.fs.file_open((artifact_path, job_file), "r") as f:
7317 job_data = f.read()
7318
7319 # TODO get_service
garciadeblas5697b8b2021-03-24 09:17:02 +01007320 _, _, service = ee_id.partition(".") # remove prefix "namespace."
tiernob996d942020-07-03 14:52:28 +00007321 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
7322 host_port = "80"
7323 vnfr_id = vnfr_id.replace("-", "")
7324 variables = {
7325 "JOB_NAME": vnfr_id,
7326 "TARGET_IP": target_ip,
7327 "EXPORTER_POD_IP": host_name,
7328 "EXPORTER_POD_PORT": host_port,
7329 }
bravof73bac502021-05-11 07:38:47 -04007330 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007331 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7332 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007333 if (
7334 not isinstance(job.get("job_name"), str)
7335 or vnfr_id not in job["job_name"]
7336 ):
tiernob996d942020-07-03 14:52:28 +00007337 job["job_name"] = vnfr_id + "_" + str(randint(1, 10000))
7338 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007339 job["vnfr_id"] = vnfr_id
7340 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007341
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007342 async def rebuild_start_stop(
7343 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7344 ):
k4.rahulb827de92022-05-02 16:35:02 +00007345 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7346 self.logger.info(logging_text + "Enter")
7347 stage = ["Preparing the environment", ""]
7348 # database nsrs record
7349 db_nsr_update = {}
7350 vdu_vim_name = None
7351 vim_vm_id = None
7352 # in case of error, indicates what part of scale was failed to put nsr at error status
7353 start_deploy = time()
7354 try:
7355 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7356 vim_account_id = db_vnfr.get("vim-account-id")
7357 vim_info_key = "vim:" + vim_account_id
k4.rahul54e86fd2022-07-27 10:37:26 +00007358 vdu_id = additional_param["vdu_id"]
7359 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007360 vdur = find_in_list(
k4.rahul54e86fd2022-07-27 10:37:26 +00007361 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007362 )
k4.rahulb827de92022-05-02 16:35:02 +00007363 if vdur:
7364 vdu_vim_name = vdur["name"]
7365 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7366 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul54e86fd2022-07-27 10:37:26 +00007367 else:
7368 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007369 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7370 # wait for any previous tasks in process
7371 stage[1] = "Waiting for previous operations to terminate"
7372 self.logger.info(stage[1])
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007373 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007374
7375 stage[1] = "Reading from database."
7376 self.logger.info(stage[1])
7377 self._write_ns_status(
7378 nsr_id=nsr_id,
7379 ns_state=None,
7380 current_operation=operation_type.upper(),
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007381 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007382 )
7383 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7384
7385 # read from db: ns
7386 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7387 db_nsr_update["operational-status"] = operation_type
7388 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7389 # Payload for RO
7390 desc = {
7391 operation_type: {
7392 "vim_vm_id": vim_vm_id,
7393 "vnf_id": vnf_id,
7394 "vdu_index": additional_param["count-index"],
7395 "vdu_id": vdur["id"],
7396 "target_vim": target_vim,
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007397 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007398 }
7399 }
7400 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7401 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7402 self.logger.info("ro nsr id: {}".format(nsr_id))
7403 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7404 self.logger.info("response from RO: {}".format(result_dict))
7405 action_id = result_dict["action_id"]
7406 await self._wait_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007407 nsr_id,
7408 action_id,
7409 nslcmop_id,
7410 start_deploy,
7411 self.timeout_operate,
7412 None,
7413 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007414 )
7415 return "COMPLETED", "Done"
7416 except (ROclient.ROClientException, DbException, LcmException) as e:
7417 self.logger.error("Exit Exception {}".format(e))
7418 exc = e
7419 except asyncio.CancelledError:
7420 self.logger.error("Cancelled Exception while '{}'".format(stage))
7421 exc = "Operation was cancelled"
7422 except Exception as e:
7423 exc = traceback.format_exc()
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007424 self.logger.critical(
7425 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7426 )
k4.rahulb827de92022-05-02 16:35:02 +00007427 return "FAILED", "Error in operate VNF {}".format(exc)
7428
David Garciaaae391f2020-11-09 11:12:54 +01007429 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7430 """
7431 Get VCA Cloud and VCA Cloud Credentials for the VIM account
7432
7433 :param: vim_account_id: VIM Account ID
7434
7435 :return: (cloud_name, cloud_credential)
7436 """
bravof922c4172020-11-24 21:21:43 -03007437 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007438 return config.get("vca_cloud"), config.get("vca_cloud_credential")
7439
7440 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7441 """
7442 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
7443
7444 :param: vim_account_id: VIM Account ID
7445
7446 :return: (cloud_name, cloud_credential)
7447 """
bravof922c4172020-11-24 21:21:43 -03007448 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007449 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")
elumalai80bcf1c2022-04-28 18:05:01 +05307450
7451 async def migrate(self, nsr_id, nslcmop_id):
7452 """
7453 Migrate VNFs and VDUs instances in a NS
7454
7455 :param: nsr_id: NS Instance ID
7456 :param: nslcmop_id: nslcmop ID of migrate
7457
7458 """
7459 # Try to lock HA task here
7460 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7461 if not task_is_locked_by_me:
7462 return
7463 logging_text = "Task ns={} migrate ".format(nsr_id)
7464 self.logger.debug(logging_text + "Enter")
7465 # get all needed from database
7466 db_nslcmop = None
7467 db_nslcmop_update = {}
7468 nslcmop_operation_state = None
7469 db_nsr_update = {}
7470 target = {}
7471 exc = None
7472 # in case of error, indicates what part of scale was failed to put nsr at error status
7473 start_deploy = time()
7474
7475 try:
7476 # wait for any previous tasks in process
7477 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007478 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307479
7480 self._write_ns_status(
7481 nsr_id=nsr_id,
7482 ns_state=None,
7483 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007484 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307485 )
7486 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007487 self.logger.debug(
7488 step + " after having waited for previous tasks to be completed"
7489 )
elumalai80bcf1c2022-04-28 18:05:01 +05307490 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7491 migrate_params = db_nslcmop.get("operationParams")
7492
7493 target = {}
7494 target.update(migrate_params)
7495 desc = await self.RO.migrate(nsr_id, target)
7496 self.logger.debug("RO return > {}".format(desc))
7497 action_id = desc["action_id"]
7498 await self._wait_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007499 nsr_id,
7500 action_id,
7501 nslcmop_id,
7502 start_deploy,
7503 self.timeout_migrate,
7504 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307505 )
7506 except (ROclient.ROClientException, DbException, LcmException) as e:
7507 self.logger.error("Exit Exception {}".format(e))
7508 exc = e
7509 except asyncio.CancelledError:
7510 self.logger.error("Cancelled Exception while '{}'".format(step))
7511 exc = "Operation was cancelled"
7512 except Exception as e:
7513 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007514 self.logger.critical(
7515 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7516 )
elumalai80bcf1c2022-04-28 18:05:01 +05307517 finally:
7518 self._write_ns_status(
7519 nsr_id=nsr_id,
7520 ns_state=None,
7521 current_operation="IDLE",
7522 current_operation_id=None,
7523 )
7524 if exc:
aticig349aa462022-05-19 12:29:35 +03007525 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05307526 nslcmop_operation_state = "FAILED"
7527 else:
7528 nslcmop_operation_state = "COMPLETED"
7529 db_nslcmop_update["detailed-status"] = "Done"
7530 db_nsr_update["detailed-status"] = "Done"
7531
7532 self._write_op_status(
7533 op_id=nslcmop_id,
7534 stage="",
7535 error_message="",
7536 operation_state=nslcmop_operation_state,
7537 other_update=db_nslcmop_update,
7538 )
7539 if nslcmop_operation_state:
7540 try:
7541 msg = {
7542 "nsr_id": nsr_id,
7543 "nslcmop_id": nslcmop_id,
7544 "operationState": nslcmop_operation_state,
7545 }
7546 await self.msg.aiowrite("ns", "migrated", msg, loop=self.loop)
7547 except Exception as e:
7548 self.logger.error(
7549 logging_text + "kafka_write notification Exception {}".format(e)
7550 )
7551 self.logger.debug(logging_text + "Exit")
7552 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007553
garciadeblas07f4e4c2022-06-09 09:42:58 +02007554 async def heal(self, nsr_id, nslcmop_id):
7555 """
7556 Heal NS
7557
7558 :param nsr_id: ns instance to heal
7559 :param nslcmop_id: operation to run
7560 :return:
7561 """
7562
7563 # Try to lock HA task here
7564 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7565 if not task_is_locked_by_me:
7566 return
7567
7568 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
7569 stage = ["", "", ""]
7570 tasks_dict_info = {}
7571 # ^ stage, step, VIM progress
7572 self.logger.debug(logging_text + "Enter")
7573 # get all needed from database
7574 db_nsr = None
7575 db_nslcmop_update = {}
7576 db_nsr_update = {}
7577 db_vnfrs = {} # vnf's info indexed by _id
7578 exc = None
7579 old_operational_status = ""
7580 old_config_status = ""
7581 nsi_id = None
7582 try:
7583 # wait for any previous tasks in process
7584 step = "Waiting for previous operations to terminate"
7585 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
7586 self._write_ns_status(
7587 nsr_id=nsr_id,
7588 ns_state=None,
7589 current_operation="HEALING",
7590 current_operation_id=nslcmop_id,
7591 )
7592
7593 step = "Getting nslcmop from database"
7594 self.logger.debug(
7595 step + " after having waited for previous tasks to be completed"
7596 )
7597 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7598
7599 step = "Getting nsr from database"
7600 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
7601 old_operational_status = db_nsr["operational-status"]
7602 old_config_status = db_nsr["config-status"]
7603
7604 db_nsr_update = {
7605 "_admin.deployed.RO.operational-status": "healing",
7606 }
7607 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7608
7609 step = "Sending heal order to VIM"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007610 # task_ro = asyncio.ensure_future(
Gabriel Cuba73d550f2022-11-07 19:28:14 -05007611 # self.heal_RO(
7612 # logging_text=logging_text,
7613 # nsr_id=nsr_id,
7614 # db_nslcmop=db_nslcmop,
7615 # stage=stage,
7616 # )
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007617 # )
7618 # self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "heal_RO", task_ro)
7619 # tasks_dict_info[task_ro] = "Healing at VIM"
Gabriel Cuba73d550f2022-11-07 19:28:14 -05007620 await self.heal_RO(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007621 logging_text=logging_text,
7622 nsr_id=nsr_id,
7623 db_nslcmop=db_nslcmop,
7624 stage=stage,
7625 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007626 # VCA tasks
7627 # read from db: nsd
7628 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
7629 self.logger.debug(logging_text + stage[1])
7630 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7631 self.fs.sync(db_nsr["nsd-id"])
7632 db_nsr["nsd"] = nsd
7633 # read from db: vnfr's of this ns
7634 step = "Getting vnfrs from db"
7635 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
7636 for vnfr in db_vnfrs_list:
7637 db_vnfrs[vnfr["_id"]] = vnfr
7638 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
7639
7640 # Check for each target VNF
7641 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
7642 for target_vnf in target_list:
7643 # Find this VNF in the list from DB
7644 vnfr_id = target_vnf.get("vnfInstanceId", None)
7645 if vnfr_id:
7646 db_vnfr = db_vnfrs[vnfr_id]
7647 vnfd_id = db_vnfr.get("vnfd-id")
7648 vnfd_ref = db_vnfr.get("vnfd-ref")
7649 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
7650 base_folder = vnfd["_admin"]["storage"]
7651 vdu_id = None
7652 vdu_index = 0
7653 vdu_name = None
7654 kdu_name = None
7655 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
7656 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
7657
7658 # Check each target VDU and deploy N2VC
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007659 target_vdu_list = target_vnf.get("additionalParams", {}).get(
7660 "vdu", []
7661 )
garciadeblasa54747c2022-09-01 13:09:47 +02007662 if not target_vdu_list:
7663 # Codigo nuevo para crear diccionario
7664 target_vdu_list = []
7665 for existing_vdu in db_vnfr.get("vdur"):
7666 vdu_name = existing_vdu.get("vdu-name", None)
7667 vdu_index = existing_vdu.get("count-index", 0)
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007668 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
7669 "run-day1", False
7670 )
7671 vdu_to_be_healed = {
7672 "vdu-id": vdu_name,
7673 "count-index": vdu_index,
7674 "run-day1": vdu_run_day1,
7675 }
garciadeblasa54747c2022-09-01 13:09:47 +02007676 target_vdu_list.append(vdu_to_be_healed)
7677 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02007678 deploy_params_vdu = target_vdu
7679 # Set run-day1 vnf level value if not vdu level value exists
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007680 if not deploy_params_vdu.get("run-day1") and target_vnf[
7681 "additionalParams"
7682 ].get("run-day1"):
7683 deploy_params_vdu["run-day1"] = target_vnf[
7684 "additionalParams"
7685 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007686 vdu_name = target_vdu.get("vdu-id", None)
7687 # TODO: Get vdu_id from vdud.
7688 vdu_id = vdu_name
7689 # For multi instance VDU count-index is mandatory
7690 # For single session VDU count-indes is 0
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007691 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007692
7693 # n2vc_redesign STEP 3 to 6 Deploy N2VC
7694 stage[1] = "Deploying Execution Environments."
7695 self.logger.debug(logging_text + stage[1])
7696
7697 # VNF Level charm. Normal case when proxy charms.
7698 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
7699 descriptor_config = get_configuration(vnfd, vnfd_ref)
7700 if descriptor_config:
7701 # Continue if healed machine is management machine
7702 vnf_ip_address = db_vnfr.get("ip-address")
7703 target_instance = None
7704 for instance in db_vnfr.get("vdur", None):
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007705 if (
7706 instance["vdu-name"] == vdu_name
7707 and instance["count-index"] == vdu_index
7708 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02007709 target_instance = instance
7710 break
7711 if vnf_ip_address == target_instance.get("ip-address"):
7712 self._heal_n2vc(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007713 logging_text=logging_text
7714 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
7715 member_vnf_index, vdu_name, vdu_index
7716 ),
7717 db_nsr=db_nsr,
7718 db_vnfr=db_vnfr,
7719 nslcmop_id=nslcmop_id,
7720 nsr_id=nsr_id,
7721 nsi_id=nsi_id,
7722 vnfd_id=vnfd_ref,
7723 vdu_id=None,
7724 kdu_name=None,
7725 member_vnf_index=member_vnf_index,
7726 vdu_index=0,
7727 vdu_name=None,
7728 deploy_params=deploy_params_vdu,
7729 descriptor_config=descriptor_config,
7730 base_folder=base_folder,
7731 task_instantiation_info=tasks_dict_info,
7732 stage=stage,
7733 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007734
7735 # VDU Level charm. Normal case with native charms.
7736 descriptor_config = get_configuration(vnfd, vdu_name)
7737 if descriptor_config:
7738 self._heal_n2vc(
7739 logging_text=logging_text
7740 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
7741 member_vnf_index, vdu_name, vdu_index
7742 ),
7743 db_nsr=db_nsr,
7744 db_vnfr=db_vnfr,
7745 nslcmop_id=nslcmop_id,
7746 nsr_id=nsr_id,
7747 nsi_id=nsi_id,
7748 vnfd_id=vnfd_ref,
7749 vdu_id=vdu_id,
7750 kdu_name=kdu_name,
7751 member_vnf_index=member_vnf_index,
7752 vdu_index=vdu_index,
7753 vdu_name=vdu_name,
7754 deploy_params=deploy_params_vdu,
7755 descriptor_config=descriptor_config,
7756 base_folder=base_folder,
7757 task_instantiation_info=tasks_dict_info,
7758 stage=stage,
7759 )
7760
7761 except (
7762 ROclient.ROClientException,
7763 DbException,
7764 LcmException,
7765 NgRoException,
7766 ) as e:
7767 self.logger.error(logging_text + "Exit Exception {}".format(e))
7768 exc = e
7769 except asyncio.CancelledError:
7770 self.logger.error(
7771 logging_text + "Cancelled Exception while '{}'".format(step)
7772 )
7773 exc = "Operation was cancelled"
7774 except Exception as e:
7775 exc = traceback.format_exc()
7776 self.logger.critical(
7777 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7778 exc_info=True,
7779 )
7780 finally:
7781 if tasks_dict_info:
7782 stage[1] = "Waiting for healing pending tasks."
7783 self.logger.debug(logging_text + stage[1])
7784 exc = await self._wait_for_tasks(
7785 logging_text,
7786 tasks_dict_info,
7787 self.timeout_ns_deploy,
7788 stage,
7789 nslcmop_id,
7790 nsr_id=nsr_id,
7791 )
7792 if exc:
7793 db_nslcmop_update[
7794 "detailed-status"
7795 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
7796 nslcmop_operation_state = "FAILED"
7797 if db_nsr:
7798 db_nsr_update["operational-status"] = old_operational_status
7799 db_nsr_update["config-status"] = old_config_status
7800 db_nsr_update[
7801 "detailed-status"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007802 ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007803 for task, task_name in tasks_dict_info.items():
7804 if not task.done() or task.cancelled() or task.exception():
7805 if task_name.startswith(self.task_name_deploy_vca):
7806 # A N2VC task is pending
7807 db_nsr_update["config-status"] = "failed"
7808 else:
7809 # RO task is pending
7810 db_nsr_update["operational-status"] = "failed"
7811 else:
7812 error_description_nslcmop = None
7813 nslcmop_operation_state = "COMPLETED"
7814 db_nslcmop_update["detailed-status"] = "Done"
7815 db_nsr_update["detailed-status"] = "Done"
7816 db_nsr_update["operational-status"] = "running"
7817 db_nsr_update["config-status"] = "configured"
7818
7819 self._write_op_status(
7820 op_id=nslcmop_id,
7821 stage="",
7822 error_message=error_description_nslcmop,
7823 operation_state=nslcmop_operation_state,
7824 other_update=db_nslcmop_update,
7825 )
7826 if db_nsr:
7827 self._write_ns_status(
7828 nsr_id=nsr_id,
7829 ns_state=None,
7830 current_operation="IDLE",
7831 current_operation_id=None,
7832 other_update=db_nsr_update,
7833 )
7834
7835 if nslcmop_operation_state:
7836 try:
7837 msg = {
7838 "nsr_id": nsr_id,
7839 "nslcmop_id": nslcmop_id,
7840 "operationState": nslcmop_operation_state,
7841 }
7842 await self.msg.aiowrite("ns", "healed", msg, loop=self.loop)
7843 except Exception as e:
7844 self.logger.error(
7845 logging_text + "kafka_write notification Exception {}".format(e)
7846 )
7847 self.logger.debug(logging_text + "Exit")
7848 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
7849
7850 async def heal_RO(
7851 self,
7852 logging_text,
7853 nsr_id,
7854 db_nslcmop,
7855 stage,
7856 ):
7857 """
7858 Heal at RO
7859 :param logging_text: preffix text to use at logging
7860 :param nsr_id: nsr identity
7861 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
7862 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
7863 :return: None or exception
7864 """
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007865
garciadeblas07f4e4c2022-06-09 09:42:58 +02007866 def get_vim_account(vim_account_id):
7867 nonlocal db_vims
7868 if vim_account_id in db_vims:
7869 return db_vims[vim_account_id]
7870 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
7871 db_vims[vim_account_id] = db_vim
7872 return db_vim
7873
7874 try:
7875 start_heal = time()
7876 ns_params = db_nslcmop.get("operationParams")
7877 if ns_params and ns_params.get("timeout_ns_heal"):
7878 timeout_ns_heal = ns_params["timeout_ns_heal"]
7879 else:
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007880 timeout_ns_heal = self.timeout.get("ns_heal", self.timeout_ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007881
7882 db_vims = {}
7883
7884 nslcmop_id = db_nslcmop["_id"]
7885 target = {
7886 "action_id": nslcmop_id,
7887 }
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007888 self.logger.warning(
7889 "db_nslcmop={} and timeout_ns_heal={}".format(
7890 db_nslcmop, timeout_ns_heal
7891 )
7892 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007893 target.update(db_nslcmop.get("operationParams", {}))
7894
7895 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
7896 desc = await self.RO.recreate(nsr_id, target)
7897 self.logger.debug("RO return > {}".format(desc))
7898 action_id = desc["action_id"]
7899 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
7900 await self._wait_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007901 nsr_id,
7902 action_id,
7903 nslcmop_id,
7904 start_heal,
7905 timeout_ns_heal,
7906 stage,
7907 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02007908 )
7909
7910 # Updating NSR
7911 db_nsr_update = {
7912 "_admin.deployed.RO.operational-status": "running",
7913 "detailed-status": " ".join(stage),
7914 }
7915 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7916 self._write_op_status(nslcmop_id, stage)
7917 self.logger.debug(
7918 logging_text + "ns healed at RO. RO_id={}".format(action_id)
7919 )
7920
7921 except Exception as e:
7922 stage[2] = "ERROR healing at VIM"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02007923 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02007924 self.logger.error(
7925 "Error healing at VIM {}".format(e),
7926 exc_info=not isinstance(
7927 e,
7928 (
7929 ROclient.ROClientException,
7930 LcmException,
7931 DbException,
7932 NgRoException,
7933 ),
7934 ),
7935 )
7936 raise
7937
7938 def _heal_n2vc(
7939 self,
7940 logging_text,
7941 db_nsr,
7942 db_vnfr,
7943 nslcmop_id,
7944 nsr_id,
7945 nsi_id,
7946 vnfd_id,
7947 vdu_id,
7948 kdu_name,
7949 member_vnf_index,
7950 vdu_index,
7951 vdu_name,
7952 deploy_params,
7953 descriptor_config,
7954 base_folder,
7955 task_instantiation_info,
7956 stage,
7957 ):
7958 # launch instantiate_N2VC in a asyncio task and register task object
7959 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
7960 # if not found, create one entry and update database
7961 # fill db_nsr._admin.deployed.VCA.<index>
7962
7963 self.logger.debug(
7964 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
7965 )
7966 if "execution-environment-list" in descriptor_config:
7967 ee_list = descriptor_config.get("execution-environment-list", [])
7968 elif "juju" in descriptor_config:
7969 ee_list = [descriptor_config] # ns charms
7970 else: # other types as script are not supported
7971 ee_list = []
7972
7973 for ee_item in ee_list:
7974 self.logger.debug(
7975 logging_text
7976 + "_deploy_n2vc ee_item juju={}, helm={}".format(
7977 ee_item.get("juju"), ee_item.get("helm-chart")
7978 )
7979 )
7980 ee_descriptor_id = ee_item.get("id")
7981 if ee_item.get("juju"):
7982 vca_name = ee_item["juju"].get("charm")
7983 vca_type = (
7984 "lxc_proxy_charm"
7985 if ee_item["juju"].get("charm") is not None
7986 else "native_charm"
7987 )
7988 if ee_item["juju"].get("cloud") == "k8s":
7989 vca_type = "k8s_proxy_charm"
7990 elif ee_item["juju"].get("proxy") is False:
7991 vca_type = "native_charm"
7992 elif ee_item.get("helm-chart"):
7993 vca_name = ee_item["helm-chart"]
7994 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
7995 vca_type = "helm"
7996 else:
7997 vca_type = "helm-v3"
7998 else:
7999 self.logger.debug(
8000 logging_text + "skipping non juju neither charm configuration"
8001 )
8002 continue
8003
8004 vca_index = -1
8005 for vca_index, vca_deployed in enumerate(
8006 db_nsr["_admin"]["deployed"]["VCA"]
8007 ):
8008 if not vca_deployed:
8009 continue
8010 if (
8011 vca_deployed.get("member-vnf-index") == member_vnf_index
8012 and vca_deployed.get("vdu_id") == vdu_id
8013 and vca_deployed.get("kdu_name") == kdu_name
8014 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8015 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8016 ):
8017 break
8018 else:
8019 # not found, create one.
8020 target = (
8021 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8022 )
8023 if vdu_id:
8024 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8025 elif kdu_name:
8026 target += "/kdu/{}".format(kdu_name)
8027 vca_deployed = {
8028 "target_element": target,
8029 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8030 "member-vnf-index": member_vnf_index,
8031 "vdu_id": vdu_id,
8032 "kdu_name": kdu_name,
8033 "vdu_count_index": vdu_index,
8034 "operational-status": "init", # TODO revise
8035 "detailed-status": "", # TODO revise
8036 "step": "initial-deploy", # TODO revise
8037 "vnfd_id": vnfd_id,
8038 "vdu_name": vdu_name,
8039 "type": vca_type,
8040 "ee_descriptor_id": ee_descriptor_id,
8041 }
8042 vca_index += 1
8043
8044 # create VCA and configurationStatus in db
8045 db_dict = {
8046 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8047 "configurationStatus.{}".format(vca_index): dict(),
8048 }
8049 self.update_db_2("nsrs", nsr_id, db_dict)
8050
8051 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8052
8053 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8054 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8055 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8056
8057 # Launch task
8058 task_n2vc = asyncio.ensure_future(
8059 self.heal_N2VC(
8060 logging_text=logging_text,
8061 vca_index=vca_index,
8062 nsi_id=nsi_id,
8063 db_nsr=db_nsr,
8064 db_vnfr=db_vnfr,
8065 vdu_id=vdu_id,
8066 kdu_name=kdu_name,
8067 vdu_index=vdu_index,
8068 deploy_params=deploy_params,
8069 config_descriptor=descriptor_config,
8070 base_folder=base_folder,
8071 nslcmop_id=nslcmop_id,
8072 stage=stage,
8073 vca_type=vca_type,
8074 vca_name=vca_name,
8075 ee_config_descriptor=ee_item,
8076 )
8077 )
8078 self.lcm_tasks.register(
8079 "ns",
8080 nsr_id,
8081 nslcmop_id,
8082 "instantiate_N2VC-{}".format(vca_index),
8083 task_n2vc,
8084 )
8085 task_instantiation_info[
8086 task_n2vc
8087 ] = self.task_name_deploy_vca + " {}.{}".format(
8088 member_vnf_index or "", vdu_id or ""
8089 )
8090
8091 async def heal_N2VC(
8092 self,
8093 logging_text,
8094 vca_index,
8095 nsi_id,
8096 db_nsr,
8097 db_vnfr,
8098 vdu_id,
8099 kdu_name,
8100 vdu_index,
8101 config_descriptor,
8102 deploy_params,
8103 base_folder,
8104 nslcmop_id,
8105 stage,
8106 vca_type,
8107 vca_name,
8108 ee_config_descriptor,
8109 ):
8110 nsr_id = db_nsr["_id"]
8111 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8112 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8113 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8114 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8115 db_dict = {
8116 "collection": "nsrs",
8117 "filter": {"_id": nsr_id},
8118 "path": db_update_entry,
8119 }
8120 step = ""
8121 try:
garciadeblas07f4e4c2022-06-09 09:42:58 +02008122 element_type = "NS"
8123 element_under_configuration = nsr_id
8124
8125 vnfr_id = None
8126 if db_vnfr:
8127 vnfr_id = db_vnfr["_id"]
8128 osm_config["osm"]["vnf_id"] = vnfr_id
8129
8130 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8131
8132 if vca_type == "native_charm":
8133 index_number = 0
8134 else:
8135 index_number = vdu_index or 0
8136
8137 if vnfr_id:
8138 element_type = "VNF"
8139 element_under_configuration = vnfr_id
8140 namespace += ".{}-{}".format(vnfr_id, index_number)
8141 if vdu_id:
8142 namespace += ".{}-{}".format(vdu_id, index_number)
8143 element_type = "VDU"
8144 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8145 osm_config["osm"]["vdu_id"] = vdu_id
8146 elif kdu_name:
8147 namespace += ".{}".format(kdu_name)
8148 element_type = "KDU"
8149 element_under_configuration = kdu_name
8150 osm_config["osm"]["kdu_name"] = kdu_name
8151
8152 # Get artifact path
8153 if base_folder["pkg-dir"]:
8154 artifact_path = "{}/{}/{}/{}".format(
8155 base_folder["folder"],
8156 base_folder["pkg-dir"],
8157 "charms"
8158 if vca_type
8159 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8160 else "helm-charts",
8161 vca_name,
8162 )
8163 else:
8164 artifact_path = "{}/Scripts/{}/{}/".format(
8165 base_folder["folder"],
8166 "charms"
8167 if vca_type
8168 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8169 else "helm-charts",
8170 vca_name,
8171 )
8172
8173 self.logger.debug("Artifact path > {}".format(artifact_path))
8174
8175 # get initial_config_primitive_list that applies to this element
8176 initial_config_primitive_list = config_descriptor.get(
8177 "initial-config-primitive"
8178 )
8179
8180 self.logger.debug(
8181 "Initial config primitive list > {}".format(
8182 initial_config_primitive_list
8183 )
8184 )
8185
8186 # add config if not present for NS charm
8187 ee_descriptor_id = ee_config_descriptor.get("id")
8188 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8189 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8190 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8191 )
8192
8193 self.logger.debug(
8194 "Initial config primitive list #2 > {}".format(
8195 initial_config_primitive_list
8196 )
8197 )
8198 # n2vc_redesign STEP 3.1
8199 # find old ee_id if exists
8200 ee_id = vca_deployed.get("ee_id")
8201
8202 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8203 # create or register execution environment in VCA. Only for native charms when healing
8204 if vca_type == "native_charm":
8205 step = "Waiting to VM being up and getting IP address"
8206 self.logger.debug(logging_text + step)
8207 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8208 logging_text,
8209 nsr_id,
8210 vnfr_id,
8211 vdu_id,
8212 vdu_index,
8213 user=None,
8214 pub_key=None,
8215 )
8216 credentials = {"hostname": rw_mgmt_ip}
8217 # get username
8218 username = deep_get(
8219 config_descriptor, ("config-access", "ssh-access", "default-user")
8220 )
8221 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8222 # merged. Meanwhile let's get username from initial-config-primitive
8223 if not username and initial_config_primitive_list:
8224 for config_primitive in initial_config_primitive_list:
8225 for param in config_primitive.get("parameter", ()):
8226 if param["name"] == "ssh-username":
8227 username = param["value"]
8228 break
8229 if not username:
8230 raise LcmException(
8231 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8232 "'config-access.ssh-access.default-user'"
8233 )
8234 credentials["username"] = username
8235
8236 # n2vc_redesign STEP 3.2
8237 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8238 self._write_configuration_status(
8239 nsr_id=nsr_id,
8240 vca_index=vca_index,
8241 status="REGISTERING",
8242 element_under_configuration=element_under_configuration,
8243 element_type=element_type,
8244 )
8245
8246 step = "register execution environment {}".format(credentials)
8247 self.logger.debug(logging_text + step)
8248 ee_id = await self.vca_map[vca_type].register_execution_environment(
8249 credentials=credentials,
8250 namespace=namespace,
8251 db_dict=db_dict,
8252 vca_id=vca_id,
8253 )
8254
8255 # update ee_id en db
8256 db_dict_ee_id = {
8257 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8258 }
8259 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8260
8261 # for compatibility with MON/POL modules, the need model and application name at database
8262 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8263 # Not sure if this need to be done when healing
8264 """
8265 ee_id_parts = ee_id.split(".")
8266 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8267 if len(ee_id_parts) >= 2:
8268 model_name = ee_id_parts[0]
8269 application_name = ee_id_parts[1]
8270 db_nsr_update[db_update_entry + "model"] = model_name
8271 db_nsr_update[db_update_entry + "application"] = application_name
8272 """
8273
8274 # n2vc_redesign STEP 3.3
8275 # Install configuration software. Only for native charms.
8276 step = "Install configuration Software"
8277
8278 self._write_configuration_status(
8279 nsr_id=nsr_id,
8280 vca_index=vca_index,
8281 status="INSTALLING SW",
8282 element_under_configuration=element_under_configuration,
8283 element_type=element_type,
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008284 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008285 other_update=None,
8286 )
8287
8288 # TODO check if already done
8289 self.logger.debug(logging_text + step)
8290 config = None
8291 if vca_type == "native_charm":
8292 config_primitive = next(
8293 (p for p in initial_config_primitive_list if p["name"] == "config"),
8294 None,
8295 )
8296 if config_primitive:
8297 config = self._map_primitive_params(
8298 config_primitive, {}, deploy_params
8299 )
8300 await self.vca_map[vca_type].install_configuration_sw(
8301 ee_id=ee_id,
8302 artifact_path=artifact_path,
8303 db_dict=db_dict,
8304 config=config,
8305 num_units=1,
8306 vca_id=vca_id,
8307 vca_type=vca_type,
8308 )
8309
8310 # write in db flag of configuration_sw already installed
8311 self.update_db_2(
8312 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8313 )
8314
8315 # Not sure if this need to be done when healing
8316 """
8317 # add relations for this VCA (wait for other peers related with this VCA)
8318 await self._add_vca_relations(
8319 logging_text=logging_text,
8320 nsr_id=nsr_id,
8321 vca_type=vca_type,
8322 vca_index=vca_index,
8323 )
8324 """
8325
8326 # if SSH access is required, then get execution environment SSH public
8327 # if native charm we have waited already to VM be UP
8328 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
8329 pub_key = None
8330 user = None
8331 # self.logger.debug("get ssh key block")
8332 if deep_get(
8333 config_descriptor, ("config-access", "ssh-access", "required")
8334 ):
8335 # self.logger.debug("ssh key needed")
8336 # Needed to inject a ssh key
8337 user = deep_get(
8338 config_descriptor,
8339 ("config-access", "ssh-access", "default-user"),
8340 )
8341 step = "Install configuration Software, getting public ssh key"
8342 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8343 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8344 )
8345
8346 step = "Insert public key into VM user={} ssh_key={}".format(
8347 user, pub_key
8348 )
8349 else:
8350 # self.logger.debug("no need to get ssh key")
8351 step = "Waiting to VM being up and getting IP address"
8352 self.logger.debug(logging_text + step)
8353
8354 # n2vc_redesign STEP 5.1
8355 # wait for RO (ip-address) Insert pub_key into VM
8356 # IMPORTANT: We need do wait for RO to complete healing operation.
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008357 await self._wait_heal_ro(nsr_id, self.timeout_ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008358 if vnfr_id:
8359 if kdu_name:
8360 rw_mgmt_ip = await self.wait_kdu_up(
8361 logging_text, nsr_id, vnfr_id, kdu_name
8362 )
8363 else:
8364 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8365 logging_text,
8366 nsr_id,
8367 vnfr_id,
8368 vdu_id,
8369 vdu_index,
8370 user=user,
8371 pub_key=pub_key,
8372 )
8373 else:
8374 rw_mgmt_ip = None # This is for a NS configuration
8375
8376 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8377
8378 # store rw_mgmt_ip in deploy params for later replacement
8379 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8380
8381 # Day1 operations.
8382 # get run-day1 operation parameter
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008383 runDay1 = deploy_params.get("run-day1", False)
8384 self.logger.debug(
8385 " Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8386 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008387 if runDay1:
8388 # n2vc_redesign STEP 6 Execute initial config primitive
8389 step = "execute initial config primitive"
8390
8391 # wait for dependent primitives execution (NS -> VNF -> VDU)
8392 if initial_config_primitive_list:
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008393 await self._wait_dependent_n2vc(
8394 nsr_id, vca_deployed_list, vca_index
8395 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008396
8397 # stage, in function of element type: vdu, kdu, vnf or ns
8398 my_vca = vca_deployed_list[vca_index]
8399 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8400 # VDU or KDU
8401 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8402 elif my_vca.get("member-vnf-index"):
8403 # VNF
8404 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8405 else:
8406 # NS
8407 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8408
8409 self._write_configuration_status(
8410 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8411 )
8412
8413 self._write_op_status(op_id=nslcmop_id, stage=stage)
8414
8415 check_if_terminated_needed = True
8416 for initial_config_primitive in initial_config_primitive_list:
8417 # adding information on the vca_deployed if it is a NS execution environment
8418 if not vca_deployed["member-vnf-index"]:
8419 deploy_params["ns_config_info"] = json.dumps(
8420 self._get_ns_config_info(nsr_id)
8421 )
8422 # TODO check if already done
8423 primitive_params_ = self._map_primitive_params(
8424 initial_config_primitive, {}, deploy_params
8425 )
8426
8427 step = "execute primitive '{}' params '{}'".format(
8428 initial_config_primitive["name"], primitive_params_
8429 )
8430 self.logger.debug(logging_text + step)
8431 await self.vca_map[vca_type].exec_primitive(
8432 ee_id=ee_id,
8433 primitive_name=initial_config_primitive["name"],
8434 params_dict=primitive_params_,
8435 db_dict=db_dict,
8436 vca_id=vca_id,
8437 vca_type=vca_type,
8438 )
8439 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8440 if check_if_terminated_needed:
8441 if config_descriptor.get("terminate-config-primitive"):
8442 self.update_db_2(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008443 "nsrs",
8444 nsr_id,
8445 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008446 )
8447 check_if_terminated_needed = False
8448
8449 # TODO register in database that primitive is done
8450
8451 # STEP 7 Configure metrics
8452 # Not sure if this need to be done when healing
8453 """
8454 if vca_type == "helm" or vca_type == "helm-v3":
8455 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8456 ee_id=ee_id,
8457 artifact_path=artifact_path,
8458 ee_config_descriptor=ee_config_descriptor,
8459 vnfr_id=vnfr_id,
8460 nsr_id=nsr_id,
8461 target_ip=rw_mgmt_ip,
8462 )
8463 if prometheus_jobs:
8464 self.update_db_2(
8465 "nsrs",
8466 nsr_id,
8467 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8468 )
8469
8470 for job in prometheus_jobs:
8471 self.db.set_one(
8472 "prometheus_jobs",
8473 {"job_name": job["job_name"]},
8474 job,
8475 upsert=True,
8476 fail_on_empty=False,
8477 )
8478
8479 """
8480 step = "instantiated at VCA"
8481 self.logger.debug(logging_text + step)
8482
8483 self._write_configuration_status(
8484 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8485 )
8486
8487 except Exception as e: # TODO not use Exception but N2VC exception
8488 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8489 if not isinstance(
8490 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8491 ):
8492 self.logger.error(
8493 "Exception while {} : {}".format(step, e), exc_info=True
8494 )
8495 self._write_configuration_status(
8496 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8497 )
8498 raise LcmException("{} {}".format(step, e)) from e
8499
8500 async def _wait_heal_ro(
8501 self,
8502 nsr_id,
8503 timeout=600,
8504 ):
8505 start_time = time()
8506 while time() <= start_time + timeout:
8507 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008508 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
8509 "operational-status"
8510 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02008511 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
8512 if operational_status_ro != "healing":
8513 break
8514 await asyncio.sleep(15, loop=self.loop)
8515 else: # timeout_ns_deploy
8516 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05308517
8518 async def vertical_scale(self, nsr_id, nslcmop_id):
8519 """
8520 Vertical Scale the VDUs in a NS
8521
8522 :param: nsr_id: NS Instance ID
8523 :param: nslcmop_id: nslcmop ID of migrate
8524
8525 """
8526 # Try to lock HA task here
8527 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8528 if not task_is_locked_by_me:
8529 return
8530 logging_text = "Task ns={} vertical scale ".format(nsr_id)
8531 self.logger.debug(logging_text + "Enter")
8532 # get all needed from database
8533 db_nslcmop = None
8534 db_nslcmop_update = {}
8535 nslcmop_operation_state = None
8536 db_nsr_update = {}
8537 target = {}
8538 exc = None
8539 # in case of error, indicates what part of scale was failed to put nsr at error status
8540 start_deploy = time()
8541
8542 try:
8543 # wait for any previous tasks in process
8544 step = "Waiting for previous operations to terminate"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008545 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05308546
8547 self._write_ns_status(
8548 nsr_id=nsr_id,
8549 ns_state=None,
8550 current_operation="VerticalScale",
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008551 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05308552 )
8553 step = "Getting nslcmop from database"
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008554 self.logger.debug(
8555 step + " after having waited for previous tasks to be completed"
8556 )
govindarajul4ff4b512022-05-02 20:02:41 +05308557 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8558 operationParams = db_nslcmop.get("operationParams")
8559 target = {}
8560 target.update(operationParams)
8561 desc = await self.RO.vertical_scale(nsr_id, target)
8562 self.logger.debug("RO return > {}".format(desc))
8563 action_id = desc["action_id"]
8564 await self._wait_ng_ro(
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008565 nsr_id,
8566 action_id,
8567 nslcmop_id,
8568 start_deploy,
8569 self.timeout_verticalscale,
8570 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05308571 )
8572 except (ROclient.ROClientException, DbException, LcmException) as e:
8573 self.logger.error("Exit Exception {}".format(e))
8574 exc = e
8575 except asyncio.CancelledError:
8576 self.logger.error("Cancelled Exception while '{}'".format(step))
8577 exc = "Operation was cancelled"
8578 except Exception as e:
8579 exc = traceback.format_exc()
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008580 self.logger.critical(
8581 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8582 )
govindarajul4ff4b512022-05-02 20:02:41 +05308583 finally:
8584 self._write_ns_status(
8585 nsr_id=nsr_id,
8586 ns_state=None,
8587 current_operation="IDLE",
8588 current_operation_id=None,
8589 )
8590 if exc:
Guillermo Calvino9d8e6ce2023-04-18 18:43:59 +02008591 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
govindarajul4ff4b512022-05-02 20:02:41 +05308592 nslcmop_operation_state = "FAILED"
8593 else:
8594 nslcmop_operation_state = "COMPLETED"
8595 db_nslcmop_update["detailed-status"] = "Done"
8596 db_nsr_update["detailed-status"] = "Done"
8597
8598 self._write_op_status(
8599 op_id=nslcmop_id,
8600 stage="",
8601 error_message="",
8602 operation_state=nslcmop_operation_state,
8603 other_update=db_nslcmop_update,
8604 )
8605 if nslcmop_operation_state:
8606 try:
8607 msg = {
8608 "nsr_id": nsr_id,
8609 "nslcmop_id": nslcmop_id,
8610 "operationState": nslcmop_operation_state,
8611 }
8612 await self.msg.aiowrite("ns", "verticalscaled", msg, loop=self.loop)
8613 except Exception as e:
8614 self.logger.error(
8615 logging_text + "kafka_write notification Exception {}".format(e)
8616 )
8617 self.logger.debug(logging_text + "Exit")
8618 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")