blob: 968e1f3f52f2740dde807ee64b3a4e4c4b615037 [file] [log] [blame]
tierno59d22d22018-09-25 18:10:19 +02001# -*- coding: utf-8 -*-
2
tierno2e215512018-11-28 09:37:52 +00003##
4# Copyright 2018 Telefonica S.A.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17##
18
tierno59d22d22018-09-25 18:10:19 +020019import asyncio
aticigdffa6212022-04-12 15:27:53 +030020import shutil
David Garcia444bf962021-11-11 16:35:26 +010021from typing import Any, Dict, List
tierno59d22d22018-09-25 18:10:19 +020022import yaml
23import logging
24import logging.handlers
tierno59d22d22018-09-25 18:10:19 +020025import traceback
David Garciad4816682019-12-09 14:57:43 +010026import json
garciadeblas5697b8b2021-03-24 09:17:02 +010027from jinja2 import (
28 Environment,
29 TemplateError,
30 TemplateNotFound,
31 StrictUndefined,
32 UndefinedError,
garciadeblasef91e082022-08-02 15:12:18 +020033 select_autoescape,
garciadeblas5697b8b2021-03-24 09:17:02 +010034)
tierno59d22d22018-09-25 18:10:19 +020035
tierno77677d92019-08-22 13:46:35 +000036from osm_lcm import ROclient
David Garciab4ebcd02021-10-28 02:00:43 +020037from osm_lcm.data_utils.nsr import (
38 get_deployed_kdu,
39 get_deployed_vca,
40 get_deployed_vca_list,
41 get_nsd,
42)
43from osm_lcm.data_utils.vca import (
44 DeployedComponent,
45 DeployedK8sResource,
46 DeployedVCA,
47 EELevel,
48 Relation,
49 EERelation,
50 safe_get_ee_relation,
51)
tierno69f0d382020-05-07 13:08:09 +000052from osm_lcm.ng_ro import NgRoClient, NgRoException
garciadeblas5697b8b2021-03-24 09:17:02 +010053from osm_lcm.lcm_utils import (
54 LcmException,
55 LcmExceptionNoMgmtIP,
56 LcmBase,
57 deep_get,
58 get_iterable,
59 populate_dict,
aticigdffa6212022-04-12 15:27:53 +030060 check_juju_bundle_existence,
61 get_charm_artifact_path,
Gabriel Cubae539a8d2022-10-10 11:34:51 -050062 get_ee_id_parts,
garciadeblas5697b8b2021-03-24 09:17:02 +010063)
David Garciab4ebcd02021-10-28 02:00:43 +020064from osm_lcm.data_utils.nsd import (
65 get_ns_configuration_relation_list,
66 get_vnf_profile,
67 get_vnf_profiles,
68)
garciadeblas5697b8b2021-03-24 09:17:02 +010069from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020070 get_kdu,
71 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020072 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010073 get_vdu_list,
74 get_vdu_profile,
75 get_ee_sorted_initial_config_primitive_list,
76 get_ee_sorted_terminate_config_primitive_list,
77 get_kdu_list,
78 get_virtual_link_profiles,
79 get_vdu,
80 get_configuration,
81 get_vdu_index,
82 get_scaling_aspect,
83 get_number_of_instances,
84 get_juju_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020085 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030086 find_software_version,
Gabriel Cuba1411a002022-10-07 11:38:23 -050087 check_helm_ee_in_ns,
garciadeblas5697b8b2021-03-24 09:17:02 +010088)
bravof922c4172020-11-24 21:21:43 -030089from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030090from osm_lcm.data_utils.vnfr import (
91 get_osm_params,
92 get_vdur_index,
93 get_kdur,
94 get_volumes_from_instantiation_params,
95)
bravof922c4172020-11-24 21:21:43 -030096from osm_lcm.data_utils.dict_utils import parse_yaml_strings
97from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +020098from n2vc.definitions import RelationEndpoint
calvinosanch9f9c6f22019-11-04 13:37:39 +010099from n2vc.k8s_helm_conn import K8sHelmConnector
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000100from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -0500101from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200102
tierno27246d82018-09-27 15:59:09 +0200103from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200104from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200105
bravof922c4172020-11-24 21:21:43 -0300106from osm_lcm.data_utils.database.database import Database
107from osm_lcm.data_utils.filesystem.filesystem import Filesystem
gifrerenom17cd4922022-11-11 14:44:57 +0000108from osm_lcm.data_utils.wim import (
109 get_sdn_ports,
110 get_target_wim_attrs,
111 select_feasible_wim_account,
112)
bravof922c4172020-11-24 21:21:43 -0300113
quilesj7e13aeb2019-10-08 13:34:55 +0200114from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000115from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200116
tierno588547c2020-07-01 15:30:20 +0000117from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200118from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400119from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000120
tierno27246d82018-09-27 15:59:09 +0200121from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200122from time import time
tierno27246d82018-09-27 15:59:09 +0200123from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000124
tiernob996d942020-07-03 14:52:28 +0000125from random import randint
tierno59d22d22018-09-25 18:10:19 +0200126
tierno69f0d382020-05-07 13:08:09 +0000127__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200128
129
130class NsLcm(LcmBase):
Pedro Escaleira3b610a42022-07-23 23:16:06 +0100131 timeout_scale_on_error = (
garciadeblas5697b8b2021-03-24 09:17:02 +0100132 5 * 60
133 ) # Time for charm from first time at blocked,error status to mark as failed
Pedro Escaleira3b610a42022-07-23 23:16:06 +0100134 timeout_scale_on_error_outer_factor = 1.05 # Factor in relation to timeout_scale_on_error related to the timeout to be applied within the asyncio.wait_for coroutine
garciadeblas5697b8b2021-03-24 09:17:02 +0100135 timeout_ns_deploy = 2 * 3600 # default global timeout for deployment a ns
136 timeout_ns_terminate = 1800 # default global timeout for un deployment a ns
garciadeblas07f4e4c2022-06-09 09:42:58 +0200137 timeout_ns_heal = 1800 # default global timeout for un deployment a ns
garciadeblasf9b04952019-04-09 18:53:58 +0200138 timeout_charm_delete = 10 * 60
Pedro Escaleira3b610a42022-07-23 23:16:06 +0100139 timeout_primitive = 30 * 60 # Timeout for primitive execution
140 timeout_primitive_outer_factor = 1.05 # Factor in relation to timeout_primitive related to the timeout to be applied within the asyncio.wait_for coroutine
aticigdffa6212022-04-12 15:27:53 +0300141 timeout_ns_update = 30 * 60 # timeout for ns update
garciadeblas5697b8b2021-03-24 09:17:02 +0100142 timeout_progress_primitive = (
143 10 * 60
144 ) # timeout for some progress in a primitive execution
elumalai80bcf1c2022-04-28 18:05:01 +0530145 timeout_migrate = 1800 # default global timeout for migrating vnfs
k4.rahulb827de92022-05-02 16:35:02 +0000146 timeout_operate = 1800 # default global timeout for migrating vnfs
preethika.p28b0bf82022-09-23 07:36:28 +0000147 timeout_verticalscale = 1800 # default global timeout for Vertical Sclaing
kuuseac3a8882019-10-03 10:48:06 +0200148 SUBOPERATION_STATUS_NOT_FOUND = -1
149 SUBOPERATION_STATUS_NEW = -2
150 SUBOPERATION_STATUS_SKIP = -3
tiernoa2143262020-03-27 16:20:40 +0000151 task_name_deploy_vca = "Deploying VCA"
kuuseac3a8882019-10-03 10:48:06 +0200152
bravof73bac502021-05-11 07:38:47 -0400153 def __init__(self, msg, lcm_tasks, config, loop):
tierno59d22d22018-09-25 18:10:19 +0200154 """
155 Init, Connect to database, filesystem storage, and messaging
156 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
157 :return: None
158 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100159 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200160
bravof922c4172020-11-24 21:21:43 -0300161 self.db = Database().instance.db
162 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200163 self.loop = loop
164 self.lcm_tasks = lcm_tasks
tierno744303e2020-01-13 16:46:31 +0000165 self.timeout = config["timeout"]
166 self.ro_config = config["ro_config"]
tierno69f0d382020-05-07 13:08:09 +0000167 self.ng_ro = config["ro_config"].get("ng")
tierno744303e2020-01-13 16:46:31 +0000168 self.vca_config = config["VCA"].copy()
tierno59d22d22018-09-25 18:10:19 +0200169
quilesj7e13aeb2019-10-08 13:34:55 +0200170 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100171 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200172 log=self.logger,
quilesj7e13aeb2019-10-08 13:34:55 +0200173 loop=self.loop,
bravof922c4172020-11-24 21:21:43 -0300174 on_update_db=self._on_update_n2vc_db,
175 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100176 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200177 )
quilesj7e13aeb2019-10-08 13:34:55 +0200178
tierno588547c2020-07-01 15:30:20 +0000179 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000180 log=self.logger,
181 loop=self.loop,
tierno588547c2020-07-01 15:30:20 +0000182 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100183 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000184 )
185
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000186 self.k8sclusterhelm2 = K8sHelmConnector(
calvinosanch9f9c6f22019-11-04 13:37:39 +0100187 kubectl_command=self.vca_config.get("kubectlpath"),
188 helm_command=self.vca_config.get("helmpath"),
calvinosanch9f9c6f22019-11-04 13:37:39 +0100189 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100190 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300191 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100192 db=self.db,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100193 )
194
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000195 self.k8sclusterhelm3 = K8sHelm3Connector(
196 kubectl_command=self.vca_config.get("kubectlpath"),
197 helm_command=self.vca_config.get("helm3path"),
198 fs=self.fs,
199 log=self.logger,
200 db=self.db,
201 on_update_db=None,
202 )
203
Adam Israelbaacc302019-12-01 12:41:39 -0500204 self.k8sclusterjuju = K8sJujuConnector(
205 kubectl_command=self.vca_config.get("kubectlpath"),
206 juju_command=self.vca_config.get("jujupath"),
Adam Israelbaacc302019-12-01 12:41:39 -0500207 log=self.logger,
David Garciaba89cbb2020-10-16 13:05:34 +0200208 loop=self.loop,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530209 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300210 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100211 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500212 )
213
tiernoa2143262020-03-27 16:20:40 +0000214 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000215 "helm-chart": self.k8sclusterhelm2,
216 "helm-chart-v3": self.k8sclusterhelm3,
217 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000218 "juju-bundle": self.k8sclusterjuju,
219 "juju": self.k8sclusterjuju,
220 }
tierno588547c2020-07-01 15:30:20 +0000221
222 self.vca_map = {
223 "lxc_proxy_charm": self.n2vc,
224 "native_charm": self.n2vc,
225 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000226 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100227 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000228 }
229
quilesj7e13aeb2019-10-08 13:34:55 +0200230 # create RO client
bravof922c4172020-11-24 21:21:43 -0300231 self.RO = NgRoClient(self.loop, **self.ro_config)
tierno59d22d22018-09-25 18:10:19 +0200232
garciadeblas07f4e4c2022-06-09 09:42:58 +0200233 self.op_status_map = {
234 "instantiation": self.RO.status,
235 "termination": self.RO.status,
236 "migrate": self.RO.status,
237 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000238 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000239 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200240 }
241
tierno2357f4e2020-10-19 16:38:59 +0000242 @staticmethod
243 def increment_ip_mac(ip_mac, vm_index=1):
244 if not isinstance(ip_mac, str):
245 return ip_mac
246 try:
247 # try with ipv4 look for last dot
248 i = ip_mac.rfind(".")
249 if i > 0:
250 i += 1
251 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
252 # try with ipv6 or mac look for last colon. Operate in hex
253 i = ip_mac.rfind(":")
254 if i > 0:
255 i += 1
256 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100257 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
258 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
259 )
tierno2357f4e2020-10-19 16:38:59 +0000260 except Exception:
261 pass
262 return None
263
quilesj3655ae02019-12-12 16:08:35 +0000264 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj7e13aeb2019-10-08 13:34:55 +0200265
quilesj3655ae02019-12-12 16:08:35 +0000266 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
267
268 try:
269 # TODO filter RO descriptor fields...
270
271 # write to database
272 db_dict = dict()
273 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
garciadeblas5697b8b2021-03-24 09:17:02 +0100274 db_dict["deploymentStatus"] = ro_descriptor
quilesj3655ae02019-12-12 16:08:35 +0000275 self.update_db_2("nsrs", nsrs_id, db_dict)
276
277 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100278 self.logger.warn(
279 "Cannot write database RO deployment for ns={} -> {}".format(nsrs_id, e)
280 )
quilesj3655ae02019-12-12 16:08:35 +0000281
David Garciac1fe90a2021-03-31 19:12:02 +0200282 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj3655ae02019-12-12 16:08:35 +0000283
quilesj69a722c2020-01-09 08:30:17 +0000284 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100285 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000286 path = path[:-1]
287
quilesj3655ae02019-12-12 16:08:35 +0000288 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
289 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000290 try:
291
garciadeblas5697b8b2021-03-24 09:17:02 +0100292 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000293
294 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100295 nsr = self.db.get_one(table="nsrs", q_filter=filter)
296 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000297
298 # get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100299 status_dict = await self.n2vc.get_status(
300 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
301 )
quilesj3655ae02019-12-12 16:08:35 +0000302
303 # vcaStatus
304 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100305 db_dict["vcaStatus"] = status_dict
quilesj3655ae02019-12-12 16:08:35 +0000306
307 # update configurationStatus for this VCA
308 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100309 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000310
garciadeblas5697b8b2021-03-24 09:17:02 +0100311 vca_list = deep_get(
312 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
313 )
314 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000315
garciadeblas5697b8b2021-03-24 09:17:02 +0100316 configuration_status_list = nsr.get("configurationStatus")
317 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000318
garciadeblas5697b8b2021-03-24 09:17:02 +0100319 if config_status == "BROKEN" and vca_status != "failed":
320 db_dict["configurationStatus"][vca_index] = "READY"
321 elif config_status != "BROKEN" and vca_status == "failed":
322 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000323 except Exception as e:
324 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100325 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000326
327 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
328 # if nsState = 'DEGRADED' check if all is OK
329 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100330 if current_ns_status in ("READY", "DEGRADED"):
331 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000332 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100333 if status_dict.get("machines"):
334 for machine_id in status_dict.get("machines"):
335 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000336 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100337 if machine.get("agent-status"):
338 s = machine.get("agent-status").get("status")
339 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000340 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100341 error_description += (
342 "machine {} agent-status={} ; ".format(
343 machine_id, s
344 )
345 )
quilesj3655ae02019-12-12 16:08:35 +0000346 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100347 if machine.get("instance-status"):
348 s = machine.get("instance-status").get("status")
349 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000350 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100351 error_description += (
352 "machine {} instance-status={} ; ".format(
353 machine_id, s
354 )
355 )
quilesj3655ae02019-12-12 16:08:35 +0000356 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100357 if status_dict.get("applications"):
358 for app_id in status_dict.get("applications"):
359 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000360 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100361 if app.get("status"):
362 s = app.get("status").get("status")
363 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000364 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100365 error_description += (
366 "application {} status={} ; ".format(app_id, s)
367 )
quilesj3655ae02019-12-12 16:08:35 +0000368
369 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100370 db_dict["errorDescription"] = error_description
371 if current_ns_status == "READY" and is_degraded:
372 db_dict["nsState"] = "DEGRADED"
373 if current_ns_status == "DEGRADED" and not is_degraded:
374 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000375
376 # write to database
377 self.update_db_2("nsrs", nsr_id, db_dict)
378
tierno51183952020-04-03 15:48:18 +0000379 except (asyncio.CancelledError, asyncio.TimeoutError):
380 raise
quilesj3655ae02019-12-12 16:08:35 +0000381 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100382 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200383
garciadeblas5697b8b2021-03-24 09:17:02 +0100384 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100385 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100386 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530387 """
388 Updating vca status in NSR record
389 :param cluster_uuid: UUID of a k8s cluster
390 :param kdu_instance: The unique name of the KDU instance
391 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100392 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530393 :return: none
394 """
395
396 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
397 # .format(cluster_uuid, kdu_instance, filter))
398
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100399 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530400 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100401 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
402 cluster_uuid=cluster_uuid,
403 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200404 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100405 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200406 vca_id=vca_id,
407 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100408
ksaikiranr656b6dd2021-02-19 10:25:18 +0530409 # vcaStatus
410 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100411 db_dict["vcaStatus"] = {nsr_id: vca_status}
ksaikiranr656b6dd2021-02-19 10:25:18 +0530412
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100413 self.logger.debug(
414 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200415 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530416
417 # write to database
418 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530419 except (asyncio.CancelledError, asyncio.TimeoutError):
420 raise
421 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100422 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530423
tierno72ef84f2020-10-06 08:22:07 +0000424 @staticmethod
425 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
426 try:
garciadeblasef91e082022-08-02 15:12:18 +0200427 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000428 undefined=StrictUndefined,
429 autoescape=select_autoescape(default_for_string=True, default=True),
430 )
tierno72ef84f2020-10-06 08:22:07 +0000431 template = env.from_string(cloud_init_text)
432 return template.render(additional_params or {})
433 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100434 raise LcmException(
435 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
436 "file, must be provided in the instantiation parameters inside the "
437 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
438 )
tierno72ef84f2020-10-06 08:22:07 +0000439 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100440 raise LcmException(
441 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
442 vnfd_id, vdu_id, e
443 )
444 )
tierno72ef84f2020-10-06 08:22:07 +0000445
bravof922c4172020-11-24 21:21:43 -0300446 def _get_vdu_cloud_init_content(self, vdu, vnfd):
447 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000448 try:
tierno72ef84f2020-10-06 08:22:07 +0000449 if vdu.get("cloud-init-file"):
450 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300451 if base_folder["pkg-dir"]:
452 cloud_init_file = "{}/{}/cloud_init/{}".format(
453 base_folder["folder"],
454 base_folder["pkg-dir"],
455 vdu["cloud-init-file"],
456 )
457 else:
458 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
459 base_folder["folder"],
460 vdu["cloud-init-file"],
461 )
tierno72ef84f2020-10-06 08:22:07 +0000462 with self.fs.file_open(cloud_init_file, "r") as ci_file:
463 cloud_init_content = ci_file.read()
464 elif vdu.get("cloud-init"):
465 cloud_init_content = vdu["cloud-init"]
466
467 return cloud_init_content
468 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100469 raise LcmException(
470 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
471 vnfd["id"], vdu["id"], cloud_init_file, e
472 )
473 )
tierno72ef84f2020-10-06 08:22:07 +0000474
tierno72ef84f2020-10-06 08:22:07 +0000475 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100476 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300477 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100478 )
tierno72ef84f2020-10-06 08:22:07 +0000479 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300480 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000481
gcalvino35be9152018-12-20 09:33:12 +0100482 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200483 """
484 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
485 :param vnfd: input vnfd
486 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000487 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100488 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200489 :return: copy of vnfd
490 """
tierno72ef84f2020-10-06 08:22:07 +0000491 vnfd_RO = deepcopy(vnfd)
492 # remove unused by RO configuration, monitoring, scaling and internal keys
493 vnfd_RO.pop("_id", None)
494 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000495 vnfd_RO.pop("monitoring-param", None)
496 vnfd_RO.pop("scaling-group-descriptor", None)
497 vnfd_RO.pop("kdu", None)
498 vnfd_RO.pop("k8s-cluster", None)
499 if new_id:
500 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000501
tierno72ef84f2020-10-06 08:22:07 +0000502 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
503 for vdu in get_iterable(vnfd_RO, "vdu"):
504 vdu.pop("cloud-init-file", None)
505 vdu.pop("cloud-init", None)
506 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200507
tierno2357f4e2020-10-19 16:38:59 +0000508 @staticmethod
509 def ip_profile_2_RO(ip_profile):
510 RO_ip_profile = deepcopy(ip_profile)
511 if "dns-server" in RO_ip_profile:
512 if isinstance(RO_ip_profile["dns-server"], list):
513 RO_ip_profile["dns-address"] = []
514 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100515 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000516 else:
517 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
518 if RO_ip_profile.get("ip-version") == "ipv4":
519 RO_ip_profile["ip-version"] = "IPv4"
520 if RO_ip_profile.get("ip-version") == "ipv6":
521 RO_ip_profile["ip-version"] = "IPv6"
522 if "dhcp-params" in RO_ip_profile:
523 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
524 return RO_ip_profile
525
bravof922c4172020-11-24 21:21:43 -0300526 def _get_ro_vim_id_for_vim_account(self, vim_account):
527 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
528 if db_vim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100529 raise LcmException(
530 "VIM={} is not available. operationalState={}".format(
531 vim_account, db_vim["_admin"]["operationalState"]
532 )
533 )
bravof922c4172020-11-24 21:21:43 -0300534 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
535 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200536
bravof922c4172020-11-24 21:21:43 -0300537 def get_ro_wim_id_for_wim_account(self, wim_account):
538 if isinstance(wim_account, str):
539 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
540 if db_wim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100541 raise LcmException(
542 "WIM={} is not available. operationalState={}".format(
543 wim_account, db_wim["_admin"]["operationalState"]
544 )
545 )
bravof922c4172020-11-24 21:21:43 -0300546 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
547 return RO_wim_id
548 else:
549 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200550
tierno2357f4e2020-10-19 16:38:59 +0000551 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno27246d82018-09-27 15:59:09 +0200552
tierno2357f4e2020-10-19 16:38:59 +0000553 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000554 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000555 db_update = {"_admin.modified": time()}
556 if vdu_create:
557 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100558 vdur = next(
559 (
560 vdur
561 for vdur in reversed(db_vnfr["vdur"])
562 if vdur["vdu-id-ref"] == vdu_id
563 ),
564 None,
565 )
tierno2357f4e2020-10-19 16:38:59 +0000566 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000567 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300568 self.logger.debug(
569 "No vdur in the database. Using the vdur-template to scale"
570 )
vegall8d625f12022-03-22 16:23:30 +0000571 vdur_template = db_vnfr.get("vdur-template")
572 if not vdur_template:
573 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300574 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
575 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000576 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100577 )
vegall8d625f12022-03-22 16:23:30 +0000578 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300579 # Delete a template from the database after using it
580 self.db.set_one(
581 "vnfrs",
582 {"_id": db_vnfr["_id"]},
583 None,
584 pull={"vdur-template": {"_id": vdur["_id"]}},
585 )
tierno2357f4e2020-10-19 16:38:59 +0000586 for count in range(vdu_count):
587 vdur_copy = deepcopy(vdur)
588 vdur_copy["status"] = "BUILD"
589 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100590 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000591 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000592 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100593 vdur_copy["id"] = "{}-{}".format(
594 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
595 )
tierno2357f4e2020-10-19 16:38:59 +0000596 vdur_copy.pop("vim_info", None)
597 for iface in vdur_copy["interfaces"]:
598 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100599 iface["ip-address"] = self.increment_ip_mac(
600 iface["ip-address"], count + 1
601 )
tierno2357f4e2020-10-19 16:38:59 +0000602 else:
603 iface.pop("ip-address", None)
604 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100605 iface["mac-address"] = self.increment_ip_mac(
606 iface["mac-address"], count + 1
607 )
tierno2357f4e2020-10-19 16:38:59 +0000608 else:
609 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000610 if db_vnfr["vdur"]:
611 iface.pop(
612 "mgmt_vnf", None
613 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000614 db_vdu_push_list.append(vdur_copy)
615 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200616 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000617 if len(db_vnfr["vdur"]) == 1:
618 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300619 self.logger.debug(
620 "Scaling to 0 !, creating the template with the last vdur"
621 )
vegall8d625f12022-03-22 16:23:30 +0000622 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000623 for vdu_id, vdu_count in vdu_delete.items():
624 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100625 indexes_to_delete = [
626 iv[0]
627 for iv in enumerate(db_vnfr["vdur"])
628 if iv[1]["vdu-id-ref"] == vdu_id
629 ]
630 db_update.update(
631 {
632 "vdur.{}.status".format(i): "DELETING"
633 for i in indexes_to_delete[-vdu_count:]
634 }
635 )
tierno2357f4e2020-10-19 16:38:59 +0000636 else:
637 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100638 vdus_to_delete = [
639 v
640 for v in reversed(db_vnfr["vdur"])
641 if v["vdu-id-ref"] == vdu_id
642 ]
tierno2357f4e2020-10-19 16:38:59 +0000643 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100644 self.db.set_one(
645 "vnfrs",
646 {"_id": db_vnfr["_id"]},
647 None,
648 pull={"vdur": {"_id": vdu["_id"]}},
649 )
vegall8d625f12022-03-22 16:23:30 +0000650 db_push = {}
651 if db_vdu_push_list:
652 db_push["vdur"] = db_vdu_push_list
653 if template_vdur:
654 db_push["vdur-template"] = template_vdur
655 if not db_push:
656 db_push = None
657 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000658 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
659 # modify passed dictionary db_vnfr
660 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
661 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200662
tiernof578e552018-11-08 19:07:20 +0100663 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
664 """
665 Updates database nsr with the RO info for the created vld
666 :param ns_update_nsr: dictionary to be filled with the updated info
667 :param db_nsr: content of db_nsr. This is also modified
668 :param nsr_desc_RO: nsr descriptor from RO
669 :return: Nothing, LcmException is raised on errors
670 """
671
672 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
673 for net_RO in get_iterable(nsr_desc_RO, "nets"):
674 if vld["id"] != net_RO.get("ns_net_osm_id"):
675 continue
676 vld["vim-id"] = net_RO.get("vim_net_id")
677 vld["name"] = net_RO.get("vim_name")
678 vld["status"] = net_RO.get("status")
679 vld["status-detailed"] = net_RO.get("error_msg")
680 ns_update_nsr["vld.{}".format(vld_index)] = vld
681 break
682 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100683 raise LcmException(
684 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
685 )
tiernof578e552018-11-08 19:07:20 +0100686
tiernoe876f672020-02-13 14:34:48 +0000687 def set_vnfr_at_error(self, db_vnfrs, error_text):
688 try:
689 for db_vnfr in db_vnfrs.values():
690 vnfr_update = {"status": "ERROR"}
691 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
692 if "status" not in vdur:
693 vdur["status"] = "ERROR"
694 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
695 if error_text:
696 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100697 vnfr_update[
698 "vdur.{}.status-detailed".format(vdu_index)
699 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000700 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
701 except DbException as e:
702 self.logger.error("Cannot update vnf. {}".format(e))
703
tierno59d22d22018-09-25 18:10:19 +0200704 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
705 """
706 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 +0200707 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
708 :param nsr_desc_RO: nsr descriptor from RO
709 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200710 """
711 for vnf_index, db_vnfr in db_vnfrs.items():
712 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200713 if vnf_RO["member_vnf_index"] != vnf_index:
714 continue
715 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100716 if vnf_RO.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100717 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO[
718 "ip_address"
719 ].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100720 elif not db_vnfr.get("ip-address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100721 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
722 raise LcmExceptionNoMgmtIP(
723 "ns member_vnf_index '{}' has no IP address".format(
724 vnf_index
725 )
726 )
tierno59d22d22018-09-25 18:10:19 +0200727
tierno27246d82018-09-27 15:59:09 +0200728 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
729 vdur_RO_count_index = 0
730 if vdur.get("pdu-type"):
731 continue
732 for vdur_RO in get_iterable(vnf_RO, "vms"):
733 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
734 continue
735 if vdur["count-index"] != vdur_RO_count_index:
736 vdur_RO_count_index += 1
737 continue
738 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000739 if vdur_RO.get("ip_address"):
740 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000741 else:
742 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200743 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
744 vdur["name"] = vdur_RO.get("vim_name")
745 vdur["status"] = vdur_RO.get("status")
746 vdur["status-detailed"] = vdur_RO.get("error_msg")
747 for ifacer in get_iterable(vdur, "interfaces"):
748 for interface_RO in get_iterable(vdur_RO, "interfaces"):
749 if ifacer["name"] == interface_RO.get("internal_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100750 ifacer["ip-address"] = interface_RO.get(
751 "ip_address"
752 )
753 ifacer["mac-address"] = interface_RO.get(
754 "mac_address"
755 )
tierno27246d82018-09-27 15:59:09 +0200756 break
757 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100758 raise LcmException(
759 "ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
760 "from VIM info".format(
761 vnf_index, vdur["vdu-id-ref"], ifacer["name"]
762 )
763 )
tierno27246d82018-09-27 15:59:09 +0200764 vnfr_update["vdur.{}".format(vdu_index)] = vdur
765 break
766 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100767 raise LcmException(
768 "ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
769 "VIM info".format(
770 vnf_index, vdur["vdu-id-ref"], vdur["count-index"]
771 )
772 )
tiernof578e552018-11-08 19:07:20 +0100773
774 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
775 for net_RO in get_iterable(nsr_desc_RO, "nets"):
776 if vld["id"] != net_RO.get("vnf_net_osm_id"):
777 continue
778 vld["vim-id"] = net_RO.get("vim_net_id")
779 vld["name"] = net_RO.get("vim_name")
780 vld["status"] = net_RO.get("status")
781 vld["status-detailed"] = net_RO.get("error_msg")
782 vnfr_update["vld.{}".format(vld_index)] = vld
783 break
784 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100785 raise LcmException(
786 "ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
787 vnf_index, vld["id"]
788 )
789 )
tiernof578e552018-11-08 19:07:20 +0100790
tierno27246d82018-09-27 15:59:09 +0200791 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
792 break
tierno59d22d22018-09-25 18:10:19 +0200793
794 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100795 raise LcmException(
796 "ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(
797 vnf_index
798 )
799 )
tierno59d22d22018-09-25 18:10:19 +0200800
tierno5ee02052019-12-05 19:55:02 +0000801 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000802 """
803 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000804 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000805 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
806 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
807 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
808 """
tierno5ee02052019-12-05 19:55:02 +0000809 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
810 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000811 mapping = {}
812 ns_config_info = {"osm-config-mapping": mapping}
813 for vca in vca_deployed_list:
814 if not vca["member-vnf-index"]:
815 continue
816 if not vca["vdu_id"]:
817 mapping[vca["member-vnf-index"]] = vca["application"]
818 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100819 mapping[
820 "{}.{}.{}".format(
821 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
822 )
823 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000824 return ns_config_info
825
garciadeblas5697b8b2021-03-24 09:17:02 +0100826 async def _instantiate_ng_ro(
827 self,
828 logging_text,
829 nsr_id,
830 nsd,
831 db_nsr,
832 db_nslcmop,
833 db_vnfrs,
834 db_vnfds,
835 n2vc_key_list,
836 stage,
837 start_deploy,
838 timeout_ns_deploy,
839 ):
tierno2357f4e2020-10-19 16:38:59 +0000840
841 db_vims = {}
842
843 def get_vim_account(vim_account_id):
844 nonlocal db_vims
845 if vim_account_id in db_vims:
846 return db_vims[vim_account_id]
847 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
848 db_vims[vim_account_id] = db_vim
849 return db_vim
850
851 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100852 def parse_vld_instantiation_params(
853 target_vim, target_vld, vld_params, target_sdn
854 ):
tierno2357f4e2020-10-19 16:38:59 +0000855 if vld_params.get("ip-profile"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100856 target_vld["vim_info"][target_vim]["ip_profile"] = vld_params[
857 "ip-profile"
858 ]
tierno2357f4e2020-10-19 16:38:59 +0000859 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100860 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
861 "provider-network"
862 ]
tierno2357f4e2020-10-19 16:38:59 +0000863 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100864 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
865 "provider-network"
866 ]["sdn-ports"]
gifrerenom17cd4922022-11-11 14:44:57 +0000867
868 # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
869 # if wim_account_id is specified in vld_params, validate if it is feasible.
870 wim_account_id, db_wim = select_feasible_wim_account(
871 db_nsr, db_vnfrs, target_vld, vld_params, self.logger
872 )
873
874 if wim_account_id:
875 # WIM is needed and a feasible one was found, populate WIM target and SDN ports
876 self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
877 # update vld_params with correct WIM account Id
878 vld_params["wimAccountId"] = wim_account_id
879
880 target_wim = "wim:{}".format(wim_account_id)
881 target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
882 sdn_ports = get_sdn_ports(vld_params, db_wim)
883 if len(sdn_ports) > 0:
884 target_vld["vim_info"][target_wim] = target_wim_attrs
885 target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
886
887 self.logger.debug(
888 "Target VLD with WIM data: {:s}".format(str(target_vld))
889 )
890
tierno2357f4e2020-10-19 16:38:59 +0000891 for param in ("vim-network-name", "vim-network-id"):
892 if vld_params.get(param):
893 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300894 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300895 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100896 populate_dict(
897 target_vld["vim_info"],
898 (other_target_vim, param.replace("-", "_")),
899 vim_net,
900 )
tierno2357f4e2020-10-19 16:38:59 +0000901 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100902 target_vld["vim_info"][target_vim][
903 param.replace("-", "_")
904 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300905 if vld_params.get("common_id"):
906 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000907
aticig15db6142022-01-24 12:51:26 +0300908 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
909 def update_ns_vld_target(target, ns_params):
910 for vnf_params in ns_params.get("vnf", ()):
911 if vnf_params.get("vimAccountId"):
912 target_vnf = next(
913 (
914 vnfr
915 for vnfr in db_vnfrs.values()
916 if vnf_params["member-vnf-index"]
917 == vnfr["member-vnf-index-ref"]
918 ),
919 None,
920 )
921 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
Pedro Escaleiraaa366ed2022-09-12 00:14:41 +0100922 if not vdur:
923 return
aticig15db6142022-01-24 12:51:26 +0300924 for a_index, a_vld in enumerate(target["ns"]["vld"]):
925 target_vld = find_in_list(
926 get_iterable(vdur, "interfaces"),
927 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
928 )
aticig84bd9a72022-06-14 03:01:36 +0300929
930 vld_params = find_in_list(
931 get_iterable(ns_params, "vld"),
932 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
933 )
aticig15db6142022-01-24 12:51:26 +0300934 if target_vld:
aticig84bd9a72022-06-14 03:01:36 +0300935
aticig15db6142022-01-24 12:51:26 +0300936 if vnf_params.get("vimAccountId") not in a_vld.get(
937 "vim_info", {}
938 ):
aticig84bd9a72022-06-14 03:01:36 +0300939 target_vim_network_list = [
940 v for _, v in a_vld.get("vim_info").items()
941 ]
942 target_vim_network_name = next(
943 (
944 item.get("vim_network_name", "")
945 for item in target_vim_network_list
946 ),
947 "",
948 )
949
aticig15db6142022-01-24 12:51:26 +0300950 target["ns"]["vld"][a_index].get("vim_info").update(
951 {
952 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300953 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300954 }
955 }
956 )
957
aticig84bd9a72022-06-14 03:01:36 +0300958 if vld_params:
959 for param in ("vim-network-name", "vim-network-id"):
960 if vld_params.get(param) and isinstance(
961 vld_params[param], dict
962 ):
963 for vim, vim_net in vld_params[
964 param
965 ].items():
966 other_target_vim = "vim:" + vim
967 populate_dict(
968 target["ns"]["vld"][a_index].get(
969 "vim_info"
970 ),
971 (
972 other_target_vim,
973 param.replace("-", "_"),
974 ),
975 vim_net,
976 )
977
tierno69f0d382020-05-07 13:08:09 +0000978 nslcmop_id = db_nslcmop["_id"]
979 target = {
980 "name": db_nsr["name"],
981 "ns": {"vld": []},
982 "vnf": [],
983 "image": deepcopy(db_nsr["image"]),
984 "flavor": deepcopy(db_nsr["flavor"]),
985 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000986 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000987 }
988 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000989 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000990 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000991 flavor["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100992 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100993 target["affinity-or-anti-affinity-group"] = deepcopy(
994 db_nsr["affinity-or-anti-affinity-group"]
995 )
996 for affinity_or_anti_affinity_group in target[
997 "affinity-or-anti-affinity-group"
998 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100999 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +00001000
tierno2357f4e2020-10-19 16:38:59 +00001001 if db_nslcmop.get("lcmOperationType") != "instantiate":
1002 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +01001003 db_nslcmop_instantiate = self.db.get_list(
1004 "nslcmops",
1005 {
1006 "nsInstanceId": db_nslcmop["nsInstanceId"],
1007 "lcmOperationType": "instantiate",
1008 },
1009 )[-1]
tierno2357f4e2020-10-19 16:38:59 +00001010 ns_params = db_nslcmop_instantiate.get("operationParams")
1011 else:
1012 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -03001013 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
1014 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +00001015
1016 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +00001017 for vld_index, vld in enumerate(db_nsr.get("vld")):
1018 target_vim = "vim:{}".format(ns_params["vimAccountId"])
1019 target_vld = {
1020 "id": vld["id"],
1021 "name": vld["name"],
1022 "mgmt-network": vld.get("mgmt-network", False),
1023 "type": vld.get("type"),
1024 "vim_info": {
bravof922c4172020-11-24 21:21:43 -03001025 target_vim: {
1026 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +01001027 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -03001028 }
garciadeblas5697b8b2021-03-24 09:17:02 +01001029 },
tierno2357f4e2020-10-19 16:38:59 +00001030 }
1031 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +00001032 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +00001033 db_vim = get_vim_account(ns_params["vimAccountId"])
tierno2357f4e2020-10-19 16:38:59 +00001034 sdnc_id = db_vim["config"].get("sdn-controller")
1035 if sdnc_id:
garciadeblasa5ae90b2021-02-12 11:26:46 +00001036 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
1037 target_sdn = "sdn:{}".format(sdnc_id)
1038 target_vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001039 "sdn": True,
1040 "target_vim": target_vim,
1041 "vlds": [sdn_vld],
1042 "type": vld.get("type"),
1043 }
tierno2357f4e2020-10-19 16:38:59 +00001044
bravof922c4172020-11-24 21:21:43 -03001045 nsd_vnf_profiles = get_vnf_profiles(nsd)
1046 for nsd_vnf_profile in nsd_vnf_profiles:
1047 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
1048 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001049 cp2target[
1050 "member_vnf:{}.{}".format(
1051 cp["constituent-cpd-id"][0][
1052 "constituent-base-element-id"
1053 ],
1054 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
1055 )
1056 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +00001057
1058 # check at nsd descriptor, if there is an ip-profile
1059 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +00001060 nsd_vlp = find_in_list(
1061 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001062 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
1063 == vld["id"],
1064 )
1065 if (
1066 nsd_vlp
1067 and nsd_vlp.get("virtual-link-protocol-data")
1068 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1069 ):
1070 ip_profile_source_data = nsd_vlp["virtual-link-protocol-data"][
1071 "l3-protocol-data"
1072 ]
lloretgalleg19008482021-04-19 11:40:18 +00001073 ip_profile_dest_data = {}
1074 if "ip-version" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001075 ip_profile_dest_data["ip-version"] = ip_profile_source_data[
1076 "ip-version"
1077 ]
lloretgalleg19008482021-04-19 11:40:18 +00001078 if "cidr" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001079 ip_profile_dest_data["subnet-address"] = ip_profile_source_data[
1080 "cidr"
1081 ]
lloretgalleg19008482021-04-19 11:40:18 +00001082 if "gateway-ip" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001083 ip_profile_dest_data["gateway-address"] = ip_profile_source_data[
1084 "gateway-ip"
1085 ]
lloretgalleg19008482021-04-19 11:40:18 +00001086 if "dhcp-enabled" in ip_profile_source_data:
1087 ip_profile_dest_data["dhcp-params"] = {
1088 "enabled": ip_profile_source_data["dhcp-enabled"]
1089 }
1090 vld_params["ip-profile"] = ip_profile_dest_data
bravof922c4172020-11-24 21:21:43 -03001091
tierno2357f4e2020-10-19 16:38:59 +00001092 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +01001093 vld_instantiation_params = find_in_list(
1094 get_iterable(ns_params, "vld"),
1095 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
1096 )
tierno2357f4e2020-10-19 16:38:59 +00001097 if vld_instantiation_params:
1098 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -03001099 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +00001100 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +03001101 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
1102 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -03001103
tierno69f0d382020-05-07 13:08:09 +00001104 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +01001105 vnfd = find_in_list(
1106 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
1107 )
1108 vnf_params = find_in_list(
1109 get_iterable(ns_params, "vnf"),
1110 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
1111 )
tierno69f0d382020-05-07 13:08:09 +00001112 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +00001113 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +00001114 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +00001115 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +01001116 vnf_cp = find_in_list(
1117 vnfd.get("int-virtual-link-desc", ()),
1118 lambda cpd: cpd.get("id") == vld["id"],
1119 )
tierno69f0d382020-05-07 13:08:09 +00001120 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01001121 ns_cp = "member_vnf:{}.{}".format(
1122 vnfr["member-vnf-index-ref"], vnf_cp["id"]
1123 )
tierno69f0d382020-05-07 13:08:09 +00001124 if cp2target.get(ns_cp):
1125 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -03001126
garciadeblas5697b8b2021-03-24 09:17:02 +01001127 vld["vim_info"] = {
1128 target_vim: {"vim_network_name": vld.get("vim-network-name")}
1129 }
tierno2357f4e2020-10-19 16:38:59 +00001130 # check if this network needs SDN assist
1131 target_sdn = None
1132 if vld.get("pci-interfaces"):
1133 db_vim = get_vim_account(vnfr["vim-account-id"])
1134 sdnc_id = db_vim["config"].get("sdn-controller")
1135 if sdnc_id:
1136 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
1137 target_sdn = "sdn:{}".format(sdnc_id)
1138 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001139 "sdn": True,
1140 "target_vim": target_vim,
1141 "vlds": [sdn_vld],
1142 "type": vld.get("type"),
1143 }
tierno69f0d382020-05-07 13:08:09 +00001144
tierno2357f4e2020-10-19 16:38:59 +00001145 # check at vnfd descriptor, if there is an ip-profile
1146 vld_params = {}
bravof922c4172020-11-24 21:21:43 -03001147 vnfd_vlp = find_in_list(
1148 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001149 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -03001150 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001151 if (
1152 vnfd_vlp
1153 and vnfd_vlp.get("virtual-link-protocol-data")
1154 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1155 ):
1156 ip_profile_source_data = vnfd_vlp["virtual-link-protocol-data"][
1157 "l3-protocol-data"
1158 ]
bravof922c4172020-11-24 21:21:43 -03001159 ip_profile_dest_data = {}
1160 if "ip-version" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001161 ip_profile_dest_data["ip-version"] = ip_profile_source_data[
1162 "ip-version"
1163 ]
bravof922c4172020-11-24 21:21:43 -03001164 if "cidr" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001165 ip_profile_dest_data["subnet-address"] = ip_profile_source_data[
1166 "cidr"
1167 ]
bravof922c4172020-11-24 21:21:43 -03001168 if "gateway-ip" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001169 ip_profile_dest_data[
1170 "gateway-address"
1171 ] = ip_profile_source_data["gateway-ip"]
bravof922c4172020-11-24 21:21:43 -03001172 if "dhcp-enabled" in ip_profile_source_data:
1173 ip_profile_dest_data["dhcp-params"] = {
1174 "enabled": ip_profile_source_data["dhcp-enabled"]
1175 }
1176
1177 vld_params["ip-profile"] = ip_profile_dest_data
tierno2357f4e2020-10-19 16:38:59 +00001178 # update vld_params with instantiation params
1179 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01001180 vld_instantiation_params = find_in_list(
1181 get_iterable(vnf_params, "internal-vld"),
1182 lambda i_vld: i_vld["name"] == vld["id"],
1183 )
tierno2357f4e2020-10-19 16:38:59 +00001184 if vld_instantiation_params:
1185 vld_params.update(vld_instantiation_params)
1186 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1187
1188 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001189 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001190 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1191 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001192 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001193
bravof922c4172020-11-24 21:21:43 -03001194 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1195
1196 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001197 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1198 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001199 if (
1200 vdu_configuration
1201 and vdu_configuration.get("config-access")
1202 and vdu_configuration.get("config-access").get("ssh-access")
1203 ):
bravof922c4172020-11-24 21:21:43 -03001204 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001205 vdur["ssh-access-required"] = vdu_configuration[
1206 "config-access"
1207 ]["ssh-access"]["required"]
1208 elif (
1209 vnf_configuration
1210 and vnf_configuration.get("config-access")
1211 and vnf_configuration.get("config-access").get("ssh-access")
1212 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1213 ):
bravof922c4172020-11-24 21:21:43 -03001214 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001215 vdur["ssh-access-required"] = vnf_configuration[
1216 "config-access"
1217 ]["ssh-access"]["required"]
1218 elif ssh_keys_instantiation and find_in_list(
1219 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1220 ):
bravof922c4172020-11-24 21:21:43 -03001221 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001222
bravof922c4172020-11-24 21:21:43 -03001223 self.logger.debug("NS > vdur > {}".format(vdur))
1224
1225 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001226 # cloud-init
1227 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001228 vdur["cloud-init"] = "{}:file:{}".format(
1229 vnfd["_id"], vdud.get("cloud-init-file")
1230 )
tierno2357f4e2020-10-19 16:38:59 +00001231 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1232 if vdur["cloud-init"] not in target["cloud_init_content"]:
1233 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001234 if base_folder["pkg-dir"]:
1235 cloud_init_file = "{}/{}/cloud_init/{}".format(
1236 base_folder["folder"],
1237 base_folder["pkg-dir"],
1238 vdud.get("cloud-init-file"),
1239 )
1240 else:
1241 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1242 base_folder["folder"],
1243 vdud.get("cloud-init-file"),
1244 )
tierno2357f4e2020-10-19 16:38:59 +00001245 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001246 target["cloud_init_content"][
1247 vdur["cloud-init"]
1248 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001249 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001250 vdur["cloud-init"] = "{}:vdu:{}".format(
1251 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1252 )
tierno2357f4e2020-10-19 16:38:59 +00001253 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001254 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1255 "cloud-init"
1256 ]
tierno2357f4e2020-10-19 16:38:59 +00001257 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001258 deploy_params_vdu = self._format_additional_params(
1259 vdur.get("additionalParams") or {}
1260 )
1261 deploy_params_vdu["OSM"] = get_osm_params(
1262 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1263 )
tierno2357f4e2020-10-19 16:38:59 +00001264 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001265
1266 # flavor
1267 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001268 if target_vim not in ns_flavor["vim_info"]:
1269 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001270
1271 # deal with images
1272 # in case alternative images are provided we must check if they should be applied
1273 # for the vim_type, modify the vim_type taking into account
1274 ns_image_id = int(vdur["ns-image-id"])
1275 if vdur.get("alt-image-ids"):
1276 db_vim = get_vim_account(vnfr["vim-account-id"])
1277 vim_type = db_vim["vim_type"]
1278 for alt_image_id in vdur.get("alt-image-ids"):
1279 ns_alt_image = target["image"][int(alt_image_id)]
1280 if vim_type == ns_alt_image.get("vim-type"):
1281 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001282 self.logger.debug(
1283 "use alternative image id: {}".format(alt_image_id)
1284 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001285 ns_image_id = alt_image_id
1286 vdur["ns-image-id"] = ns_image_id
1287 break
1288 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001289 if target_vim not in ns_image["vim_info"]:
1290 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001291
Alexis Romero305b5c42022-03-11 15:29:18 +01001292 # Affinity groups
1293 if vdur.get("affinity-or-anti-affinity-group-id"):
1294 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1295 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1296 if target_vim not in ns_ags["vim_info"]:
1297 ns_ags["vim_info"][target_vim] = {}
1298
tierno2357f4e2020-10-19 16:38:59 +00001299 vdur["vim_info"] = {target_vim: {}}
1300 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001301 if vnf_params:
1302 vdu_instantiation_params = find_in_list(
1303 get_iterable(vnf_params, "vdu"),
1304 lambda i_vdu: i_vdu["id"] == vdud["id"],
1305 )
1306 if vdu_instantiation_params:
1307 # Parse the vdu_volumes from the instantiation params
1308 vdu_volumes = get_volumes_from_instantiation_params(
1309 vdu_instantiation_params, vdud
1310 )
1311 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
tierno2357f4e2020-10-19 16:38:59 +00001312 vdur_list.append(vdur)
1313 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001314 target["vnf"].append(target_vnf)
1315
garciadeblas07f4e4c2022-06-09 09:42:58 +02001316 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001317 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001318 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001319 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001320 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001321 nsr_id,
1322 action_id,
1323 nslcmop_id,
1324 start_deploy,
1325 timeout_ns_deploy,
1326 stage,
1327 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001328 )
tierno69f0d382020-05-07 13:08:09 +00001329
1330 # Updating NSR
1331 db_nsr_update = {
1332 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001333 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001334 }
1335 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1336 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1337 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001338 self.logger.debug(
1339 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1340 )
tierno69f0d382020-05-07 13:08:09 +00001341 return
1342
garciadeblas5697b8b2021-03-24 09:17:02 +01001343 async def _wait_ng_ro(
1344 self,
1345 nsr_id,
1346 action_id,
1347 nslcmop_id=None,
1348 start_time=None,
1349 timeout=600,
1350 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001351 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001352 ):
tierno69f0d382020-05-07 13:08:09 +00001353 detailed_status_old = None
1354 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001355 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001356 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001357 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001358 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001359 if desc_status["status"] == "FAILED":
1360 raise NgRoException(desc_status["details"])
1361 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001362 if stage:
1363 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001364 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001365 if stage:
1366 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001367 break
1368 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001369 assert False, "ROclient.check_ns_status returns unknown {}".format(
1370 desc_status["status"]
1371 )
tierno2357f4e2020-10-19 16:38:59 +00001372 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001373 detailed_status_old = stage[2]
1374 db_nsr_update["detailed-status"] = " ".join(stage)
1375 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1376 self._write_op_status(nslcmop_id, stage)
bravof922c4172020-11-24 21:21:43 -03001377 await asyncio.sleep(15, loop=self.loop)
tierno69f0d382020-05-07 13:08:09 +00001378 else: # timeout_ns_deploy
1379 raise NgRoException("Timeout waiting ns to deploy")
1380
garciadeblas5697b8b2021-03-24 09:17:02 +01001381 async def _terminate_ng_ro(
1382 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1383 ):
tierno69f0d382020-05-07 13:08:09 +00001384 db_nsr_update = {}
1385 failed_detail = []
1386 action_id = None
1387 start_deploy = time()
1388 try:
1389 target = {
1390 "ns": {"vld": []},
1391 "vnf": [],
1392 "image": [],
1393 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001394 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001395 }
1396 desc = await self.RO.deploy(nsr_id, target)
1397 action_id = desc["action_id"]
1398 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = action_id
1399 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001400 self.logger.debug(
1401 logging_text
1402 + "ns terminate action at RO. action_id={}".format(action_id)
1403 )
tierno69f0d382020-05-07 13:08:09 +00001404
1405 # wait until done
1406 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001407 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001408 nsr_id,
1409 action_id,
1410 nslcmop_id,
1411 start_deploy,
1412 delete_timeout,
1413 stage,
1414 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001415 )
tierno69f0d382020-05-07 13:08:09 +00001416
1417 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
1418 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1419 # delete all nsr
1420 await self.RO.delete(nsr_id)
1421 except Exception as e:
1422 if isinstance(e, NgRoException) and e.http_code == 404: # not found
1423 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1424 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1425 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01001426 self.logger.debug(
1427 logging_text + "RO_action_id={} already deleted".format(action_id)
1428 )
tierno69f0d382020-05-07 13:08:09 +00001429 elif isinstance(e, NgRoException) and e.http_code == 409: # conflict
1430 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001431 self.logger.debug(
1432 logging_text
1433 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1434 )
tierno69f0d382020-05-07 13:08:09 +00001435 else:
1436 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001437 self.logger.error(
1438 logging_text
1439 + "RO_action_id={} delete error: {}".format(action_id, e)
1440 )
tierno69f0d382020-05-07 13:08:09 +00001441
1442 if failed_detail:
1443 stage[2] = "Error deleting from VIM"
1444 else:
1445 stage[2] = "Deleted from VIM"
1446 db_nsr_update["detailed-status"] = " ".join(stage)
1447 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1448 self._write_op_status(nslcmop_id, stage)
1449
1450 if failed_detail:
1451 raise LcmException("; ".join(failed_detail))
1452 return
1453
garciadeblas5697b8b2021-03-24 09:17:02 +01001454 async def instantiate_RO(
1455 self,
1456 logging_text,
1457 nsr_id,
1458 nsd,
1459 db_nsr,
1460 db_nslcmop,
1461 db_vnfrs,
1462 db_vnfds,
1463 n2vc_key_list,
1464 stage,
1465 ):
tiernoe95ed362020-04-23 08:24:57 +00001466 """
1467 Instantiate at RO
1468 :param logging_text: preffix text to use at logging
1469 :param nsr_id: nsr identity
1470 :param nsd: database content of ns descriptor
1471 :param db_nsr: database content of ns record
1472 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1473 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001474 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001475 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1476 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1477 :return: None or exception
1478 """
tiernoe876f672020-02-13 14:34:48 +00001479 try:
tiernoe876f672020-02-13 14:34:48 +00001480 start_deploy = time()
1481 ns_params = db_nslcmop.get("operationParams")
1482 if ns_params and ns_params.get("timeout_ns_deploy"):
1483 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1484 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001485 timeout_ns_deploy = self.timeout.get(
1486 "ns_deploy", self.timeout_ns_deploy
1487 )
quilesj7e13aeb2019-10-08 13:34:55 +02001488
tiernoe876f672020-02-13 14:34:48 +00001489 # Check for and optionally request placement optimization. Database will be updated if placement activated
1490 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001491 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1492 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1493 for vnfr in db_vnfrs.values():
1494 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1495 break
1496 else:
1497 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001498
garciadeblas5697b8b2021-03-24 09:17:02 +01001499 return await self._instantiate_ng_ro(
1500 logging_text,
1501 nsr_id,
1502 nsd,
1503 db_nsr,
1504 db_nslcmop,
1505 db_vnfrs,
1506 db_vnfds,
1507 n2vc_key_list,
1508 stage,
1509 start_deploy,
1510 timeout_ns_deploy,
1511 )
tierno2357f4e2020-10-19 16:38:59 +00001512 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001513 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001514 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001515 self.logger.error(
1516 "Error deploying at VIM {}".format(e),
1517 exc_info=not isinstance(
1518 e,
1519 (
1520 ROclient.ROClientException,
1521 LcmException,
1522 DbException,
1523 NgRoException,
1524 ),
1525 ),
1526 )
tiernoe876f672020-02-13 14:34:48 +00001527 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001528
tierno7ecbc342020-09-21 14:05:39 +00001529 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1530 """
1531 Wait for kdu to be up, get ip address
1532 :param logging_text: prefix use for logging
1533 :param nsr_id:
1534 :param vnfr_id:
1535 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001536 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001537 """
1538
1539 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1540 nb_tries = 0
1541
1542 while nb_tries < 360:
1543 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001544 kdur = next(
1545 (
1546 x
1547 for x in get_iterable(db_vnfr, "kdur")
1548 if x.get("kdu-name") == kdu_name
1549 ),
1550 None,
1551 )
tierno7ecbc342020-09-21 14:05:39 +00001552 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001553 raise LcmException(
1554 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1555 )
tierno7ecbc342020-09-21 14:05:39 +00001556 if kdur.get("status"):
1557 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001558 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001559 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001560 raise LcmException(
1561 "target KDU={} is in error state".format(kdu_name)
1562 )
tierno7ecbc342020-09-21 14:05:39 +00001563
1564 await asyncio.sleep(10, loop=self.loop)
1565 nb_tries += 1
1566 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1567
garciadeblas5697b8b2021-03-24 09:17:02 +01001568 async def wait_vm_up_insert_key_ro(
1569 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1570 ):
tiernoa5088192019-11-26 16:12:53 +00001571 """
1572 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1573 :param logging_text: prefix use for logging
1574 :param nsr_id:
1575 :param vnfr_id:
1576 :param vdu_id:
1577 :param vdu_index:
1578 :param pub_key: public ssh key to inject, None to skip
1579 :param user: user to apply the public ssh key
1580 :return: IP address
1581 """
quilesj7e13aeb2019-10-08 13:34:55 +02001582
tierno2357f4e2020-10-19 16:38:59 +00001583 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001584 ro_nsr_id = None
1585 ip_address = None
1586 nb_tries = 0
1587 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001588 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001589
tiernod8323042019-08-09 11:32:23 +00001590 while True:
quilesj7e13aeb2019-10-08 13:34:55 +02001591
quilesj3149f262019-12-03 10:58:10 +00001592 ro_retries += 1
1593 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001594 raise LcmException(
1595 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1596 )
quilesj3149f262019-12-03 10:58:10 +00001597
tiernod8323042019-08-09 11:32:23 +00001598 await asyncio.sleep(10, loop=self.loop)
quilesj7e13aeb2019-10-08 13:34:55 +02001599
1600 # get ip address
tiernod8323042019-08-09 11:32:23 +00001601 if not target_vdu_id:
1602 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001603
1604 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001605 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001606 raise LcmException(
1607 "Cannot inject ssh-key because target VNF is in error state"
1608 )
tiernod8323042019-08-09 11:32:23 +00001609 ip_address = db_vnfr.get("ip-address")
1610 if not ip_address:
1611 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001612 vdur = next(
1613 (
1614 x
1615 for x in get_iterable(db_vnfr, "vdur")
1616 if x.get("ip-address") == ip_address
1617 ),
1618 None,
1619 )
quilesj3149f262019-12-03 10:58:10 +00001620 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001621 vdur = next(
1622 (
1623 x
1624 for x in get_iterable(db_vnfr, "vdur")
1625 if x.get("vdu-id-ref") == vdu_id
1626 and x.get("count-index") == vdu_index
1627 ),
1628 None,
1629 )
quilesj3149f262019-12-03 10:58:10 +00001630
garciadeblas5697b8b2021-03-24 09:17:02 +01001631 if (
1632 not vdur and len(db_vnfr.get("vdur", ())) == 1
1633 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001634 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001635 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001636 raise LcmException(
1637 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1638 vnfr_id, vdu_id, vdu_index
1639 )
1640 )
tierno2357f4e2020-10-19 16:38:59 +00001641 # New generation RO stores information at "vim_info"
1642 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001643 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001644 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001645 target_vim = next(
1646 t for t in vdur["vim_info"]
1647 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001648 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001649 if (
1650 vdur.get("pdu-type")
1651 or vdur.get("status") == "ACTIVE"
1652 or ng_ro_status == "ACTIVE"
1653 ):
quilesj3149f262019-12-03 10:58:10 +00001654 ip_address = vdur.get("ip-address")
1655 if not ip_address:
1656 continue
1657 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001658 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001659 raise LcmException(
1660 "Cannot inject ssh-key because target VM is in error state"
1661 )
quilesj3149f262019-12-03 10:58:10 +00001662
tiernod8323042019-08-09 11:32:23 +00001663 if not target_vdu_id:
1664 continue
tiernod8323042019-08-09 11:32:23 +00001665
quilesj7e13aeb2019-10-08 13:34:55 +02001666 # inject public key into machine
1667 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001668 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001669 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001670 if vdur.get("pdu-type"):
1671 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1672 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001673 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001674 ro_vm_id = "{}-{}".format(
1675 db_vnfr["member-vnf-index-ref"], target_vdu_id
1676 ) # TODO add vdu_index
tierno69f0d382020-05-07 13:08:09 +00001677 if self.ng_ro:
garciadeblas5697b8b2021-03-24 09:17:02 +01001678 target = {
1679 "action": {
1680 "action": "inject_ssh_key",
1681 "key": pub_key,
1682 "user": user,
1683 },
1684 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1685 }
tierno2357f4e2020-10-19 16:38:59 +00001686 desc = await self.RO.deploy(nsr_id, target)
1687 action_id = desc["action_id"]
preethika.p28b0bf82022-09-23 07:36:28 +00001688 await self._wait_ng_ro(
1689 nsr_id, action_id, timeout=600, operation="instantiation"
1690 )
tierno2357f4e2020-10-19 16:38:59 +00001691 break
tierno69f0d382020-05-07 13:08:09 +00001692 else:
tierno2357f4e2020-10-19 16:38:59 +00001693 # wait until NS is deployed at RO
1694 if not ro_nsr_id:
1695 db_nsrs = self.db.get_one("nsrs", {"_id": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001696 ro_nsr_id = deep_get(
1697 db_nsrs, ("_admin", "deployed", "RO", "nsr_id")
1698 )
tierno2357f4e2020-10-19 16:38:59 +00001699 if not ro_nsr_id:
1700 continue
tierno69f0d382020-05-07 13:08:09 +00001701 result_dict = await self.RO.create_action(
1702 item="ns",
1703 item_id_name=ro_nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001704 descriptor={
1705 "add_public_key": pub_key,
1706 "vms": [ro_vm_id],
1707 "user": user,
1708 },
tierno69f0d382020-05-07 13:08:09 +00001709 )
1710 # result_dict contains the format {VM-id: {vim_result: 200, description: text}}
1711 if not result_dict or not isinstance(result_dict, dict):
garciadeblas5697b8b2021-03-24 09:17:02 +01001712 raise LcmException(
1713 "Unknown response from RO when injecting key"
1714 )
tierno69f0d382020-05-07 13:08:09 +00001715 for result in result_dict.values():
1716 if result.get("vim_result") == 200:
1717 break
1718 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001719 raise ROclient.ROClientException(
1720 "error injecting key: {}".format(
1721 result.get("description")
1722 )
1723 )
tierno69f0d382020-05-07 13:08:09 +00001724 break
1725 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001726 raise LcmException(
1727 "Reaching max tries injecting key. Error: {}".format(e)
1728 )
quilesj7e13aeb2019-10-08 13:34:55 +02001729 except ROclient.ROClientException as e:
tiernoa5088192019-11-26 16:12:53 +00001730 if not nb_tries:
garciadeblas5697b8b2021-03-24 09:17:02 +01001731 self.logger.debug(
1732 logging_text
1733 + "error injecting key: {}. Retrying until {} seconds".format(
1734 e, 20 * 10
1735 )
1736 )
quilesj7e13aeb2019-10-08 13:34:55 +02001737 nb_tries += 1
tiernoa5088192019-11-26 16:12:53 +00001738 if nb_tries >= 20:
garciadeblas5697b8b2021-03-24 09:17:02 +01001739 raise LcmException(
1740 "Reaching max tries injecting key. Error: {}".format(e)
1741 )
quilesj7e13aeb2019-10-08 13:34:55 +02001742 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001743 break
1744
1745 return ip_address
1746
tierno5ee02052019-12-05 19:55:02 +00001747 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1748 """
1749 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1750 """
1751 my_vca = vca_deployed_list[vca_index]
1752 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001753 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001754 return
1755 timeout = 300
1756 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001757 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1758 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1759 configuration_status_list = db_nsr["configurationStatus"]
1760 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001761 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001762 # myself
tierno5ee02052019-12-05 19:55:02 +00001763 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001764 if not my_vca.get("member-vnf-index") or (
1765 vca_deployed.get("member-vnf-index")
1766 == my_vca.get("member-vnf-index")
1767 ):
quilesj3655ae02019-12-12 16:08:35 +00001768 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001769 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001770 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001771 elif internal_status == "BROKEN":
1772 raise LcmException(
1773 "Configuration aborted because dependent charm/s has failed"
1774 )
quilesj3655ae02019-12-12 16:08:35 +00001775 else:
1776 break
tierno5ee02052019-12-05 19:55:02 +00001777 else:
quilesj3655ae02019-12-12 16:08:35 +00001778 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001779 return
1780 await asyncio.sleep(10)
1781 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001782
1783 raise LcmException("Configuration aborted because dependent charm/s timeout")
1784
David Garciac1fe90a2021-03-31 19:12:02 +02001785 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001786 vca_id = None
1787 if db_vnfr:
1788 vca_id = deep_get(db_vnfr, ("vca-id",))
1789 elif db_nsr:
1790 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1791 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1792 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001793
garciadeblas5697b8b2021-03-24 09:17:02 +01001794 async def instantiate_N2VC(
1795 self,
1796 logging_text,
1797 vca_index,
1798 nsi_id,
1799 db_nsr,
1800 db_vnfr,
1801 vdu_id,
1802 kdu_name,
1803 vdu_index,
1804 config_descriptor,
1805 deploy_params,
1806 base_folder,
1807 nslcmop_id,
1808 stage,
1809 vca_type,
1810 vca_name,
1811 ee_config_descriptor,
1812 ):
tiernod8323042019-08-09 11:32:23 +00001813 nsr_id = db_nsr["_id"]
1814 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001815 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001816 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001817 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001818 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001819 "collection": "nsrs",
1820 "filter": {"_id": nsr_id},
1821 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001822 }
tiernod8323042019-08-09 11:32:23 +00001823 step = ""
1824 try:
quilesj3655ae02019-12-12 16:08:35 +00001825
garciadeblas5697b8b2021-03-24 09:17:02 +01001826 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001827 element_under_configuration = nsr_id
1828
tiernod8323042019-08-09 11:32:23 +00001829 vnfr_id = None
1830 if db_vnfr:
1831 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001832 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001833
garciadeblas5697b8b2021-03-24 09:17:02 +01001834 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001835
aktas98488ed2021-07-29 17:42:49 +03001836 if vca_type == "native_charm":
1837 index_number = 0
1838 else:
1839 index_number = vdu_index or 0
1840
tiernod8323042019-08-09 11:32:23 +00001841 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001842 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001843 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001844 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001845 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001846 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001847 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001848 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001849 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001850 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001851 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001852 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001853 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001854 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001855
1856 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001857 if base_folder["pkg-dir"]:
1858 artifact_path = "{}/{}/{}/{}".format(
1859 base_folder["folder"],
1860 base_folder["pkg-dir"],
1861 "charms"
aticig15db6142022-01-24 12:51:26 +03001862 if vca_type
1863 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001864 else "helm-charts",
1865 vca_name,
1866 )
1867 else:
1868 artifact_path = "{}/Scripts/{}/{}/".format(
1869 base_folder["folder"],
1870 "charms"
aticig15db6142022-01-24 12:51:26 +03001871 if vca_type
1872 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001873 else "helm-charts",
1874 vca_name,
1875 )
bravof922c4172020-11-24 21:21:43 -03001876
1877 self.logger.debug("Artifact path > {}".format(artifact_path))
1878
tiernoa278b842020-07-08 15:33:55 +00001879 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001880 initial_config_primitive_list = config_descriptor.get(
1881 "initial-config-primitive"
1882 )
tiernoa278b842020-07-08 15:33:55 +00001883
garciadeblas5697b8b2021-03-24 09:17:02 +01001884 self.logger.debug(
1885 "Initial config primitive list > {}".format(
1886 initial_config_primitive_list
1887 )
1888 )
bravof922c4172020-11-24 21:21:43 -03001889
tiernoa278b842020-07-08 15:33:55 +00001890 # add config if not present for NS charm
1891 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001892 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001893 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1894 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1895 )
tiernod8323042019-08-09 11:32:23 +00001896
garciadeblas5697b8b2021-03-24 09:17:02 +01001897 self.logger.debug(
1898 "Initial config primitive list #2 > {}".format(
1899 initial_config_primitive_list
1900 )
1901 )
tierno588547c2020-07-01 15:30:20 +00001902 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001903 # find old ee_id if exists
1904 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001905
David Garciac1fe90a2021-03-31 19:12:02 +02001906 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001907 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001908 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
quilesj7e13aeb2019-10-08 13:34:55 +02001909
tierno588547c2020-07-01 15:30:20 +00001910 self._write_configuration_status(
1911 nsr_id=nsr_id,
1912 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001913 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001914 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001915 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001916 )
tiernod8323042019-08-09 11:32:23 +00001917
tierno588547c2020-07-01 15:30:20 +00001918 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001919 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001920
1921 ee_id = None
1922 credentials = None
1923 if vca_type == "k8s_proxy_charm":
1924 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001925 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001926 namespace=namespace,
1927 artifact_path=artifact_path,
1928 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001929 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001930 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001931 elif vca_type == "helm" or vca_type == "helm-v3":
1932 ee_id, credentials = await self.vca_map[
1933 vca_type
1934 ].create_execution_environment(
bravof922c4172020-11-24 21:21:43 -03001935 namespace=namespace,
1936 reuse_ee_id=ee_id,
1937 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001938 config=osm_config,
1939 artifact_path=artifact_path,
garciadeblas1d8aa812022-06-08 13:13:13 +02001940 chart_model=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01001941 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001942 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001943 else:
1944 ee_id, credentials = await self.vca_map[
1945 vca_type
1946 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001947 namespace=namespace,
1948 reuse_ee_id=ee_id,
1949 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001950 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001951 )
quilesj3655ae02019-12-12 16:08:35 +00001952
tierno588547c2020-07-01 15:30:20 +00001953 elif vca_type == "native_charm":
1954 step = "Waiting to VM being up and getting IP address"
1955 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001956 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1957 logging_text,
1958 nsr_id,
1959 vnfr_id,
1960 vdu_id,
1961 vdu_index,
1962 user=None,
1963 pub_key=None,
1964 )
tierno588547c2020-07-01 15:30:20 +00001965 credentials = {"hostname": rw_mgmt_ip}
1966 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001967 username = deep_get(
1968 config_descriptor, ("config-access", "ssh-access", "default-user")
1969 )
tierno588547c2020-07-01 15:30:20 +00001970 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1971 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001972 if not username and initial_config_primitive_list:
1973 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001974 for param in config_primitive.get("parameter", ()):
1975 if param["name"] == "ssh-username":
1976 username = param["value"]
1977 break
1978 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001979 raise LcmException(
1980 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1981 "'config-access.ssh-access.default-user'"
1982 )
tierno588547c2020-07-01 15:30:20 +00001983 credentials["username"] = username
1984 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001985
tierno588547c2020-07-01 15:30:20 +00001986 self._write_configuration_status(
1987 nsr_id=nsr_id,
1988 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001989 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001990 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001991 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001992 )
quilesj3655ae02019-12-12 16:08:35 +00001993
tierno588547c2020-07-01 15:30:20 +00001994 step = "register execution environment {}".format(credentials)
1995 self.logger.debug(logging_text + step)
1996 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001997 credentials=credentials,
1998 namespace=namespace,
1999 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02002000 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01002001 )
tierno3bedc9b2019-11-27 15:46:57 +00002002
tierno588547c2020-07-01 15:30:20 +00002003 # for compatibility with MON/POL modules, the need model and application name at database
2004 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01002005 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00002006 db_nsr_update = {db_update_entry + "ee_id": ee_id}
2007 if len(ee_id_parts) >= 2:
2008 model_name = ee_id_parts[0]
2009 application_name = ee_id_parts[1]
2010 db_nsr_update[db_update_entry + "model"] = model_name
2011 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00002012
2013 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00002014 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00002015
tiernoc231a872020-01-21 08:49:05 +00002016 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00002017 nsr_id=nsr_id,
2018 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01002019 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00002020 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00002021 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01002022 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00002023 )
2024
tierno3bedc9b2019-11-27 15:46:57 +00002025 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02002026 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02002027 config = None
tierno588547c2020-07-01 15:30:20 +00002028 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01002029 config_primitive = next(
2030 (p for p in initial_config_primitive_list if p["name"] == "config"),
2031 None,
2032 )
tiernoa278b842020-07-08 15:33:55 +00002033 if config_primitive:
2034 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01002035 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00002036 )
tierno588547c2020-07-01 15:30:20 +00002037 num_units = 1
2038 if vca_type == "lxc_proxy_charm":
2039 if element_type == "NS":
2040 num_units = db_nsr.get("config-units") or 1
2041 elif element_type == "VNF":
2042 num_units = db_vnfr.get("config-units") or 1
2043 elif element_type == "VDU":
2044 for v in db_vnfr["vdur"]:
2045 if vdu_id == v["vdu-id-ref"]:
2046 num_units = v.get("config-units") or 1
2047 break
David Garciaaae391f2020-11-09 11:12:54 +01002048 if vca_type != "k8s_proxy_charm":
2049 await self.vca_map[vca_type].install_configuration_sw(
2050 ee_id=ee_id,
2051 artifact_path=artifact_path,
2052 db_dict=db_dict,
2053 config=config,
2054 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02002055 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002056 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01002057 )
quilesj7e13aeb2019-10-08 13:34:55 +02002058
quilesj63f90042020-01-17 09:53:55 +00002059 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01002060 self.update_db_2(
2061 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
2062 )
quilesj63f90042020-01-17 09:53:55 +00002063
2064 # add relations for this VCA (wait for other peers related with this VCA)
garciadeblas5697b8b2021-03-24 09:17:02 +01002065 await self._add_vca_relations(
2066 logging_text=logging_text,
2067 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002068 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02002069 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01002070 )
quilesj63f90042020-01-17 09:53:55 +00002071
quilesj7e13aeb2019-10-08 13:34:55 +02002072 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02002073 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002074 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00002075 pub_key = None
2076 user = None
tierno588547c2020-07-01 15:30:20 +00002077 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01002078 if deep_get(
2079 config_descriptor, ("config-access", "ssh-access", "required")
2080 ):
tierno588547c2020-07-01 15:30:20 +00002081 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00002082 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01002083 user = deep_get(
2084 config_descriptor,
2085 ("config-access", "ssh-access", "default-user"),
2086 )
tierno3bedc9b2019-11-27 15:46:57 +00002087 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02002088 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01002089 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02002090 )
quilesj7e13aeb2019-10-08 13:34:55 +02002091
garciadeblas5697b8b2021-03-24 09:17:02 +01002092 step = "Insert public key into VM user={} ssh_key={}".format(
2093 user, pub_key
2094 )
tierno3bedc9b2019-11-27 15:46:57 +00002095 else:
tierno588547c2020-07-01 15:30:20 +00002096 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00002097 step = "Waiting to VM being up and getting IP address"
2098 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02002099
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002100 # default rw_mgmt_ip to None, avoiding the non definition of the variable
2101 rw_mgmt_ip = None
2102
tierno3bedc9b2019-11-27 15:46:57 +00002103 # n2vc_redesign STEP 5.1
2104 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00002105 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00002106 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02002107 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01002108 logging_text, nsr_id, vnfr_id, kdu_name
2109 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002110 vnfd = self.db.get_one(
2111 "vnfds_revisions",
2112 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
2113 )
2114 kdu = get_kdu(vnfd, kdu_name)
2115 kdu_services = [
2116 service["name"] for service in get_kdu_services(kdu)
2117 ]
2118 exposed_services = []
2119 for service in services:
2120 if any(s in service["name"] for s in kdu_services):
2121 exposed_services.append(service)
2122 await self.vca_map[vca_type].exec_primitive(
2123 ee_id=ee_id,
2124 primitive_name="config",
2125 params_dict={
2126 "osm-config": json.dumps(
2127 OsmConfigBuilder(
2128 k8s={"services": exposed_services}
2129 ).build()
2130 )
2131 },
2132 vca_id=vca_id,
2133 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002134
2135 # This verification is needed in order to avoid trying to add a public key
2136 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
2137 # for a KNF and not for its KDUs, the previous verification gives False, and the code
2138 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
2139 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00002140 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002141 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2142 logging_text,
2143 nsr_id,
2144 vnfr_id,
2145 vdu_id,
2146 vdu_index,
2147 user=user,
2148 pub_key=pub_key,
2149 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002150
garciadeblas5697b8b2021-03-24 09:17:02 +01002151 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02002152
tiernoa5088192019-11-26 16:12:53 +00002153 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02002154 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00002155
2156 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01002157 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00002158
2159 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00002160 if initial_config_primitive_list:
2161 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00002162
2163 # stage, in function of element type: vdu, kdu, vnf or ns
2164 my_vca = vca_deployed_list[vca_index]
2165 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
2166 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01002167 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00002168 elif my_vca.get("member-vnf-index"):
2169 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01002170 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00002171 else:
2172 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01002173 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00002174
tiernoc231a872020-01-21 08:49:05 +00002175 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002176 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002177 )
2178
garciadeblas5697b8b2021-03-24 09:17:02 +01002179 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002180
tiernoe876f672020-02-13 14:34:48 +00002181 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002182 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002183 # adding information on the vca_deployed if it is a NS execution environment
2184 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002185 deploy_params["ns_config_info"] = json.dumps(
2186 self._get_ns_config_info(nsr_id)
2187 )
tiernod8323042019-08-09 11:32:23 +00002188 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002189 primitive_params_ = self._map_primitive_params(
2190 initial_config_primitive, {}, deploy_params
2191 )
tierno3bedc9b2019-11-27 15:46:57 +00002192
garciadeblas5697b8b2021-03-24 09:17:02 +01002193 step = "execute primitive '{}' params '{}'".format(
2194 initial_config_primitive["name"], primitive_params_
2195 )
tiernod8323042019-08-09 11:32:23 +00002196 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002197 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002198 ee_id=ee_id,
2199 primitive_name=initial_config_primitive["name"],
2200 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002201 db_dict=db_dict,
2202 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002203 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002204 )
tiernoe876f672020-02-13 14:34:48 +00002205 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2206 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002207 if config_descriptor.get("terminate-config-primitive"):
2208 self.update_db_2(
2209 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2210 )
tiernoe876f672020-02-13 14:34:48 +00002211 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002212
tiernod8323042019-08-09 11:32:23 +00002213 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002214
tiernob996d942020-07-03 14:52:28 +00002215 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002216 if vca_type == "helm" or vca_type == "helm-v3":
garciadeblas1d8aa812022-06-08 13:13:13 +02002217 # TODO: review for those cases where the helm chart is a reference and
2218 # is not part of the NF package
bravof73bac502021-05-11 07:38:47 -04002219 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002220 ee_id=ee_id,
2221 artifact_path=artifact_path,
2222 ee_config_descriptor=ee_config_descriptor,
2223 vnfr_id=vnfr_id,
2224 nsr_id=nsr_id,
2225 target_ip=rw_mgmt_ip,
2226 )
2227 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002228 self.update_db_2(
2229 "nsrs",
2230 nsr_id,
2231 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2232 )
tiernob996d942020-07-03 14:52:28 +00002233
bravof73bac502021-05-11 07:38:47 -04002234 for job in prometheus_jobs:
2235 self.db.set_one(
2236 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002237 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002238 job,
2239 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002240 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002241 )
2242
quilesj7e13aeb2019-10-08 13:34:55 +02002243 step = "instantiated at VCA"
2244 self.logger.debug(logging_text + step)
2245
tiernoc231a872020-01-21 08:49:05 +00002246 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002247 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002248 )
2249
tiernod8323042019-08-09 11:32:23 +00002250 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002251 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002252 if not isinstance(
2253 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2254 ):
2255 self.logger.error(
2256 "Exception while {} : {}".format(step, e), exc_info=True
2257 )
tiernoc231a872020-01-21 08:49:05 +00002258 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002259 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002260 )
tiernoe876f672020-02-13 14:34:48 +00002261 raise LcmException("{} {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002262
garciadeblas5697b8b2021-03-24 09:17:02 +01002263 def _write_ns_status(
2264 self,
2265 nsr_id: str,
2266 ns_state: str,
2267 current_operation: str,
2268 current_operation_id: str,
2269 error_description: str = None,
2270 error_detail: str = None,
2271 other_update: dict = None,
2272 ):
tiernoe876f672020-02-13 14:34:48 +00002273 """
2274 Update db_nsr fields.
2275 :param nsr_id:
2276 :param ns_state:
2277 :param current_operation:
2278 :param current_operation_id:
2279 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002280 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002281 :param other_update: Other required changes at database if provided, will be cleared
2282 :return:
2283 """
quilesj4cda56b2019-12-05 10:02:20 +00002284 try:
tiernoe876f672020-02-13 14:34:48 +00002285 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002286 db_dict[
2287 "_admin.nslcmop"
2288 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002289 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002290 db_dict["_admin.operation-type"] = (
2291 current_operation if current_operation != "IDLE" else None
2292 )
quilesj4cda56b2019-12-05 10:02:20 +00002293 db_dict["currentOperation"] = current_operation
2294 db_dict["currentOperationID"] = current_operation_id
2295 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002296 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002297
2298 if ns_state:
2299 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002300 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002301 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002302 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002303
garciadeblas5697b8b2021-03-24 09:17:02 +01002304 def _write_op_status(
2305 self,
2306 op_id: str,
2307 stage: list = None,
2308 error_message: str = None,
2309 queuePosition: int = 0,
2310 operation_state: str = None,
2311 other_update: dict = None,
2312 ):
quilesj3655ae02019-12-12 16:08:35 +00002313 try:
tiernoe876f672020-02-13 14:34:48 +00002314 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002315 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002316 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002317 db_dict["stage"] = stage[0]
2318 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002319 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002320 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002321
2322 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002323 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002324 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002325 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002326 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002327 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002328 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002329 self.logger.warn(
2330 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2331 )
quilesj3655ae02019-12-12 16:08:35 +00002332
tierno51183952020-04-03 15:48:18 +00002333 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002334 try:
tierno51183952020-04-03 15:48:18 +00002335 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002336 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002337 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002338 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002339 db_nsr_update = {
2340 "configurationStatus.{}.status".format(index): status
2341 for index, v in enumerate(config_status)
2342 if v
2343 }
quilesj3655ae02019-12-12 16:08:35 +00002344 # update status
tierno51183952020-04-03 15:48:18 +00002345 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002346
tiernoe876f672020-02-13 14:34:48 +00002347 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002348 self.logger.warn(
2349 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2350 )
quilesj3655ae02019-12-12 16:08:35 +00002351
garciadeblas5697b8b2021-03-24 09:17:02 +01002352 def _write_configuration_status(
2353 self,
2354 nsr_id: str,
2355 vca_index: int,
2356 status: str = None,
2357 element_under_configuration: str = None,
2358 element_type: str = None,
2359 other_update: dict = None,
2360 ):
quilesj3655ae02019-12-12 16:08:35 +00002361
2362 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2363 # .format(vca_index, status))
2364
2365 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002366 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002367 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002368 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002369 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002370 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002371 db_dict[
2372 db_path + "elementUnderConfiguration"
2373 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002374 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002375 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002376 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002377 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002378 self.logger.warn(
2379 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2380 status, nsr_id, vca_index, e
2381 )
2382 )
quilesj4cda56b2019-12-05 10:02:20 +00002383
tierno38089af2020-04-16 07:56:58 +00002384 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2385 """
2386 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2387 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2388 Database is used because the result can be obtained from a different LCM worker in case of HA.
2389 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2390 :param db_nslcmop: database content of nslcmop
2391 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002392 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2393 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002394 """
tierno8790a3d2020-04-23 22:49:52 +00002395 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002396 nslcmop_id = db_nslcmop["_id"]
2397 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002398 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002399 self.logger.debug(
2400 logging_text + "Invoke and wait for placement optimization"
2401 )
2402 await self.msg.aiowrite(
2403 "pla", "get_placement", {"nslcmopId": nslcmop_id}, loop=self.loop
2404 )
magnussonle9198bb2020-01-21 13:00:51 +01002405 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002406 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002407 pla_result = None
2408 while not pla_result and wait >= 0:
2409 await asyncio.sleep(db_poll_interval)
2410 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002411 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002412 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002413
2414 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002415 raise LcmException(
2416 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2417 )
magnussonle9198bb2020-01-21 13:00:51 +01002418
garciadeblas5697b8b2021-03-24 09:17:02 +01002419 for pla_vnf in pla_result["vnf"]:
2420 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2421 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002422 continue
tierno8790a3d2020-04-23 22:49:52 +00002423 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002424 self.db.set_one(
2425 "vnfrs",
2426 {"_id": vnfr["_id"]},
2427 {"vim-account-id": pla_vnf["vimAccountId"]},
2428 )
tierno38089af2020-04-16 07:56:58 +00002429 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002430 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002431 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002432
2433 def update_nsrs_with_pla_result(self, params):
2434 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002435 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2436 self.update_db_2(
2437 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2438 )
magnussonle9198bb2020-01-21 13:00:51 +01002439 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002440 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002441
tierno59d22d22018-09-25 18:10:19 +02002442 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002443 """
2444
2445 :param nsr_id: ns instance to deploy
2446 :param nslcmop_id: operation to run
2447 :return:
2448 """
kuused124bfe2019-06-18 12:09:24 +02002449
2450 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002451 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002452 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002453 self.logger.debug(
2454 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2455 )
kuused124bfe2019-06-18 12:09:24 +02002456 return
2457
tierno59d22d22018-09-25 18:10:19 +02002458 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2459 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002460
tierno59d22d22018-09-25 18:10:19 +02002461 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002462
2463 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002464 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002465
2466 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002467 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002468
2469 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002470 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002471 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002472 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002473
tierno59d22d22018-09-25 18:10:19 +02002474 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002475 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002476 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002477 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002478 exc = None
tiernoe876f672020-02-13 14:34:48 +00002479 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002480 stage = [
2481 "Stage 1/5: preparation of the environment.",
2482 "Waiting for previous operations to terminate.",
2483 "",
2484 ]
tiernoe876f672020-02-13 14:34:48 +00002485 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002486 try:
kuused124bfe2019-06-18 12:09:24 +02002487 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002488 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002489
quilesj7e13aeb2019-10-08 13:34:55 +02002490 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002491 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002492 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002493 db_nsr_update["detailed-status"] = "creating"
2494 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002495 self._write_ns_status(
2496 nsr_id=nsr_id,
2497 ns_state="BUILDING",
2498 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002499 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002500 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002501 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002502 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002503
quilesj7e13aeb2019-10-08 13:34:55 +02002504 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002505 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002506 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002507 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2508 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2509 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2510 )
tierno744303e2020-01-13 16:46:31 +00002511 ns_params = db_nslcmop.get("operationParams")
2512 if ns_params and ns_params.get("timeout_ns_deploy"):
2513 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
2514 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01002515 timeout_ns_deploy = self.timeout.get(
2516 "ns_deploy", self.timeout_ns_deploy
2517 )
quilesj7e13aeb2019-10-08 13:34:55 +02002518
2519 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002520 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002521 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002522 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002523 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002524 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002525 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002526 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002527 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002528 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002529
quilesj7e13aeb2019-10-08 13:34:55 +02002530 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002531 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002532 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002533 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002534
quilesj7e13aeb2019-10-08 13:34:55 +02002535 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002536 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002537
2538 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002539 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002540 if vnfr.get("kdur"):
2541 kdur_list = []
2542 for kdur in vnfr["kdur"]:
2543 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002544 kdur["additionalParams"] = json.loads(
2545 kdur["additionalParams"]
2546 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002547 kdur_list.append(kdur)
2548 vnfr["kdur"] = kdur_list
2549
bravof922c4172020-11-24 21:21:43 -03002550 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2551 vnfd_id = vnfr["vnfd-id"]
2552 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002553 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002554
quilesj7e13aeb2019-10-08 13:34:55 +02002555 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002556 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002557 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002558 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2559 vnfd_id, vnfd_ref
2560 )
tiernoe876f672020-02-13 14:34:48 +00002561 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002562 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002563
quilesj7e13aeb2019-10-08 13:34:55 +02002564 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002565 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002566
2567 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002568 vca_deployed_list = None
2569 if db_nsr["_admin"].get("deployed"):
2570 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2571 if vca_deployed_list is None:
2572 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002573 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002574 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002575 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002576 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002577 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002578 elif isinstance(vca_deployed_list, dict):
2579 # maintain backward compatibility. Change a dict to list at database
2580 vca_deployed_list = list(vca_deployed_list.values())
2581 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002582 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002583
garciadeblas5697b8b2021-03-24 09:17:02 +01002584 if not isinstance(
2585 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2586 ):
tiernoa009e552019-01-30 16:45:44 +00002587 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2588 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002589
tiernobaa51102018-12-14 13:16:18 +00002590 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2591 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2592 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002593 self.db.set_list(
2594 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2595 )
quilesj3655ae02019-12-12 16:08:35 +00002596
2597 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002598 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2599 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002600
tiernob5203912020-08-11 11:20:13 +00002601 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002602 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002603 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002604 await self.deploy_kdus(
2605 logging_text=logging_text,
2606 nsr_id=nsr_id,
2607 nslcmop_id=nslcmop_id,
2608 db_vnfrs=db_vnfrs,
2609 db_vnfds=db_vnfds,
2610 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002611 )
tiernoe876f672020-02-13 14:34:48 +00002612
2613 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002614 # n2vc_redesign STEP 1 Get VCA public ssh-key
2615 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002616 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002617 n2vc_key_list = [n2vc_key]
2618 if self.vca_config.get("public_key"):
2619 n2vc_key_list.append(self.vca_config["public_key"])
tierno98ad6ea2019-05-30 17:16:28 +00002620
tiernoe876f672020-02-13 14:34:48 +00002621 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002622 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002623 self.instantiate_RO(
2624 logging_text=logging_text,
2625 nsr_id=nsr_id,
2626 nsd=nsd,
2627 db_nsr=db_nsr,
2628 db_nslcmop=db_nslcmop,
2629 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002630 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002631 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002632 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002633 )
tiernod8323042019-08-09 11:32:23 +00002634 )
2635 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002636 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002637
tiernod8323042019-08-09 11:32:23 +00002638 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002639 stage[1] = "Deploying Execution Environments."
2640 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002641
Gabriel Cuba1411a002022-10-07 11:38:23 -05002642 # create namespace and certificate if any helm based EE is present in the NS
2643 if check_helm_ee_in_ns(db_vnfds):
2644 # TODO: create EE namespace
2645 # create TLS certificates
2646 await self.vca_map["helm-v3"].create_tls_certificate(
2647 secret_name="ee-tls-{}".format(nsr_id),
2648 dns_prefix="*",
2649 nsr_id=nsr_id,
2650 usage="server auth",
2651 )
2652
tiernod8323042019-08-09 11:32:23 +00002653 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002654 for vnf_profile in get_vnf_profiles(nsd):
2655 vnfd_id = vnf_profile["vnfd-id"]
2656 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2657 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002658 db_vnfr = db_vnfrs[member_vnf_index]
2659 base_folder = vnfd["_admin"]["storage"]
2660 vdu_id = None
2661 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002662 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002663 kdu_name = None
tierno59d22d22018-09-25 18:10:19 +02002664
tierno8a518872018-12-21 13:42:14 +00002665 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002666 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002667 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002668 deploy_params.update(
2669 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2670 )
tierno8a518872018-12-21 13:42:14 +00002671
bravofe5a31bc2021-02-17 19:09:12 -03002672 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002673 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002674 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002675 logging_text=logging_text
2676 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002677 db_nsr=db_nsr,
2678 db_vnfr=db_vnfr,
2679 nslcmop_id=nslcmop_id,
2680 nsr_id=nsr_id,
2681 nsi_id=nsi_id,
2682 vnfd_id=vnfd_id,
2683 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002684 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002685 member_vnf_index=member_vnf_index,
2686 vdu_index=vdu_index,
2687 vdu_name=vdu_name,
2688 deploy_params=deploy_params,
2689 descriptor_config=descriptor_config,
2690 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002691 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002692 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002693 )
tierno59d22d22018-09-25 18:10:19 +02002694
2695 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002696 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002697 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002698 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002699 vdur = find_in_list(
2700 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2701 )
bravof922c4172020-11-24 21:21:43 -03002702
tierno626e0152019-11-29 14:16:16 +00002703 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002704 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002705 else:
2706 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002707 deploy_params_vdu["OSM"] = get_osm_params(
2708 db_vnfr, vdu_id, vdu_count_index=0
2709 )
endika76ba9232021-06-21 18:55:07 +02002710 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002711
2712 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002713 self.logger.debug(
2714 "Descriptor config > {}".format(descriptor_config)
2715 )
tierno588547c2020-07-01 15:30:20 +00002716 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002717 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002718 kdu_name = None
bravof922c4172020-11-24 21:21:43 -03002719 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002720 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002721 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002722 logging_text=logging_text
2723 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2724 member_vnf_index, vdu_id, vdu_index
2725 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002726 db_nsr=db_nsr,
2727 db_vnfr=db_vnfr,
2728 nslcmop_id=nslcmop_id,
2729 nsr_id=nsr_id,
2730 nsi_id=nsi_id,
2731 vnfd_id=vnfd_id,
2732 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002733 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002734 member_vnf_index=member_vnf_index,
2735 vdu_index=vdu_index,
2736 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002737 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002738 descriptor_config=descriptor_config,
2739 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002740 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002741 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002742 )
bravof922c4172020-11-24 21:21:43 -03002743 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002744 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002745 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002746 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002747 vdu_id = None
2748 vdu_index = 0
2749 vdu_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002750 kdur = next(
2751 x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name
2752 )
bravof922c4172020-11-24 21:21:43 -03002753 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002754 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002755 deploy_params_kdu.update(
2756 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002757 )
tierno59d22d22018-09-25 18:10:19 +02002758
calvinosanch9f9c6f22019-11-04 13:37:39 +01002759 self._deploy_n2vc(
2760 logging_text=logging_text,
2761 db_nsr=db_nsr,
2762 db_vnfr=db_vnfr,
2763 nslcmop_id=nslcmop_id,
2764 nsr_id=nsr_id,
2765 nsi_id=nsi_id,
2766 vnfd_id=vnfd_id,
2767 vdu_id=vdu_id,
2768 kdu_name=kdu_name,
2769 member_vnf_index=member_vnf_index,
2770 vdu_index=vdu_index,
2771 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002772 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002773 descriptor_config=descriptor_config,
2774 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002775 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002776 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002777 )
tierno59d22d22018-09-25 18:10:19 +02002778
tierno1b633412019-02-25 16:48:23 +00002779 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002780 descriptor_config = nsd.get("ns-configuration")
2781 if descriptor_config and descriptor_config.get("juju"):
2782 vnfd_id = None
2783 db_vnfr = None
2784 member_vnf_index = None
2785 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002786 kdu_name = None
tiernod8323042019-08-09 11:32:23 +00002787 vdu_index = 0
2788 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002789
tiernod8323042019-08-09 11:32:23 +00002790 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002791 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002792 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002793 deploy_params.update(
2794 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2795 )
tiernod8323042019-08-09 11:32:23 +00002796 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002797 self._deploy_n2vc(
2798 logging_text=logging_text,
2799 db_nsr=db_nsr,
2800 db_vnfr=db_vnfr,
2801 nslcmop_id=nslcmop_id,
2802 nsr_id=nsr_id,
2803 nsi_id=nsi_id,
2804 vnfd_id=vnfd_id,
2805 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002806 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002807 member_vnf_index=member_vnf_index,
2808 vdu_index=vdu_index,
2809 vdu_name=vdu_name,
2810 deploy_params=deploy_params,
2811 descriptor_config=descriptor_config,
2812 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002813 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002814 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002815 )
tierno1b633412019-02-25 16:48:23 +00002816
tiernoe876f672020-02-13 14:34:48 +00002817 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002818
garciadeblas5697b8b2021-03-24 09:17:02 +01002819 except (
2820 ROclient.ROClientException,
2821 DbException,
2822 LcmException,
2823 N2VCException,
2824 ) as e:
2825 self.logger.error(
2826 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
2827 )
tierno59d22d22018-09-25 18:10:19 +02002828 exc = e
2829 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01002830 self.logger.error(
2831 logging_text + "Cancelled Exception while '{}'".format(stage[1])
2832 )
tierno59d22d22018-09-25 18:10:19 +02002833 exc = "Operation was cancelled"
2834 except Exception as e:
2835 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01002836 self.logger.critical(
2837 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
2838 exc_info=True,
2839 )
tierno59d22d22018-09-25 18:10:19 +02002840 finally:
2841 if exc:
tiernoe876f672020-02-13 14:34:48 +00002842 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00002843 try:
tiernoe876f672020-02-13 14:34:48 +00002844 # wait for pending tasks
2845 if tasks_dict_info:
2846 stage[1] = "Waiting for instantiate pending tasks."
2847 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01002848 error_list += await self._wait_for_tasks(
2849 logging_text,
2850 tasks_dict_info,
2851 timeout_ns_deploy,
2852 stage,
2853 nslcmop_id,
2854 nsr_id=nsr_id,
2855 )
tiernoe876f672020-02-13 14:34:48 +00002856 stage[1] = stage[2] = ""
2857 except asyncio.CancelledError:
2858 error_list.append("Cancelled")
2859 # TODO cancel all tasks
2860 except Exception as exc:
2861 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00002862
tiernoe876f672020-02-13 14:34:48 +00002863 # update operation-status
2864 db_nsr_update["operational-status"] = "running"
2865 # let's begin with VCA 'configured' status (later we can change it)
2866 db_nsr_update["config-status"] = "configured"
2867 for task, task_name in tasks_dict_info.items():
2868 if not task.done() or task.cancelled() or task.exception():
2869 if task_name.startswith(self.task_name_deploy_vca):
2870 # A N2VC task is pending
2871 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00002872 else:
tiernoe876f672020-02-13 14:34:48 +00002873 # RO or KDU task is pending
2874 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00002875
tiernoe876f672020-02-13 14:34:48 +00002876 # update status at database
2877 if error_list:
tiernoa2143262020-03-27 16:20:40 +00002878 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00002879 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01002880 error_description_nslcmop = "{} Detail: {}".format(
2881 stage[0], error_detail
2882 )
2883 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
2884 nslcmop_id, stage[0]
2885 )
quilesj3655ae02019-12-12 16:08:35 +00002886
garciadeblas5697b8b2021-03-24 09:17:02 +01002887 db_nsr_update["detailed-status"] = (
2888 error_description_nsr + " Detail: " + error_detail
2889 )
tiernoe876f672020-02-13 14:34:48 +00002890 db_nslcmop_update["detailed-status"] = error_detail
2891 nslcmop_operation_state = "FAILED"
2892 ns_state = "BROKEN"
2893 else:
tiernoa2143262020-03-27 16:20:40 +00002894 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00002895 error_description_nsr = error_description_nslcmop = None
2896 ns_state = "READY"
2897 db_nsr_update["detailed-status"] = "Done"
2898 db_nslcmop_update["detailed-status"] = "Done"
2899 nslcmop_operation_state = "COMPLETED"
quilesj4cda56b2019-12-05 10:02:20 +00002900
tiernoe876f672020-02-13 14:34:48 +00002901 if db_nsr:
2902 self._write_ns_status(
2903 nsr_id=nsr_id,
2904 ns_state=ns_state,
2905 current_operation="IDLE",
2906 current_operation_id=None,
2907 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00002908 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01002909 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002910 )
tiernoa17d4f42020-04-28 09:59:23 +00002911 self._write_op_status(
2912 op_id=nslcmop_id,
2913 stage="",
2914 error_message=error_description_nslcmop,
2915 operation_state=nslcmop_operation_state,
2916 other_update=db_nslcmop_update,
2917 )
quilesj3655ae02019-12-12 16:08:35 +00002918
tierno59d22d22018-09-25 18:10:19 +02002919 if nslcmop_operation_state:
2920 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002921 await self.msg.aiowrite(
2922 "ns",
2923 "instantiated",
2924 {
2925 "nsr_id": nsr_id,
2926 "nslcmop_id": nslcmop_id,
2927 "operationState": nslcmop_operation_state,
2928 },
2929 loop=self.loop,
2930 )
tierno59d22d22018-09-25 18:10:19 +02002931 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002932 self.logger.error(
2933 logging_text + "kafka_write notification Exception {}".format(e)
2934 )
tierno59d22d22018-09-25 18:10:19 +02002935
2936 self.logger.debug(logging_text + "Exit")
2937 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
2938
David Garciab4ebcd02021-10-28 02:00:43 +02002939 def _get_vnfd(self, vnfd_id: str, cached_vnfds: Dict[str, Any]):
2940 if vnfd_id not in cached_vnfds:
2941 cached_vnfds[vnfd_id] = self.db.get_one("vnfds", {"id": vnfd_id})
2942 return cached_vnfds[vnfd_id]
2943
2944 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
2945 if vnf_profile_id not in cached_vnfrs:
2946 cached_vnfrs[vnf_profile_id] = self.db.get_one(
2947 "vnfrs",
2948 {
2949 "member-vnf-index-ref": vnf_profile_id,
2950 "nsr-id-ref": nsr_id,
2951 },
2952 )
2953 return cached_vnfrs[vnf_profile_id]
2954
2955 def _is_deployed_vca_in_relation(
2956 self, vca: DeployedVCA, relation: Relation
2957 ) -> bool:
2958 found = False
2959 for endpoint in (relation.provider, relation.requirer):
2960 if endpoint["kdu-resource-profile-id"]:
2961 continue
2962 found = (
2963 vca.vnf_profile_id == endpoint.vnf_profile_id
2964 and vca.vdu_profile_id == endpoint.vdu_profile_id
2965 and vca.execution_environment_ref == endpoint.execution_environment_ref
2966 )
2967 if found:
2968 break
2969 return found
2970
2971 def _update_ee_relation_data_with_implicit_data(
2972 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
2973 ):
2974 ee_relation_data = safe_get_ee_relation(
2975 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
2976 )
2977 ee_relation_level = EELevel.get_level(ee_relation_data)
2978 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
2979 "execution-environment-ref"
2980 ]:
2981 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
2982 vnfd_id = vnf_profile["vnfd-id"]
2983 db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
2984 entity_id = (
2985 vnfd_id
2986 if ee_relation_level == EELevel.VNF
2987 else ee_relation_data["vdu-profile-id"]
2988 )
2989 ee = get_juju_ee_ref(db_vnfd, entity_id)
2990 if not ee:
2991 raise Exception(
2992 f"not execution environments found for ee_relation {ee_relation_data}"
2993 )
2994 ee_relation_data["execution-environment-ref"] = ee["id"]
2995 return ee_relation_data
2996
2997 def _get_ns_relations(
2998 self,
2999 nsr_id: str,
3000 nsd: Dict[str, Any],
3001 vca: DeployedVCA,
3002 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003003 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003004 relations = []
3005 db_ns_relations = get_ns_configuration_relation_list(nsd)
3006 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01003007 provider_dict = None
3008 requirer_dict = None
3009 if all(key in r for key in ("provider", "requirer")):
3010 provider_dict = r["provider"]
3011 requirer_dict = r["requirer"]
3012 elif "entities" in r:
3013 provider_id = r["entities"][0]["id"]
3014 provider_dict = {
3015 "nsr-id": nsr_id,
3016 "endpoint": r["entities"][0]["endpoint"],
3017 }
3018 if provider_id != nsd["id"]:
3019 provider_dict["vnf-profile-id"] = provider_id
3020 requirer_id = r["entities"][1]["id"]
3021 requirer_dict = {
3022 "nsr-id": nsr_id,
3023 "endpoint": r["entities"][1]["endpoint"],
3024 }
3025 if requirer_id != nsd["id"]:
3026 requirer_dict["vnf-profile-id"] = requirer_id
3027 else:
aticig15db6142022-01-24 12:51:26 +03003028 raise Exception(
3029 "provider/requirer or entities must be included in the relation."
3030 )
David Garciab4ebcd02021-10-28 02:00:43 +02003031 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003032 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003033 )
3034 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003035 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02003036 )
3037 provider = EERelation(relation_provider)
3038 requirer = EERelation(relation_requirer)
3039 relation = Relation(r["name"], provider, requirer)
3040 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3041 if vca_in_relation:
3042 relations.append(relation)
3043 return relations
3044
3045 def _get_vnf_relations(
3046 self,
3047 nsr_id: str,
3048 nsd: Dict[str, Any],
3049 vca: DeployedVCA,
3050 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003051 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003052 relations = []
3053 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3054 vnf_profile_id = vnf_profile["id"]
3055 vnfd_id = vnf_profile["vnfd-id"]
3056 db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
3057 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3058 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003059 provider_dict = None
3060 requirer_dict = None
3061 if all(key in r for key in ("provider", "requirer")):
3062 provider_dict = r["provider"]
3063 requirer_dict = r["requirer"]
3064 elif "entities" in r:
3065 provider_id = r["entities"][0]["id"]
3066 provider_dict = {
3067 "nsr-id": nsr_id,
3068 "vnf-profile-id": vnf_profile_id,
3069 "endpoint": r["entities"][0]["endpoint"],
3070 }
3071 if provider_id != vnfd_id:
3072 provider_dict["vdu-profile-id"] = provider_id
3073 requirer_id = r["entities"][1]["id"]
3074 requirer_dict = {
3075 "nsr-id": nsr_id,
3076 "vnf-profile-id": vnf_profile_id,
3077 "endpoint": r["entities"][1]["endpoint"],
3078 }
3079 if requirer_id != vnfd_id:
3080 requirer_dict["vdu-profile-id"] = requirer_id
3081 else:
aticig15db6142022-01-24 12:51:26 +03003082 raise Exception(
3083 "provider/requirer or entities must be included in the relation."
3084 )
David Garciab4ebcd02021-10-28 02:00:43 +02003085 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003086 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003087 )
3088 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003089 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003090 )
3091 provider = EERelation(relation_provider)
3092 requirer = EERelation(relation_requirer)
3093 relation = Relation(r["name"], provider, requirer)
3094 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3095 if vca_in_relation:
3096 relations.append(relation)
3097 return relations
3098
3099 def _get_kdu_resource_data(
3100 self,
3101 ee_relation: EERelation,
3102 db_nsr: Dict[str, Any],
3103 cached_vnfds: Dict[str, Any],
3104 ) -> DeployedK8sResource:
3105 nsd = get_nsd(db_nsr)
3106 vnf_profiles = get_vnf_profiles(nsd)
3107 vnfd_id = find_in_list(
3108 vnf_profiles,
3109 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3110 )["vnfd-id"]
3111 db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
3112 kdu_resource_profile = get_kdu_resource_profile(
3113 db_vnfd, ee_relation.kdu_resource_profile_id
3114 )
3115 kdu_name = kdu_resource_profile["kdu-name"]
3116 deployed_kdu, _ = get_deployed_kdu(
3117 db_nsr.get("_admin", ()).get("deployed", ()),
3118 kdu_name,
3119 ee_relation.vnf_profile_id,
3120 )
3121 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3122 return deployed_kdu
3123
3124 def _get_deployed_component(
3125 self,
3126 ee_relation: EERelation,
3127 db_nsr: Dict[str, Any],
3128 cached_vnfds: Dict[str, Any],
3129 ) -> DeployedComponent:
3130 nsr_id = db_nsr["_id"]
3131 deployed_component = None
3132 ee_level = EELevel.get_level(ee_relation)
3133 if ee_level == EELevel.NS:
3134 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3135 if vca:
3136 deployed_component = DeployedVCA(nsr_id, vca)
3137 elif ee_level == EELevel.VNF:
3138 vca = get_deployed_vca(
3139 db_nsr,
3140 {
3141 "vdu_id": None,
3142 "member-vnf-index": ee_relation.vnf_profile_id,
3143 "ee_descriptor_id": ee_relation.execution_environment_ref,
3144 },
3145 )
3146 if vca:
3147 deployed_component = DeployedVCA(nsr_id, vca)
3148 elif ee_level == EELevel.VDU:
3149 vca = get_deployed_vca(
3150 db_nsr,
3151 {
3152 "vdu_id": ee_relation.vdu_profile_id,
3153 "member-vnf-index": ee_relation.vnf_profile_id,
3154 "ee_descriptor_id": ee_relation.execution_environment_ref,
3155 },
3156 )
3157 if vca:
3158 deployed_component = DeployedVCA(nsr_id, vca)
3159 elif ee_level == EELevel.KDU:
3160 kdu_resource_data = self._get_kdu_resource_data(
3161 ee_relation, db_nsr, cached_vnfds
3162 )
3163 if kdu_resource_data:
3164 deployed_component = DeployedK8sResource(kdu_resource_data)
3165 return deployed_component
3166
3167 async def _add_relation(
3168 self,
3169 relation: Relation,
3170 vca_type: str,
3171 db_nsr: Dict[str, Any],
3172 cached_vnfds: Dict[str, Any],
3173 cached_vnfrs: Dict[str, Any],
3174 ) -> bool:
3175 deployed_provider = self._get_deployed_component(
3176 relation.provider, db_nsr, cached_vnfds
3177 )
3178 deployed_requirer = self._get_deployed_component(
3179 relation.requirer, db_nsr, cached_vnfds
3180 )
3181 if (
3182 deployed_provider
3183 and deployed_requirer
3184 and deployed_provider.config_sw_installed
3185 and deployed_requirer.config_sw_installed
3186 ):
3187 provider_db_vnfr = (
3188 self._get_vnfr(
3189 relation.provider.nsr_id,
3190 relation.provider.vnf_profile_id,
3191 cached_vnfrs,
3192 )
3193 if relation.provider.vnf_profile_id
3194 else None
3195 )
3196 requirer_db_vnfr = (
3197 self._get_vnfr(
3198 relation.requirer.nsr_id,
3199 relation.requirer.vnf_profile_id,
3200 cached_vnfrs,
3201 )
3202 if relation.requirer.vnf_profile_id
3203 else None
3204 )
3205 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3206 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3207 provider_relation_endpoint = RelationEndpoint(
3208 deployed_provider.ee_id,
3209 provider_vca_id,
3210 relation.provider.endpoint,
3211 )
3212 requirer_relation_endpoint = RelationEndpoint(
3213 deployed_requirer.ee_id,
3214 requirer_vca_id,
3215 relation.requirer.endpoint,
3216 )
3217 await self.vca_map[vca_type].add_relation(
3218 provider=provider_relation_endpoint,
3219 requirer=requirer_relation_endpoint,
3220 )
3221 # remove entry from relations list
3222 return True
3223 return False
3224
David Garciac1fe90a2021-03-31 19:12:02 +02003225 async def _add_vca_relations(
3226 self,
3227 logging_text,
3228 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003229 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003230 vca_index: int,
3231 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003232 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003233
3234 # steps:
3235 # 1. find all relations for this VCA
3236 # 2. wait for other peers related
3237 # 3. add relations
3238
3239 try:
quilesj63f90042020-01-17 09:53:55 +00003240 # STEP 1: find all relations for this VCA
3241
3242 # read nsr record
3243 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003244 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003245
3246 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003247 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3248 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003249
David Garciab4ebcd02021-10-28 02:00:43 +02003250 cached_vnfds = {}
3251 cached_vnfrs = {}
3252 relations = []
3253 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3254 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003255
3256 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003257 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003258 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003259 return True
3260
David Garciab4ebcd02021-10-28 02:00:43 +02003261 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003262
3263 # add all relations
3264 start = time()
3265 while True:
3266 # check timeout
3267 now = time()
3268 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003269 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003270 return False
3271
David Garciab4ebcd02021-10-28 02:00:43 +02003272 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003273 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3274
David Garciab4ebcd02021-10-28 02:00:43 +02003275 # for each relation, find the VCA's related
3276 for relation in relations.copy():
3277 added = await self._add_relation(
3278 relation,
3279 vca_type,
3280 db_nsr,
3281 cached_vnfds,
3282 cached_vnfrs,
3283 )
3284 if added:
3285 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003286
David Garciab4ebcd02021-10-28 02:00:43 +02003287 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003288 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003289 break
David Garciab4ebcd02021-10-28 02:00:43 +02003290 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003291
3292 return True
3293
3294 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003295 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003296 return False
3297
garciadeblas5697b8b2021-03-24 09:17:02 +01003298 async def _install_kdu(
3299 self,
3300 nsr_id: str,
3301 nsr_db_path: str,
3302 vnfr_data: dict,
3303 kdu_index: int,
3304 kdud: dict,
3305 vnfd: dict,
3306 k8s_instance_info: dict,
3307 k8params: dict = None,
3308 timeout: int = 600,
3309 vca_id: str = None,
3310 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003311
tiernob9018152020-04-16 14:18:24 +00003312 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003313 k8sclustertype = k8s_instance_info["k8scluster-type"]
3314 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003315 db_dict_install = {
3316 "collection": "nsrs",
3317 "filter": {"_id": nsr_id},
3318 "path": nsr_db_path,
3319 }
lloretgalleg7c121132020-07-08 07:53:22 +00003320
romeromonser4554a702021-05-28 12:00:08 +02003321 if k8s_instance_info.get("kdu-deployment-name"):
3322 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3323 else:
3324 kdu_instance = self.k8scluster_map[
3325 k8sclustertype
3326 ].generate_kdu_instance_name(
3327 db_dict=db_dict_install,
3328 kdu_model=k8s_instance_info["kdu-model"],
3329 kdu_name=k8s_instance_info["kdu-name"],
3330 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003331
3332 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003333 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003334 item="nsrs",
3335 _id=nsr_id,
3336 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003337 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003338
3339 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3340 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3341 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3342 # namespace, this first verification could be removed, and the next step would be done for any kind
3343 # of KNF.
3344 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3345 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3346 if k8sclustertype in ("juju", "juju-bundle"):
3347 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3348 # that the user passed a namespace which he wants its KDU to be deployed in)
3349 if (
3350 self.db.count(
3351 table="nsrs",
3352 q_filter={
3353 "_id": nsr_id,
3354 "_admin.projects_write": k8s_instance_info["namespace"],
3355 "_admin.projects_read": k8s_instance_info["namespace"],
3356 },
3357 )
3358 > 0
3359 ):
3360 self.logger.debug(
3361 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3362 )
3363 self.update_db_2(
3364 item="nsrs",
3365 _id=nsr_id,
3366 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3367 )
3368 k8s_instance_info["namespace"] = kdu_instance
3369
David Garciad64e2742021-02-25 20:19:18 +01003370 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003371 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3372 kdu_model=k8s_instance_info["kdu-model"],
3373 atomic=True,
3374 params=k8params,
3375 db_dict=db_dict_install,
3376 timeout=timeout,
3377 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003378 namespace=k8s_instance_info["namespace"],
3379 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003380 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003381 )
lloretgalleg7c121132020-07-08 07:53:22 +00003382
3383 # Obtain services to obtain management service ip
3384 services = await self.k8scluster_map[k8sclustertype].get_services(
3385 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3386 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003387 namespace=k8s_instance_info["namespace"],
3388 )
lloretgalleg7c121132020-07-08 07:53:22 +00003389
3390 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003391 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003392 kdu_config = get_configuration(vnfd, kdud["name"])
3393 if kdu_config:
3394 target_ee_list = kdu_config.get("execution-environment-list", [])
3395 else:
3396 target_ee_list = []
3397
lloretgalleg7c121132020-07-08 07:53:22 +00003398 if services:
tierno7ecbc342020-09-21 14:05:39 +00003399 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003400 mgmt_services = [
3401 service
3402 for service in kdud.get("service", [])
3403 if service.get("mgmt-service")
3404 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003405 for mgmt_service in mgmt_services:
3406 for service in services:
3407 if service["name"].startswith(mgmt_service["name"]):
3408 # Mgmt service found, Obtain service ip
3409 ip = service.get("external_ip", service.get("cluster_ip"))
3410 if isinstance(ip, list) and len(ip) == 1:
3411 ip = ip[0]
3412
garciadeblas5697b8b2021-03-24 09:17:02 +01003413 vnfr_update_dict[
3414 "kdur.{}.ip-address".format(kdu_index)
3415 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003416
3417 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003418 service_external_cp = mgmt_service.get(
3419 "external-connection-point-ref"
3420 )
lloretgalleg7c121132020-07-08 07:53:22 +00003421 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003422 if (
3423 deep_get(vnfd, ("mgmt-interface", "cp"))
3424 == service_external_cp
3425 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003426 vnfr_update_dict["ip-address"] = ip
3427
bravof6ec62b72021-02-25 17:20:35 -03003428 if find_in_list(
3429 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003430 lambda ee: ee.get(
3431 "external-connection-point-ref", ""
3432 )
3433 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003434 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003435 vnfr_update_dict[
3436 "kdur.{}.ip-address".format(kdu_index)
3437 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003438 break
3439 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003440 self.logger.warn(
3441 "Mgmt service name: {} not found".format(
3442 mgmt_service["name"]
3443 )
3444 )
lloretgalleg7c121132020-07-08 07:53:22 +00003445
tierno7ecbc342020-09-21 14:05:39 +00003446 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3447 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003448
bravof9a256db2021-02-22 18:02:07 -03003449 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003450 if (
3451 kdu_config
3452 and kdu_config.get("initial-config-primitive")
3453 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3454 ):
3455 initial_config_primitive_list = kdu_config.get(
3456 "initial-config-primitive"
3457 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003458 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3459
3460 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003461 primitive_params_ = self._map_primitive_params(
3462 initial_config_primitive, {}, {}
3463 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003464
3465 await asyncio.wait_for(
3466 self.k8scluster_map[k8sclustertype].exec_primitive(
3467 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3468 kdu_instance=kdu_instance,
3469 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003470 params=primitive_params_,
3471 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003472 vca_id=vca_id,
3473 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003474 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003475 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003476
tiernob9018152020-04-16 14:18:24 +00003477 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003478 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003479 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003480 self.update_db_2(
3481 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3482 )
3483 self.update_db_2(
3484 "vnfrs",
3485 vnfr_data.get("_id"),
3486 {"kdur.{}.status".format(kdu_index): "ERROR"},
3487 )
tiernob9018152020-04-16 14:18:24 +00003488 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00003489 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00003490 pass
lloretgalleg7c121132020-07-08 07:53:22 +00003491 # reraise original error
3492 raise
3493
3494 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003495
garciadeblas5697b8b2021-03-24 09:17:02 +01003496 async def deploy_kdus(
3497 self,
3498 logging_text,
3499 nsr_id,
3500 nslcmop_id,
3501 db_vnfrs,
3502 db_vnfds,
3503 task_instantiation_info,
3504 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003505 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003506
garciadeblas5697b8b2021-03-24 09:17:02 +01003507 k8scluster_id_2_uuic = {
3508 "helm-chart-v3": {},
3509 "helm-chart": {},
3510 "juju-bundle": {},
3511 }
tierno626e0152019-11-29 14:16:16 +00003512
tierno16f4a4e2020-07-20 09:05:51 +00003513 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003514 nonlocal k8scluster_id_2_uuic
3515 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3516 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3517
tierno16f4a4e2020-07-20 09:05:51 +00003518 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003519 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3520 "k8scluster", cluster_id
3521 )
tierno16f4a4e2020-07-20 09:05:51 +00003522 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003523 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3524 task_name, cluster_id
3525 )
tierno16f4a4e2020-07-20 09:05:51 +00003526 self.logger.debug(logging_text + text)
3527 await asyncio.wait(task_dependency, timeout=3600)
3528
garciadeblas5697b8b2021-03-24 09:17:02 +01003529 db_k8scluster = self.db.get_one(
3530 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3531 )
tierno626e0152019-11-29 14:16:16 +00003532 if not db_k8scluster:
3533 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003534
tierno626e0152019-11-29 14:16:16 +00003535 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3536 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003537 if cluster_type == "helm-chart-v3":
3538 try:
3539 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003540 k8s_credentials = yaml.safe_dump(
3541 db_k8scluster.get("credentials")
3542 )
3543 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3544 k8s_credentials, reuse_cluster_uuid=cluster_id
3545 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003546 db_k8scluster_update = {}
3547 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3548 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003549 db_k8scluster_update[
3550 "_admin.helm-chart-v3.created"
3551 ] = uninstall_sw
3552 db_k8scluster_update[
3553 "_admin.helm-chart-v3.operationalState"
3554 ] = "ENABLED"
3555 self.update_db_2(
3556 "k8sclusters", cluster_id, db_k8scluster_update
3557 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003558 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003559 self.logger.error(
3560 logging_text
3561 + "error initializing helm-v3 cluster: {}".format(str(e))
3562 )
3563 raise LcmException(
3564 "K8s cluster '{}' has not been initialized for '{}'".format(
3565 cluster_id, cluster_type
3566 )
3567 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003568 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003569 raise LcmException(
3570 "K8s cluster '{}' has not been initialized for '{}'".format(
3571 cluster_id, cluster_type
3572 )
3573 )
tierno626e0152019-11-29 14:16:16 +00003574 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3575 return k8s_id
3576
3577 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003578 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003579 try:
tierno626e0152019-11-29 14:16:16 +00003580 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003581 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003582
tierno626e0152019-11-29 14:16:16 +00003583 index = 0
tiernoe876f672020-02-13 14:34:48 +00003584 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003585 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003586
tierno626e0152019-11-29 14:16:16 +00003587 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003588 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003589 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3590 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003591 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003592 vnfd_id = vnfr_data.get("vnfd-id")
3593 vnfd_with_id = find_in_list(
3594 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3595 )
3596 kdud = next(
3597 kdud
3598 for kdud in vnfd_with_id["kdu"]
3599 if kdud["name"] == kdur["kdu-name"]
3600 )
tiernode1584f2020-04-07 09:07:33 +00003601 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003602 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003603 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003604 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003605 # Default version: helm3, if helm-version is v2 assign v2
3606 k8sclustertype = "helm-chart-v3"
3607 self.logger.debug("kdur: {}".format(kdur))
garciadeblas5697b8b2021-03-24 09:17:02 +01003608 if (
3609 kdur.get("helm-version")
3610 and kdur.get("helm-version") == "v2"
3611 ):
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003612 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00003613 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003614 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003615 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003616 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003617 raise LcmException(
3618 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3619 "juju-bundle. Maybe an old NBI version is running".format(
3620 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3621 )
3622 )
quilesjacde94f2020-01-23 10:07:08 +00003623 # check if kdumodel is a file and exists
3624 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003625 vnfd_with_id = find_in_list(
3626 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3627 )
3628 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003629 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003630 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003631 if storage["pkg-dir"]:
3632 filename = "{}/{}/{}s/{}".format(
3633 storage["folder"],
3634 storage["pkg-dir"],
3635 k8sclustertype,
3636 kdumodel,
3637 )
3638 else:
3639 filename = "{}/Scripts/{}s/{}".format(
3640 storage["folder"],
3641 k8sclustertype,
3642 kdumodel,
3643 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003644 if self.fs.file_exists(
3645 filename, mode="file"
3646 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003647 kdumodel = self.fs.path + filename
3648 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003649 raise
garciadeblas5697b8b2021-03-24 09:17:02 +01003650 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00003651 pass
lloretgallegedc5f332020-02-20 11:50:50 +01003652
tiernoe876f672020-02-13 14:34:48 +00003653 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003654 step = "Synchronize repos for k8s cluster '{}'".format(
3655 k8s_cluster_id
3656 )
tierno16f4a4e2020-07-20 09:05:51 +00003657 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003658
lloretgalleg7c121132020-07-08 07:53:22 +00003659 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003660 if (
3661 k8sclustertype == "helm-chart"
3662 and cluster_uuid not in updated_cluster_list
3663 ) or (
3664 k8sclustertype == "helm-chart-v3"
3665 and cluster_uuid not in updated_v3_cluster_list
3666 ):
tiernoe876f672020-02-13 14:34:48 +00003667 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003668 self.k8scluster_map[k8sclustertype].synchronize_repos(
3669 cluster_uuid=cluster_uuid
3670 )
3671 )
tiernoe876f672020-02-13 14:34:48 +00003672 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003673 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003674 unset = {
3675 "_admin.helm_charts_added." + item: None
3676 for item in del_repo_list
3677 }
3678 updated = {
3679 "_admin.helm_charts_added." + item: name
3680 for item, name in added_repo_dict.items()
3681 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003682 updated_cluster_list.append(cluster_uuid)
3683 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003684 unset = {
3685 "_admin.helm_charts_v3_added." + item: None
3686 for item in del_repo_list
3687 }
3688 updated = {
3689 "_admin.helm_charts_v3_added." + item: name
3690 for item, name in added_repo_dict.items()
3691 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003692 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003693 self.logger.debug(
3694 logging_text + "repos synchronized on k8s cluster "
3695 "'{}' to_delete: {}, to_add: {}".format(
3696 k8s_cluster_id, del_repo_list, added_repo_dict
3697 )
3698 )
3699 self.db.set_one(
3700 "k8sclusters",
3701 {"_id": k8s_cluster_id},
3702 updated,
3703 unset=unset,
3704 )
lloretgallegedc5f332020-02-20 11:50:50 +01003705
lloretgalleg7c121132020-07-08 07:53:22 +00003706 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003707 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3708 vnfr_data["member-vnf-index-ref"],
3709 kdur["kdu-name"],
3710 k8s_cluster_id,
3711 )
3712 k8s_instance_info = {
3713 "kdu-instance": None,
3714 "k8scluster-uuid": cluster_uuid,
3715 "k8scluster-type": k8sclustertype,
3716 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3717 "kdu-name": kdur["kdu-name"],
3718 "kdu-model": kdumodel,
3719 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003720 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003721 }
tiernob9018152020-04-16 14:18:24 +00003722 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003723 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003724 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003725 vnfd_with_id = find_in_list(
3726 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3727 )
tiernoa2143262020-03-27 16:20:40 +00003728 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003729 self._install_kdu(
3730 nsr_id,
3731 db_path,
3732 vnfr_data,
3733 kdu_index,
3734 kdud,
3735 vnfd_with_id,
3736 k8s_instance_info,
3737 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003738 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003739 vca_id=vca_id,
3740 )
3741 )
3742 self.lcm_tasks.register(
3743 "ns",
3744 nsr_id,
3745 nslcmop_id,
3746 "instantiate_KDU-{}".format(index),
3747 task,
3748 )
3749 task_instantiation_info[task] = "Deploying KDU {}".format(
3750 kdur["kdu-name"]
3751 )
tiernoe876f672020-02-13 14:34:48 +00003752
tierno626e0152019-11-29 14:16:16 +00003753 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003754
tiernoe876f672020-02-13 14:34:48 +00003755 except (LcmException, asyncio.CancelledError):
3756 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003757 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003758 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3759 if isinstance(e, (N2VCException, DbException)):
3760 self.logger.error(logging_text + msg)
3761 else:
3762 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003763 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003764 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003765 if db_nsr_update:
3766 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003767
garciadeblas5697b8b2021-03-24 09:17:02 +01003768 def _deploy_n2vc(
3769 self,
3770 logging_text,
3771 db_nsr,
3772 db_vnfr,
3773 nslcmop_id,
3774 nsr_id,
3775 nsi_id,
3776 vnfd_id,
3777 vdu_id,
3778 kdu_name,
3779 member_vnf_index,
3780 vdu_index,
3781 vdu_name,
3782 deploy_params,
3783 descriptor_config,
3784 base_folder,
3785 task_instantiation_info,
3786 stage,
3787 ):
quilesj7e13aeb2019-10-08 13:34:55 +02003788 # launch instantiate_N2VC in a asyncio task and register task object
3789 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
3790 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02003791 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00003792
garciadeblas5697b8b2021-03-24 09:17:02 +01003793 self.logger.debug(
3794 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
3795 )
aticig9bc63ac2022-07-27 09:32:06 +03003796
3797 charm_name = ""
3798 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03003799 if "execution-environment-list" in descriptor_config:
3800 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02003801 elif "juju" in descriptor_config:
3802 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03003803 if "execution-environment-list" not in descriptor_config:
3804 # charm name is only required for ns charms
3805 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00003806 else: # other types as script are not supported
3807 ee_list = []
3808
3809 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003810 self.logger.debug(
3811 logging_text
3812 + "_deploy_n2vc ee_item juju={}, helm={}".format(
3813 ee_item.get("juju"), ee_item.get("helm-chart")
3814 )
3815 )
tiernoa278b842020-07-08 15:33:55 +00003816 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00003817 if ee_item.get("juju"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003818 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03003819 if get_charm_name:
3820 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas5697b8b2021-03-24 09:17:02 +01003821 vca_type = (
3822 "lxc_proxy_charm"
3823 if ee_item["juju"].get("charm") is not None
3824 else "native_charm"
3825 )
3826 if ee_item["juju"].get("cloud") == "k8s":
tierno588547c2020-07-01 15:30:20 +00003827 vca_type = "k8s_proxy_charm"
garciadeblas5697b8b2021-03-24 09:17:02 +01003828 elif ee_item["juju"].get("proxy") is False:
tierno588547c2020-07-01 15:30:20 +00003829 vca_type = "native_charm"
3830 elif ee_item.get("helm-chart"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003831 vca_name = ee_item["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003832 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
3833 vca_type = "helm"
3834 else:
3835 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00003836 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003837 self.logger.debug(
3838 logging_text + "skipping non juju neither charm configuration"
3839 )
quilesj7e13aeb2019-10-08 13:34:55 +02003840 continue
quilesj3655ae02019-12-12 16:08:35 +00003841
tierno588547c2020-07-01 15:30:20 +00003842 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01003843 for vca_index, vca_deployed in enumerate(
3844 db_nsr["_admin"]["deployed"]["VCA"]
3845 ):
tierno588547c2020-07-01 15:30:20 +00003846 if not vca_deployed:
3847 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01003848 if (
3849 vca_deployed.get("member-vnf-index") == member_vnf_index
3850 and vca_deployed.get("vdu_id") == vdu_id
3851 and vca_deployed.get("kdu_name") == kdu_name
3852 and vca_deployed.get("vdu_count_index", 0) == vdu_index
3853 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
3854 ):
tierno588547c2020-07-01 15:30:20 +00003855 break
3856 else:
3857 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01003858 target = (
3859 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
3860 )
tiernoa278b842020-07-08 15:33:55 +00003861 if vdu_id:
3862 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
3863 elif kdu_name:
3864 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00003865 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00003866 "target_element": target,
3867 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00003868 "member-vnf-index": member_vnf_index,
3869 "vdu_id": vdu_id,
3870 "kdu_name": kdu_name,
3871 "vdu_count_index": vdu_index,
3872 "operational-status": "init", # TODO revise
3873 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01003874 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00003875 "vnfd_id": vnfd_id,
3876 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00003877 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01003878 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03003879 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00003880 }
3881 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00003882
tierno588547c2020-07-01 15:30:20 +00003883 # create VCA and configurationStatus in db
3884 db_dict = {
3885 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01003886 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00003887 }
3888 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02003889
tierno588547c2020-07-01 15:30:20 +00003890 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
3891
bravof922c4172020-11-24 21:21:43 -03003892 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
3893 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
3894 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
3895
tierno588547c2020-07-01 15:30:20 +00003896 # Launch task
3897 task_n2vc = asyncio.ensure_future(
3898 self.instantiate_N2VC(
3899 logging_text=logging_text,
3900 vca_index=vca_index,
3901 nsi_id=nsi_id,
3902 db_nsr=db_nsr,
3903 db_vnfr=db_vnfr,
3904 vdu_id=vdu_id,
3905 kdu_name=kdu_name,
3906 vdu_index=vdu_index,
3907 deploy_params=deploy_params,
3908 config_descriptor=descriptor_config,
3909 base_folder=base_folder,
3910 nslcmop_id=nslcmop_id,
3911 stage=stage,
3912 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00003913 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003914 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00003915 )
quilesj7e13aeb2019-10-08 13:34:55 +02003916 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003917 self.lcm_tasks.register(
3918 "ns",
3919 nsr_id,
3920 nslcmop_id,
3921 "instantiate_N2VC-{}".format(vca_index),
3922 task_n2vc,
3923 )
3924 task_instantiation_info[
3925 task_n2vc
3926 ] = self.task_name_deploy_vca + " {}.{}".format(
3927 member_vnf_index or "", vdu_id or ""
3928 )
tiernobaa51102018-12-14 13:16:18 +00003929
tiernoc9556972019-07-05 15:25:25 +00003930 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02003931 def _create_nslcmop(nsr_id, operation, params):
3932 """
3933 Creates a ns-lcm-opp content to be stored at database.
3934 :param nsr_id: internal id of the instance
3935 :param operation: instantiate, terminate, scale, action, ...
3936 :param params: user parameters for the operation
3937 :return: dictionary following SOL005 format
3938 """
3939 # Raise exception if invalid arguments
3940 if not (nsr_id and operation and params):
3941 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01003942 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided"
3943 )
kuuse0ca67472019-05-13 15:59:27 +02003944 now = time()
3945 _id = str(uuid4())
3946 nslcmop = {
3947 "id": _id,
3948 "_id": _id,
3949 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
3950 "operationState": "PROCESSING",
3951 "statusEnteredTime": now,
3952 "nsInstanceId": nsr_id,
3953 "lcmOperationType": operation,
3954 "startTime": now,
3955 "isAutomaticInvocation": False,
3956 "operationParams": params,
3957 "isCancelPending": False,
3958 "links": {
3959 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
3960 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01003961 },
kuuse0ca67472019-05-13 15:59:27 +02003962 }
3963 return nslcmop
3964
calvinosanch9f9c6f22019-11-04 13:37:39 +01003965 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00003966 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003967 for key, value in params.items():
3968 if str(value).startswith("!!yaml "):
3969 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01003970 return params
3971
kuuse8b998e42019-07-30 15:22:16 +02003972 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01003973 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02003974 primitive_params = {}
3975 params = {
3976 "member_vnf_index": vnf_index,
3977 "primitive": primitive,
3978 "primitive_params": primitive_params,
3979 }
3980 desc_params = {}
3981 return self._map_primitive_params(seq, params, desc_params)
3982
kuuseac3a8882019-10-03 10:48:06 +02003983 # sub-operations
3984
tierno51183952020-04-03 15:48:18 +00003985 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01003986 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
3987 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02003988 # b. Skip sub-operation
3989 # _ns_execute_primitive() or RO.create_action() will NOT be executed
3990 return self.SUBOPERATION_STATUS_SKIP
3991 else:
tierno7c4e24c2020-05-13 08:41:35 +00003992 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003993 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00003994 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01003995 operationState = "PROCESSING"
3996 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02003997 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01003998 db_nslcmop, op_index, operationState, detailed_status
3999 )
kuuseac3a8882019-10-03 10:48:06 +02004000 # Return the sub-operation index
4001 # _ns_execute_primitive() or RO.create_action() will be called from scale()
4002 # with arguments extracted from the sub-operation
4003 return op_index
4004
4005 # Find a sub-operation where all keys in a matching dictionary must match
4006 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
4007 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00004008 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01004009 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02004010 for i, op in enumerate(op_list):
4011 if all(op.get(k) == match[k] for k in match):
4012 return i
4013 return self.SUBOPERATION_STATUS_NOT_FOUND
4014
4015 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01004016 def _update_suboperation_status(
4017 self, db_nslcmop, op_index, operationState, detailed_status
4018 ):
kuuseac3a8882019-10-03 10:48:06 +02004019 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01004020 q_filter = {"_id": db_nslcmop["_id"]}
4021 update_dict = {
4022 "_admin.operations.{}.operationState".format(op_index): operationState,
4023 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
4024 }
4025 self.db.set_one(
4026 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
4027 )
kuuseac3a8882019-10-03 10:48:06 +02004028
4029 # Add sub-operation, return the index of the added sub-operation
4030 # Optionally, set operationState, detailed-status, and operationType
4031 # Status and type are currently set for 'scale' sub-operations:
4032 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
4033 # 'detailed-status' : status message
4034 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
4035 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01004036 def _add_suboperation(
4037 self,
4038 db_nslcmop,
4039 vnf_index,
4040 vdu_id,
4041 vdu_count_index,
4042 vdu_name,
4043 primitive,
4044 mapped_primitive_params,
4045 operationState=None,
4046 detailed_status=None,
4047 operationType=None,
4048 RO_nsr_id=None,
4049 RO_scaling_info=None,
4050 ):
tiernoe876f672020-02-13 14:34:48 +00004051 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004052 return self.SUBOPERATION_STATUS_NOT_FOUND
4053 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004054 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4055 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004056 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004057 new_op = {
4058 "member_vnf_index": vnf_index,
4059 "vdu_id": vdu_id,
4060 "vdu_count_index": vdu_count_index,
4061 "primitive": primitive,
4062 "primitive_params": mapped_primitive_params,
4063 }
kuuseac3a8882019-10-03 10:48:06 +02004064 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004065 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004066 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004067 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004068 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004069 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004070 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004071 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004072 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004073 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004074 if not op_list:
4075 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004076 db_nslcmop_admin.update({"operations": [new_op]})
4077 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004078 else:
4079 # Existing operations, append operation to list
4080 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004081
garciadeblas5697b8b2021-03-24 09:17:02 +01004082 db_nslcmop_update = {"_admin.operations": op_list}
4083 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004084 op_index = len(op_list) - 1
4085 return op_index
4086
4087 # Helper methods for scale() sub-operations
4088
4089 # pre-scale/post-scale:
4090 # Check for 3 different cases:
4091 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4092 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004093 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004094 def _check_or_add_scale_suboperation(
4095 self,
4096 db_nslcmop,
4097 vnf_index,
4098 vnf_config_primitive,
4099 primitive_params,
4100 operationType,
4101 RO_nsr_id=None,
4102 RO_scaling_info=None,
4103 ):
kuuseac3a8882019-10-03 10:48:06 +02004104 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004105 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004106 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004107 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004108 "member_vnf_index": vnf_index,
4109 "RO_nsr_id": RO_nsr_id,
4110 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004111 }
4112 else:
4113 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004114 "member_vnf_index": vnf_index,
4115 "primitive": vnf_config_primitive,
4116 "primitive_params": primitive_params,
4117 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004118 }
4119 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004120 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004121 # a. New sub-operation
4122 # The sub-operation does not exist, add it.
4123 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4124 # The following parameters are set to None for all kind of scaling:
4125 vdu_id = None
4126 vdu_count_index = None
4127 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004128 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004129 vnf_config_primitive = None
4130 primitive_params = None
4131 else:
4132 RO_nsr_id = None
4133 RO_scaling_info = None
4134 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004135 operationState = "PROCESSING"
4136 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004137 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004138 self._add_suboperation(
4139 db_nslcmop,
4140 vnf_index,
4141 vdu_id,
4142 vdu_count_index,
4143 vdu_name,
4144 vnf_config_primitive,
4145 primitive_params,
4146 operationState,
4147 detailed_status,
4148 operationType,
4149 RO_nsr_id,
4150 RO_scaling_info,
4151 )
kuuseac3a8882019-10-03 10:48:06 +02004152 return self.SUBOPERATION_STATUS_NEW
4153 else:
4154 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4155 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004156 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004157
preethika.pdf7d8e02019-12-10 13:10:48 +00004158 # Function to return execution_environment id
4159
4160 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00004161 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00004162 for vca in vca_deployed_list:
4163 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
4164 return vca["ee_id"]
4165
David Garciac1fe90a2021-03-31 19:12:02 +02004166 async def destroy_N2VC(
4167 self,
4168 logging_text,
4169 db_nslcmop,
4170 vca_deployed,
4171 config_descriptor,
4172 vca_index,
4173 destroy_ee=True,
4174 exec_primitives=True,
4175 scaling_in=False,
4176 vca_id: str = None,
4177 ):
tiernoe876f672020-02-13 14:34:48 +00004178 """
4179 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4180 :param logging_text:
4181 :param db_nslcmop:
4182 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4183 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4184 :param vca_index: index in the database _admin.deployed.VCA
4185 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004186 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4187 not executed properly
aktas13251562021-02-12 22:19:10 +03004188 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004189 :return: None or exception
4190 """
tiernoe876f672020-02-13 14:34:48 +00004191
tierno588547c2020-07-01 15:30:20 +00004192 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004193 logging_text
4194 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004195 vca_index, vca_deployed, config_descriptor, destroy_ee
4196 )
4197 )
4198
4199 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4200
4201 # execute terminate_primitives
4202 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004203 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004204 config_descriptor.get("terminate-config-primitive"),
4205 vca_deployed.get("ee_descriptor_id"),
4206 )
tierno588547c2020-07-01 15:30:20 +00004207 vdu_id = vca_deployed.get("vdu_id")
4208 vdu_count_index = vca_deployed.get("vdu_count_index")
4209 vdu_name = vca_deployed.get("vdu_name")
4210 vnf_index = vca_deployed.get("member-vnf-index")
4211 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004212 for seq in terminate_primitives:
4213 # For each sequence in list, get primitive and call _ns_execute_primitive()
4214 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004215 vnf_index, seq.get("name")
4216 )
tierno588547c2020-07-01 15:30:20 +00004217 self.logger.debug(logging_text + step)
4218 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004219 primitive = seq.get("name")
4220 mapped_primitive_params = self._get_terminate_primitive_params(
4221 seq, vnf_index
4222 )
tierno588547c2020-07-01 15:30:20 +00004223
4224 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004225 self._add_suboperation(
4226 db_nslcmop,
4227 vnf_index,
4228 vdu_id,
4229 vdu_count_index,
4230 vdu_name,
4231 primitive,
4232 mapped_primitive_params,
4233 )
tierno588547c2020-07-01 15:30:20 +00004234 # Sub-operations: Call _ns_execute_primitive() instead of action()
4235 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004236 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004237 vca_deployed["ee_id"],
4238 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004239 mapped_primitive_params,
4240 vca_type=vca_type,
4241 vca_id=vca_id,
4242 )
tierno588547c2020-07-01 15:30:20 +00004243 except LcmException:
4244 # this happens when VCA is not deployed. In this case it is not needed to terminate
4245 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004246 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004247 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004248 raise LcmException(
4249 "terminate_primitive {} for vnf_member_index={} fails with "
4250 "error {}".format(seq.get("name"), vnf_index, result_detail)
4251 )
tierno588547c2020-07-01 15:30:20 +00004252 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004253 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4254 vca_index
4255 )
4256 self.update_db_2(
4257 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4258 )
tiernoe876f672020-02-13 14:34:48 +00004259
bravof73bac502021-05-11 07:38:47 -04004260 # Delete Prometheus Jobs if any
4261 # This uses NSR_ID, so it will destroy any jobs under this index
4262 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004263
tiernoe876f672020-02-13 14:34:48 +00004264 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004265 await self.vca_map[vca_type].delete_execution_environment(
4266 vca_deployed["ee_id"],
4267 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004268 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004269 vca_id=vca_id,
4270 )
kuuse0ca67472019-05-13 15:59:27 +02004271
David Garciac1fe90a2021-03-31 19:12:02 +02004272 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004273 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004274 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004275 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004276 await self.n2vc.delete_namespace(
4277 namespace=namespace,
4278 total_timeout=self.timeout_charm_delete,
4279 vca_id=vca_id,
4280 )
tiernof59ad6c2020-04-08 12:50:52 +00004281 except N2VCNotFound: # already deleted. Skip
4282 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004283 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004284
garciadeblas5697b8b2021-03-24 09:17:02 +01004285 async def _terminate_RO(
4286 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4287 ):
tiernoe876f672020-02-13 14:34:48 +00004288 """
4289 Terminates a deployment from RO
4290 :param logging_text:
4291 :param nsr_deployed: db_nsr._admin.deployed
4292 :param nsr_id:
4293 :param nslcmop_id:
4294 :param stage: list of string with the content to write on db_nslcmop.detailed-status.
4295 this method will update only the index 2, but it will write on database the concatenated content of the list
4296 :return:
4297 """
4298 db_nsr_update = {}
4299 failed_detail = []
4300 ro_nsr_id = ro_delete_action = None
4301 if nsr_deployed and nsr_deployed.get("RO"):
4302 ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
4303 ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
4304 try:
4305 if ro_nsr_id:
4306 stage[2] = "Deleting ns from VIM."
4307 db_nsr_update["detailed-status"] = " ".join(stage)
4308 self._write_op_status(nslcmop_id, stage)
4309 self.logger.debug(logging_text + stage[2])
4310 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4311 self._write_op_status(nslcmop_id, stage)
4312 desc = await self.RO.delete("ns", ro_nsr_id)
4313 ro_delete_action = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004314 db_nsr_update[
4315 "_admin.deployed.RO.nsr_delete_action_id"
4316 ] = ro_delete_action
tiernoe876f672020-02-13 14:34:48 +00004317 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
4318 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4319 if ro_delete_action:
4320 # wait until NS is deleted from VIM
4321 stage[2] = "Waiting ns deleted from VIM."
4322 detailed_status_old = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004323 self.logger.debug(
4324 logging_text
4325 + stage[2]
4326 + " RO_id={} ro_delete_action={}".format(
4327 ro_nsr_id, ro_delete_action
4328 )
4329 )
tiernoe876f672020-02-13 14:34:48 +00004330 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4331 self._write_op_status(nslcmop_id, stage)
kuused124bfe2019-06-18 12:09:24 +02004332
tiernoe876f672020-02-13 14:34:48 +00004333 delete_timeout = 20 * 60 # 20 minutes
4334 while delete_timeout > 0:
4335 desc = await self.RO.show(
4336 "ns",
4337 item_id_name=ro_nsr_id,
4338 extra_item="action",
garciadeblas5697b8b2021-03-24 09:17:02 +01004339 extra_item_id=ro_delete_action,
4340 )
tiernoe876f672020-02-13 14:34:48 +00004341
4342 # deploymentStatus
4343 self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
4344
4345 ns_status, ns_status_info = self.RO.check_action_status(desc)
4346 if ns_status == "ERROR":
4347 raise ROclient.ROClientException(ns_status_info)
4348 elif ns_status == "BUILD":
4349 stage[2] = "Deleting from VIM {}".format(ns_status_info)
4350 elif ns_status == "ACTIVE":
4351 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
4352 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4353 break
4354 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004355 assert (
4356 False
4357 ), "ROclient.check_action_status returns unknown {}".format(
4358 ns_status
4359 )
tiernoe876f672020-02-13 14:34:48 +00004360 if stage[2] != detailed_status_old:
4361 detailed_status_old = stage[2]
4362 db_nsr_update["detailed-status"] = " ".join(stage)
4363 self._write_op_status(nslcmop_id, stage)
4364 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4365 await asyncio.sleep(5, loop=self.loop)
4366 delete_timeout -= 5
4367 else: # delete_timeout <= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01004368 raise ROclient.ROClientException(
4369 "Timeout waiting ns deleted from VIM"
4370 )
tiernoe876f672020-02-13 14:34:48 +00004371
4372 except Exception as e:
4373 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01004374 if (
4375 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4376 ): # not found
tiernoe876f672020-02-13 14:34:48 +00004377 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
4378 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4379 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004380 self.logger.debug(
4381 logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id)
4382 )
4383 elif (
4384 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4385 ): # conflict
tiernoa2143262020-03-27 16:20:40 +00004386 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01004387 self.logger.debug(
4388 logging_text
4389 + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e)
4390 )
tiernoe876f672020-02-13 14:34:48 +00004391 else:
tiernoa2143262020-03-27 16:20:40 +00004392 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01004393 self.logger.error(
4394 logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e)
4395 )
tiernoe876f672020-02-13 14:34:48 +00004396
4397 # Delete nsd
4398 if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
4399 ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
4400 try:
4401 stage[2] = "Deleting nsd from RO."
4402 db_nsr_update["detailed-status"] = " ".join(stage)
4403 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4404 self._write_op_status(nslcmop_id, stage)
4405 await self.RO.delete("nsd", ro_nsd_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01004406 self.logger.debug(
4407 logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id)
4408 )
tiernoe876f672020-02-13 14:34:48 +00004409 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
4410 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004411 if (
4412 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4413 ): # not found
tiernoe876f672020-02-13 14:34:48 +00004414 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004415 self.logger.debug(
4416 logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id)
4417 )
4418 elif (
4419 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4420 ): # conflict
4421 failed_detail.append(
4422 "ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e)
4423 )
tiernoe876f672020-02-13 14:34:48 +00004424 self.logger.debug(logging_text + failed_detail[-1])
4425 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004426 failed_detail.append(
4427 "ro_nsd_id={} delete error: {}".format(ro_nsd_id, e)
4428 )
tiernoe876f672020-02-13 14:34:48 +00004429 self.logger.error(logging_text + failed_detail[-1])
4430
4431 if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
4432 for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
4433 if not vnf_deployed or not vnf_deployed["id"]:
4434 continue
4435 try:
4436 ro_vnfd_id = vnf_deployed["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004437 stage[
4438 2
4439 ] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
4440 vnf_deployed["member-vnf-index"], ro_vnfd_id
4441 )
tiernoe876f672020-02-13 14:34:48 +00004442 db_nsr_update["detailed-status"] = " ".join(stage)
4443 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4444 self._write_op_status(nslcmop_id, stage)
4445 await self.RO.delete("vnfd", ro_vnfd_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01004446 self.logger.debug(
4447 logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id)
4448 )
tiernoe876f672020-02-13 14:34:48 +00004449 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
4450 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004451 if (
4452 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4453 ): # not found
4454 db_nsr_update[
4455 "_admin.deployed.RO.vnfd.{}.id".format(index)
4456 ] = None
4457 self.logger.debug(
4458 logging_text
4459 + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id)
4460 )
4461 elif (
4462 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4463 ): # conflict
4464 failed_detail.append(
4465 "ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e)
4466 )
tiernoe876f672020-02-13 14:34:48 +00004467 self.logger.debug(logging_text + failed_detail[-1])
4468 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004469 failed_detail.append(
4470 "ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e)
4471 )
tiernoe876f672020-02-13 14:34:48 +00004472 self.logger.error(logging_text + failed_detail[-1])
4473
tiernoa2143262020-03-27 16:20:40 +00004474 if failed_detail:
4475 stage[2] = "Error deleting from VIM"
4476 else:
4477 stage[2] = "Deleted from VIM"
tiernoe876f672020-02-13 14:34:48 +00004478 db_nsr_update["detailed-status"] = " ".join(stage)
4479 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4480 self._write_op_status(nslcmop_id, stage)
4481
4482 if failed_detail:
tiernoa2143262020-03-27 16:20:40 +00004483 raise LcmException("; ".join(failed_detail))
tiernoe876f672020-02-13 14:34:48 +00004484
4485 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004486 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004487 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004488 if not task_is_locked_by_me:
4489 return
4490
tierno59d22d22018-09-25 18:10:19 +02004491 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4492 self.logger.debug(logging_text + "Enter")
tiernoe876f672020-02-13 14:34:48 +00004493 timeout_ns_terminate = self.timeout_ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004494 db_nsr = None
4495 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004496 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004497 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004498 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004499 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004500 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004501 tasks_dict_info = {}
4502 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004503 stage = [
4504 "Stage 1/3: Preparing task.",
4505 "Waiting for previous operations to terminate.",
4506 "",
4507 ]
tiernoe876f672020-02-13 14:34:48 +00004508 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004509 try:
kuused124bfe2019-06-18 12:09:24 +02004510 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004511 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004512
tiernoe876f672020-02-13 14:34:48 +00004513 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4514 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4515 operation_params = db_nslcmop.get("operationParams") or {}
4516 if operation_params.get("timeout_ns_terminate"):
4517 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4518 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4519 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4520
4521 db_nsr_update["operational-status"] = "terminating"
4522 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004523 self._write_ns_status(
4524 nsr_id=nsr_id,
4525 ns_state="TERMINATING",
4526 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004527 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004528 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004529 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004530 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004531 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004532 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4533 return
tierno59d22d22018-09-25 18:10:19 +02004534
tiernoe876f672020-02-13 14:34:48 +00004535 stage[1] = "Getting vnf descriptors from db."
4536 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004537 db_vnfrs_dict = {
4538 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4539 }
tiernoe876f672020-02-13 14:34:48 +00004540 db_vnfds_from_id = {}
4541 db_vnfds_from_member_index = {}
4542 # Loop over VNFRs
4543 for vnfr in db_vnfrs_list:
4544 vnfd_id = vnfr["vnfd-id"]
4545 if vnfd_id not in db_vnfds_from_id:
4546 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4547 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004548 db_vnfds_from_member_index[
4549 vnfr["member-vnf-index-ref"]
4550 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004551
tiernoe876f672020-02-13 14:34:48 +00004552 # Destroy individual execution environments when there are terminating primitives.
4553 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004554 # TODO - check before calling _destroy_N2VC
4555 # if not operation_params.get("skip_terminate_primitives"):#
4556 # or not vca.get("needed_terminate"):
4557 stage[0] = "Stage 2/3 execute terminating primitives."
4558 self.logger.debug(logging_text + stage[0])
4559 stage[1] = "Looking execution environment that needs terminate."
4560 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004561
tierno588547c2020-07-01 15:30:20 +00004562 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004563 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004564 vca_member_vnf_index = vca.get("member-vnf-index")
4565 vca_id = self.get_vca_id(
4566 db_vnfrs_dict.get(vca_member_vnf_index)
4567 if vca_member_vnf_index
4568 else None,
4569 db_nsr,
4570 )
tierno588547c2020-07-01 15:30:20 +00004571 if not vca or not vca.get("ee_id"):
4572 continue
4573 if not vca.get("member-vnf-index"):
4574 # ns
4575 config_descriptor = db_nsr.get("ns-configuration")
4576 elif vca.get("vdu_id"):
4577 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004578 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004579 elif vca.get("kdu_name"):
4580 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004581 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004582 else:
bravofe5a31bc2021-02-17 19:09:12 -03004583 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004584 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004585 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004586 exec_terminate_primitives = not operation_params.get(
4587 "skip_terminate_primitives"
4588 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004589 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4590 # pending native charms
garciadeblas5697b8b2021-03-24 09:17:02 +01004591 destroy_ee = (
4592 True if vca_type in ("helm", "helm-v3", "native_charm") else False
4593 )
tierno86e33612020-09-16 14:13:06 +00004594 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4595 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004596 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004597 self.destroy_N2VC(
4598 logging_text,
4599 db_nslcmop,
4600 vca,
4601 config_descriptor,
4602 vca_index,
4603 destroy_ee,
4604 exec_terminate_primitives,
4605 vca_id=vca_id,
4606 )
4607 )
tierno588547c2020-07-01 15:30:20 +00004608 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004609
tierno588547c2020-07-01 15:30:20 +00004610 # wait for pending tasks of terminate primitives
4611 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004612 self.logger.debug(
4613 logging_text
4614 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4615 )
4616 error_list = await self._wait_for_tasks(
4617 logging_text,
4618 tasks_dict_info,
4619 min(self.timeout_charm_delete, timeout_ns_terminate),
4620 stage,
4621 nslcmop_id,
4622 )
tierno86e33612020-09-16 14:13:06 +00004623 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004624 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004625 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004626
tiernoe876f672020-02-13 14:34:48 +00004627 # remove All execution environments at once
4628 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004629
tierno49676be2020-04-07 16:34:35 +00004630 if nsr_deployed.get("VCA"):
4631 stage[1] = "Deleting all execution environments."
4632 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02004633 vca_id = self.get_vca_id({}, db_nsr)
4634 task_delete_ee = asyncio.ensure_future(
4635 asyncio.wait_for(
4636 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
garciadeblas5697b8b2021-03-24 09:17:02 +01004637 timeout=self.timeout_charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004638 )
4639 )
tierno49676be2020-04-07 16:34:35 +00004640 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
4641 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02004642
Gabriel Cuba1411a002022-10-07 11:38:23 -05004643 # Delete Namespace and Certificates if necessary
4644 if check_helm_ee_in_ns(list(db_vnfds_from_member_index.values())):
4645 await self.vca_map["helm-v3"].delete_tls_certificate(
4646 certificate_name=db_nslcmop["nsInstanceId"],
4647 )
4648 # TODO: Delete namespace
4649
tiernoe876f672020-02-13 14:34:48 +00004650 # Delete from k8scluster
4651 stage[1] = "Deleting KDUs."
4652 self.logger.debug(logging_text + stage[1])
4653 # print(nsr_deployed)
4654 for kdu in get_iterable(nsr_deployed, "K8s"):
4655 if not kdu or not kdu.get("kdu-instance"):
4656 continue
4657 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004658 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004659 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4660 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004661 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004662 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4663 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004664 kdu_instance=kdu_instance,
4665 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004666 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004667 )
4668 )
tiernoe876f672020-02-13 14:34:48 +00004669 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004670 self.logger.error(
4671 logging_text
4672 + "Unknown k8s deployment type {}".format(
4673 kdu.get("k8scluster-type")
4674 )
4675 )
tiernoe876f672020-02-13 14:34:48 +00004676 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004677 tasks_dict_info[
4678 task_delete_kdu_instance
4679 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004680
4681 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004682 stage[1] = "Deleting ns from VIM."
tierno69f0d382020-05-07 13:08:09 +00004683 if self.ng_ro:
4684 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004685 self._terminate_ng_ro(
4686 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4687 )
4688 )
tierno69f0d382020-05-07 13:08:09 +00004689 else:
4690 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004691 self._terminate_RO(
4692 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4693 )
4694 )
tiernoe876f672020-02-13 14:34:48 +00004695 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004696
tiernoe876f672020-02-13 14:34:48 +00004697 # rest of staff will be done at finally
4698
garciadeblas5697b8b2021-03-24 09:17:02 +01004699 except (
4700 ROclient.ROClientException,
4701 DbException,
4702 LcmException,
4703 N2VCException,
4704 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004705 self.logger.error(logging_text + "Exit Exception {}".format(e))
4706 exc = e
4707 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004708 self.logger.error(
4709 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4710 )
tiernoe876f672020-02-13 14:34:48 +00004711 exc = "Operation was cancelled"
4712 except Exception as e:
4713 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004714 self.logger.critical(
4715 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4716 exc_info=True,
4717 )
tiernoe876f672020-02-13 14:34:48 +00004718 finally:
4719 if exc:
4720 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004721 try:
tiernoe876f672020-02-13 14:34:48 +00004722 # wait for pending tasks
4723 if tasks_dict_info:
4724 stage[1] = "Waiting for terminate pending tasks."
4725 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004726 error_list += await self._wait_for_tasks(
4727 logging_text,
4728 tasks_dict_info,
4729 timeout_ns_terminate,
4730 stage,
4731 nslcmop_id,
4732 )
tiernoe876f672020-02-13 14:34:48 +00004733 stage[1] = stage[2] = ""
4734 except asyncio.CancelledError:
4735 error_list.append("Cancelled")
4736 # TODO cancell all tasks
4737 except Exception as exc:
4738 error_list.append(str(exc))
4739 # update status at database
4740 if error_list:
4741 error_detail = "; ".join(error_list)
4742 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004743 error_description_nslcmop = "{} Detail: {}".format(
4744 stage[0], error_detail
4745 )
4746 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4747 nslcmop_id, stage[0]
4748 )
tierno59d22d22018-09-25 18:10:19 +02004749
tierno59d22d22018-09-25 18:10:19 +02004750 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004751 db_nsr_update["detailed-status"] = (
4752 error_description_nsr + " Detail: " + error_detail
4753 )
tiernoe876f672020-02-13 14:34:48 +00004754 db_nslcmop_update["detailed-status"] = error_detail
4755 nslcmop_operation_state = "FAILED"
4756 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004757 else:
tiernoa2143262020-03-27 16:20:40 +00004758 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004759 error_description_nsr = error_description_nslcmop = None
4760 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004761 db_nsr_update["operational-status"] = "terminated"
4762 db_nsr_update["detailed-status"] = "Done"
4763 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4764 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004765 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004766
tiernoe876f672020-02-13 14:34:48 +00004767 if db_nsr:
4768 self._write_ns_status(
4769 nsr_id=nsr_id,
4770 ns_state=ns_state,
4771 current_operation="IDLE",
4772 current_operation_id=None,
4773 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004774 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004775 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004776 )
tiernoa17d4f42020-04-28 09:59:23 +00004777 self._write_op_status(
4778 op_id=nslcmop_id,
4779 stage="",
4780 error_message=error_description_nslcmop,
4781 operation_state=nslcmop_operation_state,
4782 other_update=db_nslcmop_update,
4783 )
lloretgalleg6d488782020-07-22 10:13:46 +00004784 if ns_state == "NOT_INSTANTIATED":
4785 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004786 self.db.set_list(
4787 "vnfrs",
4788 {"nsr-id-ref": nsr_id},
4789 {"_admin.nsState": "NOT_INSTANTIATED"},
4790 )
lloretgalleg6d488782020-07-22 10:13:46 +00004791 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004792 self.logger.warn(
4793 logging_text
4794 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4795 nsr_id, e
4796 )
4797 )
tiernoa17d4f42020-04-28 09:59:23 +00004798 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004799 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004800 if nslcmop_operation_state:
4801 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004802 await self.msg.aiowrite(
4803 "ns",
4804 "terminated",
4805 {
4806 "nsr_id": nsr_id,
4807 "nslcmop_id": nslcmop_id,
4808 "operationState": nslcmop_operation_state,
4809 "autoremove": autoremove,
4810 },
4811 loop=self.loop,
4812 )
tierno59d22d22018-09-25 18:10:19 +02004813 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004814 self.logger.error(
4815 logging_text + "kafka_write notification Exception {}".format(e)
4816 )
quilesj7e13aeb2019-10-08 13:34:55 +02004817
tierno59d22d22018-09-25 18:10:19 +02004818 self.logger.debug(logging_text + "Exit")
4819 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4820
garciadeblas5697b8b2021-03-24 09:17:02 +01004821 async def _wait_for_tasks(
4822 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4823 ):
tiernoe876f672020-02-13 14:34:48 +00004824 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004825 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004826 error_list = []
4827 pending_tasks = list(created_tasks_info.keys())
4828 num_tasks = len(pending_tasks)
4829 num_done = 0
4830 stage[1] = "{}/{}.".format(num_done, num_tasks)
4831 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004832 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004833 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004834 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004835 done, pending_tasks = await asyncio.wait(
4836 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4837 )
tiernoe876f672020-02-13 14:34:48 +00004838 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004839 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004840 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004841 new_error = created_tasks_info[task] + ": Timeout"
4842 error_detail_list.append(new_error)
4843 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004844 break
4845 for task in done:
4846 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004847 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004848 else:
4849 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004850 if exc:
4851 if isinstance(exc, asyncio.TimeoutError):
4852 exc = "Timeout"
4853 new_error = created_tasks_info[task] + ": {}".format(exc)
4854 error_list.append(created_tasks_info[task])
4855 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004856 if isinstance(
4857 exc,
4858 (
4859 str,
4860 DbException,
4861 N2VCException,
4862 ROclient.ROClientException,
4863 LcmException,
4864 K8sException,
4865 NgRoException,
4866 ),
4867 ):
tierno067e04a2020-03-31 12:53:13 +00004868 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004869 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004870 exc_traceback = "".join(
4871 traceback.format_exception(None, exc, exc.__traceback__)
4872 )
4873 self.logger.error(
4874 logging_text
4875 + created_tasks_info[task]
4876 + " "
4877 + exc_traceback
4878 )
tierno067e04a2020-03-31 12:53:13 +00004879 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004880 self.logger.debug(
4881 logging_text + created_tasks_info[task] + ": Done"
4882 )
tiernoe876f672020-02-13 14:34:48 +00004883 stage[1] = "{}/{}.".format(num_done, num_tasks)
4884 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004885 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004886 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004887 self.update_db_2(
4888 "nsrs",
4889 nsr_id,
4890 {
4891 "errorDescription": "Error at: " + ", ".join(error_list),
4892 "errorDetail": ". ".join(error_detail_list),
4893 },
4894 )
tiernoe876f672020-02-13 14:34:48 +00004895 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004896 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004897
tiernoda1ff8c2020-10-22 14:12:46 +00004898 @staticmethod
4899 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004900 """
4901 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4902 The default-value is used. If it is between < > it look for a value at instantiation_params
4903 :param primitive_desc: portion of VNFD/NSD that describes primitive
4904 :param params: Params provided by user
4905 :param instantiation_params: Instantiation params provided by user
4906 :return: a dictionary with the calculated params
4907 """
4908 calculated_params = {}
4909 for parameter in primitive_desc.get("parameter", ()):
4910 param_name = parameter["name"]
4911 if param_name in params:
4912 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004913 elif "default-value" in parameter or "value" in parameter:
4914 if "value" in parameter:
4915 calculated_params[param_name] = parameter["value"]
4916 else:
4917 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004918 if (
4919 isinstance(calculated_params[param_name], str)
4920 and calculated_params[param_name].startswith("<")
4921 and calculated_params[param_name].endswith(">")
4922 ):
tierno98ad6ea2019-05-30 17:16:28 +00004923 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004924 calculated_params[param_name] = instantiation_params[
4925 calculated_params[param_name][1:-1]
4926 ]
tiernoda964822019-01-14 15:53:47 +00004927 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004928 raise LcmException(
4929 "Parameter {} needed to execute primitive {} not provided".format(
4930 calculated_params[param_name], primitive_desc["name"]
4931 )
4932 )
tiernoda964822019-01-14 15:53:47 +00004933 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004934 raise LcmException(
4935 "Parameter {} needed to execute primitive {} not provided".format(
4936 param_name, primitive_desc["name"]
4937 )
4938 )
tierno59d22d22018-09-25 18:10:19 +02004939
tiernoda964822019-01-14 15:53:47 +00004940 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004941 calculated_params[param_name] = yaml.safe_dump(
4942 calculated_params[param_name], default_flow_style=True, width=256
4943 )
4944 elif isinstance(calculated_params[param_name], str) and calculated_params[
4945 param_name
4946 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004947 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004948 if parameter.get("data-type") == "INTEGER":
4949 try:
4950 calculated_params[param_name] = int(calculated_params[param_name])
4951 except ValueError: # error converting string to int
4952 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004953 "Parameter {} of primitive {} must be integer".format(
4954 param_name, primitive_desc["name"]
4955 )
4956 )
tiernofa40e692020-10-14 14:59:36 +00004957 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004958 calculated_params[param_name] = not (
4959 (str(calculated_params[param_name])).lower() == "false"
4960 )
tiernoc3f2a822019-11-05 13:45:04 +00004961
4962 # add always ns_config_info if primitive name is config
4963 if primitive_desc["name"] == "config":
4964 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004965 calculated_params["ns_config_info"] = instantiation_params[
4966 "ns_config_info"
4967 ]
tiernoda964822019-01-14 15:53:47 +00004968 return calculated_params
4969
garciadeblas5697b8b2021-03-24 09:17:02 +01004970 def _look_for_deployed_vca(
4971 self,
4972 deployed_vca,
4973 member_vnf_index,
4974 vdu_id,
4975 vdu_count_index,
4976 kdu_name=None,
4977 ee_descriptor_id=None,
4978 ):
tiernoe876f672020-02-13 14:34:48 +00004979 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4980 for vca in deployed_vca:
4981 if not vca:
4982 continue
4983 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4984 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004985 if (
4986 vdu_count_index is not None
4987 and vdu_count_index != vca["vdu_count_index"]
4988 ):
tiernoe876f672020-02-13 14:34:48 +00004989 continue
4990 if kdu_name and kdu_name != vca["kdu_name"]:
4991 continue
tiernoa278b842020-07-08 15:33:55 +00004992 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4993 continue
tiernoe876f672020-02-13 14:34:48 +00004994 break
4995 else:
4996 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004997 raise LcmException(
4998 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4999 " is not deployed".format(
5000 member_vnf_index,
5001 vdu_id,
5002 vdu_count_index,
5003 kdu_name,
5004 ee_descriptor_id,
5005 )
5006 )
tiernoe876f672020-02-13 14:34:48 +00005007 # get ee_id
5008 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01005009 vca_type = vca.get(
5010 "type", "lxc_proxy_charm"
5011 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00005012 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005013 raise LcmException(
5014 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
5015 "execution environment".format(
5016 member_vnf_index, vdu_id, kdu_name, vdu_count_index
5017 )
5018 )
tierno588547c2020-07-01 15:30:20 +00005019 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00005020
David Garciac1fe90a2021-03-31 19:12:02 +02005021 async def _ns_execute_primitive(
5022 self,
5023 ee_id,
5024 primitive,
5025 primitive_params,
5026 retries=0,
5027 retries_interval=30,
5028 timeout=None,
5029 vca_type=None,
5030 db_dict=None,
5031 vca_id: str = None,
5032 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00005033 try:
tierno98ad6ea2019-05-30 17:16:28 +00005034 if primitive == "config":
5035 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00005036
tierno588547c2020-07-01 15:30:20 +00005037 vca_type = vca_type or "lxc_proxy_charm"
5038
quilesj7e13aeb2019-10-08 13:34:55 +02005039 while retries >= 0:
5040 try:
tierno067e04a2020-03-31 12:53:13 +00005041 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00005042 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00005043 ee_id=ee_id,
5044 primitive_name=primitive,
5045 params_dict=primitive_params,
5046 progress_timeout=self.timeout_progress_primitive,
tierno588547c2020-07-01 15:30:20 +00005047 total_timeout=self.timeout_primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02005048 db_dict=db_dict,
5049 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03005050 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005051 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005052 timeout=timeout or self.timeout_primitive,
5053 )
quilesj7e13aeb2019-10-08 13:34:55 +02005054 # execution was OK
5055 break
tierno067e04a2020-03-31 12:53:13 +00005056 except asyncio.CancelledError:
5057 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005058 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005059 retries -= 1
5060 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005061 self.logger.debug(
5062 "Error executing action {} on {} -> {}".format(
5063 primitive, ee_id, e
5064 )
5065 )
quilesj7e13aeb2019-10-08 13:34:55 +02005066 # wait and retry
5067 await asyncio.sleep(retries_interval, loop=self.loop)
tierno73d8bd02019-11-18 17:33:27 +00005068 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005069 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005070 e = N2VCException(
5071 message="Timed out waiting for action to complete"
5072 )
5073 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005074
garciadeblas5697b8b2021-03-24 09:17:02 +01005075 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005076
tierno067e04a2020-03-31 12:53:13 +00005077 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005078 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005079 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005080 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005081
ksaikiranr3fde2c72021-03-15 10:39:06 +05305082 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5083 """
5084 Updating the vca_status with latest juju information in nsrs record
5085 :param: nsr_id: Id of the nsr
5086 :param: nslcmop_id: Id of the nslcmop
5087 :return: None
5088 """
5089
5090 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5091 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005092 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005093 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005094 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5095 cluster_uuid, kdu_instance, cluster_type = (
5096 k8s["k8scluster-uuid"],
5097 k8s["kdu-instance"],
5098 k8s["k8scluster-type"],
5099 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005100 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005101 cluster_uuid=cluster_uuid,
5102 kdu_instance=kdu_instance,
5103 filter={"_id": nsr_id},
5104 vca_id=vca_id,
5105 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005106 )
ksaikiranr656b6dd2021-02-19 10:25:18 +05305107 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005108 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305109 table, filter = "nsrs", {"_id": nsr_id}
5110 path = "_admin.deployed.VCA.{}.".format(vca_index)
5111 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305112
5113 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5114 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5115
tierno59d22d22018-09-25 18:10:19 +02005116 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005117 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005118 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005119 if not task_is_locked_by_me:
5120 return
5121
tierno59d22d22018-09-25 18:10:19 +02005122 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5123 self.logger.debug(logging_text + "Enter")
5124 # get all needed from database
5125 db_nsr = None
5126 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005127 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005128 db_nslcmop_update = {}
5129 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005130 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005131 exc = None
5132 try:
kuused124bfe2019-06-18 12:09:24 +02005133 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005134 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005135 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005136
quilesj4cda56b2019-12-05 10:02:20 +00005137 self._write_ns_status(
5138 nsr_id=nsr_id,
5139 ns_state=None,
5140 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005141 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005142 )
5143
tierno59d22d22018-09-25 18:10:19 +02005144 step = "Getting information from database"
5145 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5146 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005147 if db_nslcmop["operationParams"].get("primitive_params"):
5148 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5149 db_nslcmop["operationParams"]["primitive_params"]
5150 )
tiernoda964822019-01-14 15:53:47 +00005151
tiernoe4f7e6c2018-11-27 14:55:30 +00005152 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005153 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005154 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005155 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005156 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005157 primitive = db_nslcmop["operationParams"]["primitive"]
5158 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005159 timeout_ns_action = db_nslcmop["operationParams"].get(
5160 "timeout_ns_action", self.timeout_primitive
5161 )
tierno59d22d22018-09-25 18:10:19 +02005162
tierno1b633412019-02-25 16:48:23 +00005163 if vnf_index:
5164 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005165 db_vnfr = self.db.get_one(
5166 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5167 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005168 if db_vnfr.get("kdur"):
5169 kdur_list = []
5170 for kdur in db_vnfr["kdur"]:
5171 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005172 kdur["additionalParams"] = json.loads(
5173 kdur["additionalParams"]
5174 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005175 kdur_list.append(kdur)
5176 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005177 step = "Getting vnfd from database"
5178 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005179
5180 # Sync filesystem before running a primitive
5181 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005182 else:
tierno067e04a2020-03-31 12:53:13 +00005183 step = "Getting nsd from database"
5184 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005185
David Garciac1fe90a2021-03-31 19:12:02 +02005186 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005187 # for backward compatibility
5188 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5189 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5190 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5191 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5192
tiernoda964822019-01-14 15:53:47 +00005193 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005194 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005195 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005196 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005197 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005198 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005199 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005200 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005201 else:
tiernoa278b842020-07-08 15:33:55 +00005202 descriptor_configuration = db_nsd.get("ns-configuration")
5203
garciadeblas5697b8b2021-03-24 09:17:02 +01005204 if descriptor_configuration and descriptor_configuration.get(
5205 "config-primitive"
5206 ):
tiernoa278b842020-07-08 15:33:55 +00005207 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005208 if config_primitive["name"] == primitive:
5209 config_primitive_desc = config_primitive
5210 break
tiernoda964822019-01-14 15:53:47 +00005211
garciadeblas6bed6b32020-07-20 11:05:42 +00005212 if not config_primitive_desc:
5213 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005214 raise LcmException(
5215 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5216 primitive
5217 )
5218 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005219 primitive_name = primitive
5220 ee_descriptor_id = None
5221 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005222 primitive_name = config_primitive_desc.get(
5223 "execution-environment-primitive", primitive
5224 )
5225 ee_descriptor_id = config_primitive_desc.get(
5226 "execution-environment-ref"
5227 )
tierno1b633412019-02-25 16:48:23 +00005228
tierno1b633412019-02-25 16:48:23 +00005229 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005230 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005231 vdur = next(
5232 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5233 )
bravof922c4172020-11-24 21:21:43 -03005234 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005235 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005236 kdur = next(
5237 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5238 )
bravof922c4172020-11-24 21:21:43 -03005239 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005240 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005241 desc_params = parse_yaml_strings(
5242 db_vnfr.get("additionalParamsForVnf")
5243 )
tierno1b633412019-02-25 16:48:23 +00005244 else:
bravof922c4172020-11-24 21:21:43 -03005245 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005246 if kdu_name and get_configuration(db_vnfd, kdu_name):
5247 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005248 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005249 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005250 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005251 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005252 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005253 kdu = find_in_list(
5254 nsr_deployed["K8s"],
5255 lambda kdu: kdu_name == kdu["kdu-name"]
5256 and kdu["member-vnf-index"] == vnf_index,
5257 )
5258 kdu_action = (
5259 True
5260 if primitive_name in actions
5261 and kdu["k8scluster-type"] not in ("helm-chart", "helm-chart-v3")
5262 else False
5263 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005264
tiernoda964822019-01-14 15:53:47 +00005265 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005266 if kdu_name and (
5267 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5268 ):
tierno067e04a2020-03-31 12:53:13 +00005269 # kdur and desc_params already set from before
5270 if primitive_params:
5271 desc_params.update(primitive_params)
5272 # TODO Check if we will need something at vnf level
5273 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005274 if (
5275 kdu_name == kdu["kdu-name"]
5276 and kdu["member-vnf-index"] == vnf_index
5277 ):
tierno067e04a2020-03-31 12:53:13 +00005278 break
5279 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005280 raise LcmException(
5281 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5282 )
quilesj7e13aeb2019-10-08 13:34:55 +02005283
tierno067e04a2020-03-31 12:53:13 +00005284 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005285 msg = "unknown k8scluster-type '{}'".format(
5286 kdu.get("k8scluster-type")
5287 )
tierno067e04a2020-03-31 12:53:13 +00005288 raise LcmException(msg)
5289
garciadeblas5697b8b2021-03-24 09:17:02 +01005290 db_dict = {
5291 "collection": "nsrs",
5292 "filter": {"_id": nsr_id},
5293 "path": "_admin.deployed.K8s.{}".format(index),
5294 }
5295 self.logger.debug(
5296 logging_text
5297 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5298 )
tiernoa278b842020-07-08 15:33:55 +00005299 step = "Executing kdu {}".format(primitive_name)
5300 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00005301 if desc_params.get("kdu_model"):
5302 kdu_model = desc_params.get("kdu_model")
5303 del desc_params["kdu_model"]
5304 else:
5305 kdu_model = kdu.get("kdu-model")
5306 parts = kdu_model.split(sep=":")
5307 if len(parts) == 2:
5308 kdu_model = parts[0]
limondd8b0a62022-10-28 10:39:16 +02005309 if desc_params.get("kdu_atomic_upgrade"):
garciadeblasfb1e25f2022-11-18 14:36:22 +01005310 atomic_upgrade = desc_params.get(
5311 "kdu_atomic_upgrade"
5312 ).lower() in ("yes", "true", "1")
limondd8b0a62022-10-28 10:39:16 +02005313 del desc_params["kdu_atomic_upgrade"]
5314 else:
5315 atomic_upgrade = True
tierno067e04a2020-03-31 12:53:13 +00005316
5317 detailed_status = await asyncio.wait_for(
5318 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5319 cluster_uuid=kdu.get("k8scluster-uuid"),
5320 kdu_instance=kdu.get("kdu-instance"),
limondd8b0a62022-10-28 10:39:16 +02005321 atomic=atomic_upgrade,
garciadeblas5697b8b2021-03-24 09:17:02 +01005322 kdu_model=kdu_model,
5323 params=desc_params,
5324 db_dict=db_dict,
5325 timeout=timeout_ns_action,
5326 ),
5327 timeout=timeout_ns_action + 10,
5328 )
5329 self.logger.debug(
5330 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5331 )
tiernoa278b842020-07-08 15:33:55 +00005332 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005333 detailed_status = await asyncio.wait_for(
5334 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5335 cluster_uuid=kdu.get("k8scluster-uuid"),
5336 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005337 db_dict=db_dict,
5338 ),
5339 timeout=timeout_ns_action,
5340 )
tiernoa278b842020-07-08 15:33:55 +00005341 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005342 detailed_status = await asyncio.wait_for(
5343 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5344 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005345 kdu_instance=kdu.get("kdu-instance"),
5346 vca_id=vca_id,
5347 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005348 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005349 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005350 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005351 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5352 kdu["kdu-name"], nsr_id
5353 )
5354 params = self._map_primitive_params(
5355 config_primitive_desc, primitive_params, desc_params
5356 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005357
5358 detailed_status = await asyncio.wait_for(
5359 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5360 cluster_uuid=kdu.get("k8scluster-uuid"),
5361 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005362 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005363 params=params,
5364 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005365 timeout=timeout_ns_action,
5366 vca_id=vca_id,
5367 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005368 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005369 )
tierno067e04a2020-03-31 12:53:13 +00005370
5371 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005372 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005373 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005374 detailed_status = ""
5375 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005376 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005377 ee_id, vca_type = self._look_for_deployed_vca(
5378 nsr_deployed["VCA"],
5379 member_vnf_index=vnf_index,
5380 vdu_id=vdu_id,
5381 vdu_count_index=vdu_count_index,
5382 ee_descriptor_id=ee_descriptor_id,
5383 )
5384 for vca_index, vca_deployed in enumerate(
5385 db_nsr["_admin"]["deployed"]["VCA"]
5386 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305387 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005388 db_dict = {
5389 "collection": "nsrs",
5390 "filter": {"_id": nsr_id},
5391 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5392 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305393 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005394 (
5395 nslcmop_operation_state,
5396 detailed_status,
5397 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005398 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005399 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005400 primitive_params=self._map_primitive_params(
5401 config_primitive_desc, primitive_params, desc_params
5402 ),
tierno588547c2020-07-01 15:30:20 +00005403 timeout=timeout_ns_action,
5404 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005405 db_dict=db_dict,
5406 vca_id=vca_id,
5407 )
tierno067e04a2020-03-31 12:53:13 +00005408
5409 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005410 error_description_nslcmop = (
5411 detailed_status if nslcmop_operation_state == "FAILED" else ""
5412 )
5413 self.logger.debug(
5414 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005415 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005416 nslcmop_operation_state, detailed_status
5417 )
5418 )
tierno59d22d22018-09-25 18:10:19 +02005419 return # database update is called inside finally
5420
tiernof59ad6c2020-04-08 12:50:52 +00005421 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005422 self.logger.error(logging_text + "Exit Exception {}".format(e))
5423 exc = e
5424 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005425 self.logger.error(
5426 logging_text + "Cancelled Exception while '{}'".format(step)
5427 )
tierno59d22d22018-09-25 18:10:19 +02005428 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005429 except asyncio.TimeoutError:
5430 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5431 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005432 except Exception as e:
5433 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005434 self.logger.critical(
5435 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5436 exc_info=True,
5437 )
tierno59d22d22018-09-25 18:10:19 +02005438 finally:
tierno067e04a2020-03-31 12:53:13 +00005439 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005440 db_nslcmop_update[
5441 "detailed-status"
5442 ] = (
5443 detailed_status
5444 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005445 nslcmop_operation_state = "FAILED"
5446 if db_nsr:
5447 self._write_ns_status(
5448 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005449 ns_state=db_nsr[
5450 "nsState"
5451 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005452 current_operation="IDLE",
5453 current_operation_id=None,
5454 # error_description=error_description_nsr,
5455 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005456 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005457 )
5458
garciadeblas5697b8b2021-03-24 09:17:02 +01005459 self._write_op_status(
5460 op_id=nslcmop_id,
5461 stage="",
5462 error_message=error_description_nslcmop,
5463 operation_state=nslcmop_operation_state,
5464 other_update=db_nslcmop_update,
5465 )
tierno067e04a2020-03-31 12:53:13 +00005466
tierno59d22d22018-09-25 18:10:19 +02005467 if nslcmop_operation_state:
5468 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005469 await self.msg.aiowrite(
5470 "ns",
5471 "actioned",
5472 {
5473 "nsr_id": nsr_id,
5474 "nslcmop_id": nslcmop_id,
5475 "operationState": nslcmop_operation_state,
5476 },
5477 loop=self.loop,
5478 )
tierno59d22d22018-09-25 18:10:19 +02005479 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005480 self.logger.error(
5481 logging_text + "kafka_write notification Exception {}".format(e)
5482 )
tierno59d22d22018-09-25 18:10:19 +02005483 self.logger.debug(logging_text + "Exit")
5484 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005485 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005486
elumalaica7ece02022-04-12 12:47:32 +05305487 async def terminate_vdus(
5488 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5489 ):
5490 """This method terminates VDUs
5491
5492 Args:
5493 db_vnfr: VNF instance record
5494 member_vnf_index: VNF index to identify the VDUs to be removed
5495 db_nsr: NS instance record
5496 update_db_nslcmops: Nslcmop update record
5497 """
5498 vca_scaling_info = []
5499 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5500 scaling_info["scaling_direction"] = "IN"
5501 scaling_info["vdu-delete"] = {}
5502 scaling_info["kdu-delete"] = {}
5503 db_vdur = db_vnfr.get("vdur")
5504 vdur_list = copy(db_vdur)
5505 count_index = 0
5506 for index, vdu in enumerate(vdur_list):
5507 vca_scaling_info.append(
5508 {
5509 "osm_vdu_id": vdu["vdu-id-ref"],
5510 "member-vnf-index": member_vnf_index,
5511 "type": "delete",
5512 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005513 }
5514 )
elumalaica7ece02022-04-12 12:47:32 +05305515 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5516 scaling_info["vdu"].append(
5517 {
5518 "name": vdu.get("name") or vdu.get("vdu-name"),
5519 "vdu_id": vdu["vdu-id-ref"],
5520 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005521 }
5522 )
elumalaica7ece02022-04-12 12:47:32 +05305523 for interface in vdu["interfaces"]:
5524 scaling_info["vdu"][index]["interface"].append(
5525 {
5526 "name": interface["name"],
5527 "ip_address": interface["ip-address"],
5528 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005529 }
5530 )
elumalaica7ece02022-04-12 12:47:32 +05305531 self.logger.info("NS update scaling info{}".format(scaling_info))
5532 stage[2] = "Terminating VDUs"
5533 if scaling_info.get("vdu-delete"):
5534 # scale_process = "RO"
5535 if self.ro_config.get("ng"):
5536 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005537 logging_text,
5538 db_nsr,
5539 update_db_nslcmops,
5540 db_vnfr,
5541 scaling_info,
5542 stage,
elumalaica7ece02022-04-12 12:47:32 +05305543 )
5544
preethika.p28b0bf82022-09-23 07:36:28 +00005545 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305546 """This method is to Remove VNF instances from NS.
5547
5548 Args:
5549 nsr_id: NS instance id
5550 nslcmop_id: nslcmop id of update
5551 vnf_instance_id: id of the VNF instance to be removed
5552
5553 Returns:
5554 result: (str, str) COMPLETED/FAILED, details
5555 """
5556 try:
5557 db_nsr_update = {}
5558 logging_text = "Task ns={} update ".format(nsr_id)
5559 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5560 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5561 if check_vnfr_count > 1:
5562 stage = ["", "", ""]
5563 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005564 self.logger.debug(
5565 step + " after having waited for previous tasks to be completed"
5566 )
elumalaica7ece02022-04-12 12:47:32 +05305567 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5568 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5569 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5570 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5571 """ db_vnfr = self.db.get_one(
5572 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5573
5574 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005575 await self.terminate_vdus(
5576 db_vnfr,
5577 member_vnf_index,
5578 db_nsr,
5579 update_db_nslcmops,
5580 stage,
5581 logging_text,
5582 )
elumalaica7ece02022-04-12 12:47:32 +05305583
5584 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5585 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005586 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5587 "constituent-vnfr-ref"
5588 )
elumalaica7ece02022-04-12 12:47:32 +05305589 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5590 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5591 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5592 return "COMPLETED", "Done"
5593 else:
5594 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005595 raise LcmException(
5596 "{} Cannot terminate the last VNF in this NS.".format(
5597 vnf_instance_id
5598 )
5599 )
elumalaica7ece02022-04-12 12:47:32 +05305600 except (LcmException, asyncio.CancelledError):
5601 raise
5602 except Exception as e:
5603 self.logger.debug("Error removing VNF {}".format(e))
5604 return "FAILED", "Error removing VNF {}".format(e)
5605
elumalaib9e357c2022-04-27 09:58:38 +05305606 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005607 self,
5608 nsr_id,
5609 nslcmop_id,
5610 db_vnfd,
5611 db_vnfr,
5612 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305613 ):
5614 """This method updates and redeploys VNF instances
5615
5616 Args:
5617 nsr_id: NS instance id
5618 nslcmop_id: nslcmop id
5619 db_vnfd: VNF descriptor
5620 db_vnfr: VNF instance record
5621 db_nsr: NS instance record
5622
5623 Returns:
5624 result: (str, str) COMPLETED/FAILED, details
5625 """
5626 try:
5627 count_index = 0
5628 stage = ["", "", ""]
5629 logging_text = "Task ns={} update ".format(nsr_id)
5630 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5631 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5632
5633 # Terminate old VNF resources
5634 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005635 await self.terminate_vdus(
5636 db_vnfr,
5637 member_vnf_index,
5638 db_nsr,
5639 update_db_nslcmops,
5640 stage,
5641 logging_text,
5642 )
elumalaib9e357c2022-04-27 09:58:38 +05305643
5644 # old_vnfd_id = db_vnfr["vnfd-id"]
5645 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5646 new_db_vnfd = db_vnfd
5647 # new_vnfd_ref = new_db_vnfd["id"]
5648 # new_vnfd_id = vnfd_id
5649
5650 # Create VDUR
5651 new_vnfr_cp = []
5652 for cp in new_db_vnfd.get("ext-cpd", ()):
5653 vnf_cp = {
5654 "name": cp.get("id"),
5655 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5656 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5657 "id": cp.get("id"),
5658 }
5659 new_vnfr_cp.append(vnf_cp)
5660 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5661 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5662 # new_vnfr_update = {"vnfd-ref": new_vnfd_ref, "vnfd-id": new_vnfd_id, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""}
preethika.p28b0bf82022-09-23 07:36:28 +00005663 new_vnfr_update = {
5664 "revision": latest_vnfd_revision,
5665 "connection-point": new_vnfr_cp,
5666 "vdur": new_vdur,
5667 "ip-address": "",
5668 }
elumalaib9e357c2022-04-27 09:58:38 +05305669 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5670 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005671 "vnfrs",
5672 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305673 )
5674
5675 # Instantiate new VNF resources
5676 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5677 vca_scaling_info = []
5678 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5679 scaling_info["scaling_direction"] = "OUT"
5680 scaling_info["vdu-create"] = {}
5681 scaling_info["kdu-create"] = {}
5682 vdud_instantiate_list = db_vnfd["vdu"]
5683 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005684 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305685 if cloud_init_text:
5686 additional_params = (
5687 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5688 or {}
5689 )
5690 cloud_init_list = []
5691 if cloud_init_text:
5692 # TODO Information of its own ip is not available because db_vnfr is not updated.
5693 additional_params["OSM"] = get_osm_params(
5694 updated_db_vnfr, vdud["id"], 1
5695 )
5696 cloud_init_list.append(
5697 self._parse_cloud_init(
5698 cloud_init_text,
5699 additional_params,
5700 db_vnfd["id"],
5701 vdud["id"],
5702 )
5703 )
5704 vca_scaling_info.append(
5705 {
5706 "osm_vdu_id": vdud["id"],
5707 "member-vnf-index": member_vnf_index,
5708 "type": "create",
5709 "vdu_index": count_index,
5710 }
5711 )
5712 scaling_info["vdu-create"][vdud["id"]] = count_index
5713 if self.ro_config.get("ng"):
5714 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005715 "New Resources to be deployed: {}".format(scaling_info)
5716 )
elumalaib9e357c2022-04-27 09:58:38 +05305717 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005718 logging_text,
5719 db_nsr,
5720 update_db_nslcmops,
5721 updated_db_vnfr,
5722 scaling_info,
5723 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305724 )
5725 return "COMPLETED", "Done"
5726 except (LcmException, asyncio.CancelledError):
5727 raise
5728 except Exception as e:
5729 self.logger.debug("Error updating VNF {}".format(e))
5730 return "FAILED", "Error updating VNF {}".format(e)
5731
aticigdffa6212022-04-12 15:27:53 +03005732 async def _ns_charm_upgrade(
5733 self,
5734 ee_id,
5735 charm_id,
5736 charm_type,
5737 path,
5738 timeout: float = None,
5739 ) -> (str, str):
5740 """This method upgrade charms in VNF instances
5741
5742 Args:
5743 ee_id: Execution environment id
5744 path: Local path to the charm
5745 charm_id: charm-id
5746 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5747 timeout: (Float) Timeout for the ns update operation
5748
5749 Returns:
5750 result: (str, str) COMPLETED/FAILED, details
5751 """
5752 try:
5753 charm_type = charm_type or "lxc_proxy_charm"
5754 output = await self.vca_map[charm_type].upgrade_charm(
5755 ee_id=ee_id,
5756 path=path,
5757 charm_id=charm_id,
5758 charm_type=charm_type,
5759 timeout=timeout or self.timeout_ns_update,
5760 )
5761
5762 if output:
5763 return "COMPLETED", output
5764
5765 except (LcmException, asyncio.CancelledError):
5766 raise
5767
5768 except Exception as e:
5769
5770 self.logger.debug("Error upgrading charm {}".format(path))
5771
5772 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5773
5774 async def update(self, nsr_id, nslcmop_id):
5775 """Update NS according to different update types
5776
5777 This method performs upgrade of VNF instances then updates the revision
5778 number in VNF record
5779
5780 Args:
5781 nsr_id: Network service will be updated
5782 nslcmop_id: ns lcm operation id
5783
5784 Returns:
5785 It may raise DbException, LcmException, N2VCException, K8sException
5786
5787 """
5788 # Try to lock HA task here
5789 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5790 if not task_is_locked_by_me:
5791 return
5792
5793 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5794 self.logger.debug(logging_text + "Enter")
5795
5796 # Set the required variables to be filled up later
5797 db_nsr = None
5798 db_nslcmop_update = {}
5799 vnfr_update = {}
5800 nslcmop_operation_state = None
5801 db_nsr_update = {}
5802 error_description_nslcmop = ""
5803 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305804 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005805 detailed_status = ""
5806
5807 try:
5808 # wait for any previous tasks in process
5809 step = "Waiting for previous operations to terminate"
5810 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5811 self._write_ns_status(
5812 nsr_id=nsr_id,
5813 ns_state=None,
5814 current_operation="UPDATING",
5815 current_operation_id=nslcmop_id,
5816 )
5817
5818 step = "Getting nslcmop from database"
5819 db_nslcmop = self.db.get_one(
5820 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5821 )
5822 update_type = db_nslcmop["operationParams"]["updateType"]
5823
5824 step = "Getting nsr from database"
5825 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5826 old_operational_status = db_nsr["operational-status"]
5827 db_nsr_update["operational-status"] = "updating"
5828 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5829 nsr_deployed = db_nsr["_admin"].get("deployed")
5830
5831 if update_type == "CHANGE_VNFPKG":
5832
5833 # Get the input parameters given through update request
5834 vnf_instance_id = db_nslcmop["operationParams"][
5835 "changeVnfPackageData"
5836 ].get("vnfInstanceId")
5837
5838 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5839 "vnfdId"
5840 )
5841 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5842
5843 step = "Getting vnfr from database"
5844 db_vnfr = self.db.get_one(
5845 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5846 )
5847
5848 step = "Getting vnfds from database"
5849 # Latest VNFD
5850 latest_vnfd = self.db.get_one(
5851 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5852 )
5853 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5854
5855 # Current VNFD
5856 current_vnf_revision = db_vnfr.get("revision", 1)
5857 current_vnfd = self.db.get_one(
5858 "vnfds_revisions",
5859 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5860 fail_on_empty=False,
5861 )
5862 # Charm artifact paths will be filled up later
5863 (
5864 current_charm_artifact_path,
5865 target_charm_artifact_path,
5866 charm_artifact_paths,
garciadeblasfb1e25f2022-11-18 14:36:22 +01005867 helm_artifacts,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005868 ) = ([], [], [], [])
aticigdffa6212022-04-12 15:27:53 +03005869
5870 step = "Checking if revision has changed in VNFD"
5871 if current_vnf_revision != latest_vnfd_revision:
5872
elumalaib9e357c2022-04-27 09:58:38 +05305873 change_type = "policy_updated"
5874
aticigdffa6212022-04-12 15:27:53 +03005875 # There is new revision of VNFD, update operation is required
5876 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005877 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005878
5879 step = "Removing the VNFD packages if they exist in the local path"
5880 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5881 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5882
5883 step = "Get the VNFD packages from FSMongo"
5884 self.fs.sync(from_path=latest_vnfd_path)
5885 self.fs.sync(from_path=current_vnfd_path)
5886
5887 step = (
5888 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5889 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005890 current_base_folder = current_vnfd["_admin"]["storage"]
5891 latest_base_folder = latest_vnfd["_admin"]["storage"]
aticigdffa6212022-04-12 15:27:53 +03005892
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005893 for vca_index, vca_deployed in enumerate(
aticigdffa6212022-04-12 15:27:53 +03005894 get_iterable(nsr_deployed, "VCA")
5895 ):
5896 vnf_index = db_vnfr.get("member-vnf-index-ref")
5897
5898 # Getting charm-id and charm-type
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005899 if vca_deployed.get("member-vnf-index") == vnf_index:
5900 vca_id = self.get_vca_id(db_vnfr, db_nsr)
5901 vca_type = vca_deployed.get("type")
5902 vdu_count_index = vca_deployed.get("vdu_count_index")
aticigdffa6212022-04-12 15:27:53 +03005903
5904 # Getting ee-id
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005905 ee_id = vca_deployed.get("ee_id")
aticigdffa6212022-04-12 15:27:53 +03005906
5907 step = "Getting descriptor config"
aticig1dda84c2022-09-10 01:56:58 +03005908 if current_vnfd.get("kdu"):
5909
5910 search_key = "kdu_name"
5911 else:
5912 search_key = "vnfd_id"
5913
5914 entity_id = vca_deployed.get(search_key)
5915
aticigdffa6212022-04-12 15:27:53 +03005916 descriptor_config = get_configuration(
aticig1dda84c2022-09-10 01:56:58 +03005917 current_vnfd, entity_id
aticigdffa6212022-04-12 15:27:53 +03005918 )
5919
5920 if "execution-environment-list" in descriptor_config:
5921 ee_list = descriptor_config.get(
5922 "execution-environment-list", []
5923 )
5924 else:
5925 ee_list = []
5926
5927 # There could be several charm used in the same VNF
5928 for ee_item in ee_list:
5929 if ee_item.get("juju"):
5930
5931 step = "Getting charm name"
5932 charm_name = ee_item["juju"].get("charm")
5933
5934 step = "Setting Charm artifact paths"
5935 current_charm_artifact_path.append(
5936 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005937 current_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005938 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005939 vca_type,
aticigdffa6212022-04-12 15:27:53 +03005940 current_vnf_revision,
5941 )
5942 )
5943 target_charm_artifact_path.append(
5944 get_charm_artifact_path(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005945 latest_base_folder,
aticigdffa6212022-04-12 15:27:53 +03005946 charm_name,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005947 vca_type,
aticigd7083542022-05-30 20:45:55 +03005948 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005949 )
5950 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005951 elif ee_item.get("helm-chart"):
5952 # add chart to list and all parameters
5953 step = "Getting helm chart name"
5954 chart_name = ee_item.get("helm-chart")
garciadeblasfb1e25f2022-11-18 14:36:22 +01005955 if (
5956 ee_item.get("helm-version")
5957 and ee_item.get("helm-version") == "v2"
5958 ):
Gabriel Cubae539a8d2022-10-10 11:34:51 -05005959 vca_type = "helm"
5960 else:
5961 vca_type = "helm-v3"
5962 step = "Setting Helm chart artifact paths"
5963
garciadeblasfb1e25f2022-11-18 14:36:22 +01005964 helm_artifacts.append(
5965 {
5966 "current_artifact_path": get_charm_artifact_path(
5967 current_base_folder,
5968 chart_name,
5969 vca_type,
5970 current_vnf_revision,
5971 ),
5972 "target_artifact_path": get_charm_artifact_path(
5973 latest_base_folder,
5974 chart_name,
5975 vca_type,
5976 latest_vnfd_revision,
5977 ),
5978 "ee_id": ee_id,
5979 "vca_index": vca_index,
5980 "vdu_index": vdu_count_index,
5981 }
5982 )
aticigdffa6212022-04-12 15:27:53 +03005983
5984 charm_artifact_paths = zip(
5985 current_charm_artifact_path, target_charm_artifact_path
5986 )
5987
5988 step = "Checking if software version has changed in VNFD"
5989 if find_software_version(current_vnfd) != find_software_version(
5990 latest_vnfd
5991 ):
5992
5993 step = "Checking if existing VNF has charm"
5994 for current_charm_path, target_charm_path in list(
5995 charm_artifact_paths
5996 ):
5997 if current_charm_path:
5998 raise LcmException(
5999 "Software version change is not supported as VNF instance {} has charm.".format(
6000 vnf_instance_id
6001 )
6002 )
6003
6004 # There is no change in the charm package, then redeploy the VNF
6005 # based on new descriptor
6006 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05306007 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00006008 (result, detailed_status) = await self._ns_redeploy_vnf(
6009 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05306010 )
6011 if result == "FAILED":
6012 nslcmop_operation_state = result
6013 error_description_nslcmop = detailed_status
6014 db_nslcmop_update["detailed-status"] = detailed_status
6015 self.logger.debug(
6016 logging_text
6017 + " step {} Done with result {} {}".format(
6018 step, nslcmop_operation_state, detailed_status
6019 )
6020 )
aticigdffa6212022-04-12 15:27:53 +03006021
6022 else:
6023 step = "Checking if any charm package has changed or not"
6024 for current_charm_path, target_charm_path in list(
6025 charm_artifact_paths
6026 ):
6027 if (
6028 current_charm_path
6029 and target_charm_path
6030 and self.check_charm_hash_changed(
6031 current_charm_path, target_charm_path
6032 )
6033 ):
6034
6035 step = "Checking whether VNF uses juju bundle"
6036 if check_juju_bundle_existence(current_vnfd):
6037
6038 raise LcmException(
6039 "Charm upgrade is not supported for the instance which"
6040 " uses juju-bundle: {}".format(
6041 check_juju_bundle_existence(current_vnfd)
6042 )
6043 )
6044
6045 step = "Upgrading Charm"
6046 (
6047 result,
6048 detailed_status,
6049 ) = await self._ns_charm_upgrade(
6050 ee_id=ee_id,
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006051 charm_id=vca_id,
6052 charm_type=vca_type,
aticigdffa6212022-04-12 15:27:53 +03006053 path=self.fs.path + target_charm_path,
6054 timeout=timeout_seconds,
6055 )
6056
6057 if result == "FAILED":
6058 nslcmop_operation_state = result
6059 error_description_nslcmop = detailed_status
6060
6061 db_nslcmop_update["detailed-status"] = detailed_status
6062 self.logger.debug(
6063 logging_text
6064 + " step {} Done with result {} {}".format(
6065 step, nslcmop_operation_state, detailed_status
6066 )
6067 )
6068
6069 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05306070 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6071 result = "COMPLETED"
6072 detailed_status = "Done"
6073 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03006074
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006075 # helm base EE
6076 for item in helm_artifacts:
garciadeblasfb1e25f2022-11-18 14:36:22 +01006077 if not (
6078 item["current_artifact_path"]
6079 and item["target_artifact_path"]
6080 and self.check_charm_hash_changed(
6081 item["current_artifact_path"],
6082 item["target_artifact_path"],
6083 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006084 ):
6085 continue
garciadeblasfb1e25f2022-11-18 14:36:22 +01006086 db_update_entry = "_admin.deployed.VCA.{}.".format(
6087 item["vca_index"]
6088 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006089 vnfr_id = db_vnfr["_id"]
6090 osm_config = {"osm": {"ns_id": nsr_id, "vnf_id": vnfr_id}}
6091 db_dict = {
6092 "collection": "nsrs",
6093 "filter": {"_id": nsr_id},
6094 "path": db_update_entry,
6095 }
6096 vca_type, namespace, helm_id = get_ee_id_parts(item["ee_id"])
garciadeblasfb1e25f2022-11-18 14:36:22 +01006097 await self.vca_map[vca_type].upgrade_execution_environment(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006098 namespace=namespace,
6099 helm_id=helm_id,
6100 db_dict=db_dict,
6101 config=osm_config,
6102 artifact_path=item["target_artifact_path"],
6103 vca_type=vca_type,
6104 )
6105 vnf_id = db_vnfr.get("vnfd-ref")
6106 config_descriptor = get_configuration(latest_vnfd, vnf_id)
6107 self.logger.debug("get ssh key block")
6108 rw_mgmt_ip = None
6109 if deep_get(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006110 config_descriptor,
6111 ("config-access", "ssh-access", "required"),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006112 ):
6113 # Needed to inject a ssh key
6114 user = deep_get(
6115 config_descriptor,
6116 ("config-access", "ssh-access", "default-user"),
6117 )
garciadeblasfb1e25f2022-11-18 14:36:22 +01006118 step = (
6119 "Install configuration Software, getting public ssh key"
6120 )
6121 pub_key = await self.vca_map[
6122 vca_type
6123 ].get_ee_ssh_public__key(
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006124 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
6125 )
6126
garciadeblasfb1e25f2022-11-18 14:36:22 +01006127 step = (
6128 "Insert public key into VM user={} ssh_key={}".format(
6129 user, pub_key
6130 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006131 )
6132 self.logger.debug(logging_text + step)
6133
6134 # wait for RO (ip-address) Insert pub_key into VM
6135 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
6136 logging_text,
6137 nsr_id,
6138 vnfr_id,
6139 None,
6140 item["vdu_index"],
6141 user=user,
6142 pub_key=pub_key,
6143 )
6144
6145 initial_config_primitive_list = config_descriptor.get(
6146 "initial-config-primitive"
6147 )
6148 config_primitive = next(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006149 (
6150 p
6151 for p in initial_config_primitive_list
6152 if p["name"] == "config"
6153 ),
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006154 None,
6155 )
6156 if not config_primitive:
6157 continue
6158
6159 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6160 if rw_mgmt_ip:
6161 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
6162 if db_vnfr.get("additionalParamsForVnf"):
6163 deploy_params.update(
garciadeblasfb1e25f2022-11-18 14:36:22 +01006164 parse_yaml_strings(
6165 db_vnfr["additionalParamsForVnf"].copy()
6166 )
Gabriel Cubae539a8d2022-10-10 11:34:51 -05006167 )
6168 primitive_params_ = self._map_primitive_params(
6169 config_primitive, {}, deploy_params
6170 )
6171
6172 step = "execute primitive '{}' params '{}'".format(
6173 config_primitive["name"], primitive_params_
6174 )
6175 self.logger.debug(logging_text + step)
6176 await self.vca_map[vca_type].exec_primitive(
6177 ee_id=ee_id,
6178 primitive_name=config_primitive["name"],
6179 params_dict=primitive_params_,
6180 db_dict=db_dict,
6181 vca_id=vca_id,
6182 vca_type=vca_type,
6183 )
6184
6185 step = "Updating policies"
6186 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6187 detailed_status = "Done"
6188 db_nslcmop_update["detailed-status"] = "Done"
6189
aticigdffa6212022-04-12 15:27:53 +03006190 # If nslcmop_operation_state is None, so any operation is not failed.
6191 if not nslcmop_operation_state:
6192 nslcmop_operation_state = "COMPLETED"
6193
6194 # If update CHANGE_VNFPKG nslcmop_operation is successful
6195 # vnf revision need to be updated
6196 vnfr_update["revision"] = latest_vnfd_revision
6197 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
6198
6199 self.logger.debug(
6200 logging_text
6201 + " task Done with result {} {}".format(
6202 nslcmop_operation_state, detailed_status
6203 )
6204 )
6205 elif update_type == "REMOVE_VNF":
6206 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05306207 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
6208 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
6209 member_vnf_index = db_vnfr["member-vnf-index-ref"]
6210 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00006211 (result, detailed_status) = await self.remove_vnf(
6212 nsr_id, nslcmop_id, vnf_instance_id
6213 )
elumalaica7ece02022-04-12 12:47:32 +05306214 if result == "FAILED":
6215 nslcmop_operation_state = result
6216 error_description_nslcmop = detailed_status
6217 db_nslcmop_update["detailed-status"] = detailed_status
6218 change_type = "vnf_terminated"
6219 if not nslcmop_operation_state:
6220 nslcmop_operation_state = "COMPLETED"
6221 self.logger.debug(
6222 logging_text
6223 + " task Done with result {} {}".format(
6224 nslcmop_operation_state, detailed_status
6225 )
6226 )
aticigdffa6212022-04-12 15:27:53 +03006227
k4.rahulb827de92022-05-02 16:35:02 +00006228 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006229 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6230 "vnfInstanceId"
6231 ]
6232 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6233 "changeStateTo"
6234 ]
6235 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6236 "additionalParam"
6237 ]
k4.rahulb827de92022-05-02 16:35:02 +00006238 (result, detailed_status) = await self.rebuild_start_stop(
6239 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006240 )
k4.rahulb827de92022-05-02 16:35:02 +00006241 if result == "FAILED":
6242 nslcmop_operation_state = result
6243 error_description_nslcmop = detailed_status
6244 db_nslcmop_update["detailed-status"] = detailed_status
6245 if not nslcmop_operation_state:
6246 nslcmop_operation_state = "COMPLETED"
6247 self.logger.debug(
6248 logging_text
6249 + " task Done with result {} {}".format(
6250 nslcmop_operation_state, detailed_status
6251 )
6252 )
6253
aticigdffa6212022-04-12 15:27:53 +03006254 # If nslcmop_operation_state is None, so any operation is not failed.
6255 # All operations are executed in overall.
6256 if not nslcmop_operation_state:
6257 nslcmop_operation_state = "COMPLETED"
6258 db_nsr_update["operational-status"] = old_operational_status
6259
6260 except (DbException, LcmException, N2VCException, K8sException) as e:
6261 self.logger.error(logging_text + "Exit Exception {}".format(e))
6262 exc = e
6263 except asyncio.CancelledError:
6264 self.logger.error(
6265 logging_text + "Cancelled Exception while '{}'".format(step)
6266 )
6267 exc = "Operation was cancelled"
6268 except asyncio.TimeoutError:
6269 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6270 exc = "Timeout"
6271 except Exception as e:
6272 exc = traceback.format_exc()
6273 self.logger.critical(
6274 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6275 exc_info=True,
6276 )
6277 finally:
6278 if exc:
6279 db_nslcmop_update[
6280 "detailed-status"
6281 ] = (
6282 detailed_status
6283 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6284 nslcmop_operation_state = "FAILED"
6285 db_nsr_update["operational-status"] = old_operational_status
6286 if db_nsr:
6287 self._write_ns_status(
6288 nsr_id=nsr_id,
6289 ns_state=db_nsr["nsState"],
6290 current_operation="IDLE",
6291 current_operation_id=None,
6292 other_update=db_nsr_update,
6293 )
6294
6295 self._write_op_status(
6296 op_id=nslcmop_id,
6297 stage="",
6298 error_message=error_description_nslcmop,
6299 operation_state=nslcmop_operation_state,
6300 other_update=db_nslcmop_update,
6301 )
6302
6303 if nslcmop_operation_state:
6304 try:
elumalaica7ece02022-04-12 12:47:32 +05306305 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306306 "nsr_id": nsr_id,
6307 "nslcmop_id": nslcmop_id,
6308 "operationState": nslcmop_operation_state,
6309 }
6310 if change_type in ("vnf_terminated", "policy_updated"):
elumalaica7ece02022-04-12 12:47:32 +05306311 msg.update({"vnf_member_index": member_vnf_index})
6312 await self.msg.aiowrite("ns", change_type, msg, loop=self.loop)
aticigdffa6212022-04-12 15:27:53 +03006313 except Exception as e:
6314 self.logger.error(
6315 logging_text + "kafka_write notification Exception {}".format(e)
6316 )
6317 self.logger.debug(logging_text + "Exit")
6318 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6319 return nslcmop_operation_state, detailed_status
6320
tierno59d22d22018-09-25 18:10:19 +02006321 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006322 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006323 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006324 if not task_is_locked_by_me:
6325 return
6326
tierno59d22d22018-09-25 18:10:19 +02006327 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006328 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006329 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006330 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006331 self.logger.debug(logging_text + "Enter")
6332 # get all needed from database
6333 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006334 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006335 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006336 exc = None
tierno9ab95942018-10-10 16:44:22 +02006337 # in case of error, indicates what part of scale was failed to put nsr at error status
6338 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006339 old_operational_status = ""
6340 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006341 nsi_id = None
tierno59d22d22018-09-25 18:10:19 +02006342 try:
kuused124bfe2019-06-18 12:09:24 +02006343 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006344 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006345 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6346 self._write_ns_status(
6347 nsr_id=nsr_id,
6348 ns_state=None,
6349 current_operation="SCALING",
6350 current_operation_id=nslcmop_id,
6351 )
quilesj4cda56b2019-12-05 10:02:20 +00006352
ikalyvas02d9e7b2019-05-27 18:16:01 +03006353 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006354 self.logger.debug(
6355 step + " after having waited for previous tasks to be completed"
6356 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006357 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006358
ikalyvas02d9e7b2019-05-27 18:16:01 +03006359 step = "Getting nsr from database"
6360 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006361 old_operational_status = db_nsr["operational-status"]
6362 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006363
tierno59d22d22018-09-25 18:10:19 +02006364 step = "Parsing scaling parameters"
6365 db_nsr_update["operational-status"] = "scaling"
6366 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006367 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006368
garciadeblas5697b8b2021-03-24 09:17:02 +01006369 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6370 "scaleByStepData"
6371 ]["member-vnf-index"]
6372 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6373 "scaleByStepData"
6374 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006375 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006376 # for backward compatibility
6377 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6378 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6379 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6380 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6381
tierno59d22d22018-09-25 18:10:19 +02006382 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006383 db_vnfr = self.db.get_one(
6384 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6385 )
bravof922c4172020-11-24 21:21:43 -03006386
David Garciac1fe90a2021-03-31 19:12:02 +02006387 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6388
tierno59d22d22018-09-25 18:10:19 +02006389 step = "Getting vnfd from database"
6390 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006391
aktas13251562021-02-12 22:19:10 +03006392 base_folder = db_vnfd["_admin"]["storage"]
6393
tierno59d22d22018-09-25 18:10:19 +02006394 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006395 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006396 get_scaling_aspect(db_vnfd),
6397 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006398 )
6399 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006400 raise LcmException(
6401 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6402 "at vnfd:scaling-group-descriptor".format(scaling_group)
6403 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006404
tierno15b1cf12019-08-29 13:21:40 +00006405 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006406 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006407 nb_scale_op = 0
6408 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006409 self.update_db_2(
6410 "nsrs",
6411 nsr_id,
6412 {
6413 "_admin.scaling-group": [
6414 {"name": scaling_group, "nb-scale-op": 0}
6415 ]
6416 },
6417 )
tierno59d22d22018-09-25 18:10:19 +02006418 admin_scale_index = 0
6419 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006420 for admin_scale_index, admin_scale_info in enumerate(
6421 db_nsr["_admin"]["scaling-group"]
6422 ):
tierno59d22d22018-09-25 18:10:19 +02006423 if admin_scale_info["name"] == scaling_group:
6424 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6425 break
tierno9ab95942018-10-10 16:44:22 +02006426 else: # not found, set index one plus last element and add new entry with the name
6427 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006428 db_nsr_update[
6429 "_admin.scaling-group.{}.name".format(admin_scale_index)
6430 ] = scaling_group
aktas5f75f102021-03-15 11:26:10 +03006431
6432 vca_scaling_info = []
6433 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006434 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006435 if "aspect-delta-details" not in scaling_descriptor:
6436 raise LcmException(
6437 "Aspect delta details not fount in scaling descriptor {}".format(
6438 scaling_descriptor["name"]
6439 )
6440 )
tierno59d22d22018-09-25 18:10:19 +02006441 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006442 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006443
aktas5f75f102021-03-15 11:26:10 +03006444 scaling_info["scaling_direction"] = "OUT"
6445 scaling_info["vdu-create"] = {}
6446 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006447 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006448 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006449 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006450 # vdu_index also provides the number of instance of the targeted vdu
6451 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
garciadeblas5697b8b2021-03-24 09:17:02 +01006452 cloud_init_text = self._get_vdu_cloud_init_content(
6453 vdud, db_vnfd
6454 )
tierno72ef84f2020-10-06 08:22:07 +00006455 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006456 additional_params = (
6457 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6458 or {}
6459 )
bravof832f8992020-12-07 12:57:31 -03006460 cloud_init_list = []
6461
6462 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6463 max_instance_count = 10
6464 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006465 max_instance_count = vdu_profile.get(
6466 "max-number-of-instances", 10
6467 )
6468
6469 default_instance_num = get_number_of_instances(
6470 db_vnfd, vdud["id"]
6471 )
aktas5f75f102021-03-15 11:26:10 +03006472 instances_number = vdu_delta.get("number-of-instances", 1)
6473 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006474
aktas5f75f102021-03-15 11:26:10 +03006475 new_instance_count = nb_scale_op + default_instance_num
6476 # Control if new count is over max and vdu count is less than max.
6477 # Then assign new instance count
6478 if new_instance_count > max_instance_count > vdu_count:
6479 instances_number = new_instance_count - max_instance_count
6480 else:
6481 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006482
aktas5f75f102021-03-15 11:26:10 +03006483 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006484 raise LcmException(
6485 "reached the limit of {} (max-instance-count) "
6486 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006487 "scaling-group-descriptor '{}'".format(
6488 nb_scale_op, scaling_group
6489 )
bravof922c4172020-11-24 21:21:43 -03006490 )
bravof832f8992020-12-07 12:57:31 -03006491 for x in range(vdu_delta.get("number-of-instances", 1)):
6492 if cloud_init_text:
6493 # TODO Information of its own ip is not available because db_vnfr is not updated.
6494 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006495 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006496 )
bravof832f8992020-12-07 12:57:31 -03006497 cloud_init_list.append(
6498 self._parse_cloud_init(
6499 cloud_init_text,
6500 additional_params,
6501 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006502 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006503 )
6504 )
aktas5f75f102021-03-15 11:26:10 +03006505 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006506 {
6507 "osm_vdu_id": vdu_delta["id"],
6508 "member-vnf-index": vnf_index,
6509 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006510 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006511 }
6512 )
aktas5f75f102021-03-15 11:26:10 +03006513 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6514 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006515 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006516 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006517 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006518
6519 # Might have different kdus in the same delta
6520 # Should have list for each kdu
6521 if not scaling_info["kdu-create"].get(kdu_name, None):
6522 scaling_info["kdu-create"][kdu_name] = []
6523
6524 kdur = get_kdur(db_vnfr, kdu_name)
6525 if kdur.get("helm-chart"):
6526 k8s_cluster_type = "helm-chart-v3"
6527 self.logger.debug("kdur: {}".format(kdur))
6528 if (
6529 kdur.get("helm-version")
6530 and kdur.get("helm-version") == "v2"
6531 ):
6532 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006533 elif kdur.get("juju-bundle"):
6534 k8s_cluster_type = "juju-bundle"
6535 else:
6536 raise LcmException(
6537 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6538 "juju-bundle. Maybe an old NBI version is running".format(
6539 db_vnfr["member-vnf-index-ref"], kdu_name
6540 )
6541 )
6542
6543 max_instance_count = 10
6544 if kdu_profile and "max-number-of-instances" in kdu_profile:
6545 max_instance_count = kdu_profile.get(
6546 "max-number-of-instances", 10
6547 )
6548
6549 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6550 deployed_kdu, _ = get_deployed_kdu(
6551 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006552 )
aktas5f75f102021-03-15 11:26:10 +03006553 if deployed_kdu is None:
6554 raise LcmException(
6555 "KDU '{}' for vnf '{}' not deployed".format(
6556 kdu_name, vnf_index
6557 )
6558 )
6559 kdu_instance = deployed_kdu.get("kdu-instance")
6560 instance_num = await self.k8scluster_map[
6561 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006562 ].get_scale_count(
6563 resource_name,
6564 kdu_instance,
6565 vca_id=vca_id,
6566 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6567 kdu_model=deployed_kdu.get("kdu-model"),
6568 )
aktas5f75f102021-03-15 11:26:10 +03006569 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006570 "number-of-instances", 1
6571 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006572
aktas5f75f102021-03-15 11:26:10 +03006573 # Control if new count is over max and instance_num is less than max.
6574 # Then assign max instance number to kdu replica count
6575 if kdu_replica_count > max_instance_count > instance_num:
6576 kdu_replica_count = max_instance_count
6577 if kdu_replica_count > max_instance_count:
6578 raise LcmException(
6579 "reached the limit of {} (max-instance-count) "
6580 "scaling-out operations for the "
6581 "scaling-group-descriptor '{}'".format(
6582 instance_num, scaling_group
6583 )
6584 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006585
aktas5f75f102021-03-15 11:26:10 +03006586 for x in range(kdu_delta.get("number-of-instances", 1)):
6587 vca_scaling_info.append(
6588 {
6589 "osm_kdu_id": kdu_name,
6590 "member-vnf-index": vnf_index,
6591 "type": "create",
6592 "kdu_index": instance_num + x - 1,
6593 }
6594 )
6595 scaling_info["kdu-create"][kdu_name].append(
6596 {
6597 "member-vnf-index": vnf_index,
6598 "type": "create",
6599 "k8s-cluster-type": k8s_cluster_type,
6600 "resource-name": resource_name,
6601 "scale": kdu_replica_count,
6602 }
6603 )
6604 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006605 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006606
6607 scaling_info["scaling_direction"] = "IN"
6608 scaling_info["vdu-delete"] = {}
6609 scaling_info["kdu-delete"] = {}
6610
bravof832f8992020-12-07 12:57:31 -03006611 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006612 for vdu_delta in delta.get("vdu-delta", {}):
6613 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006614 min_instance_count = 0
6615 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6616 if vdu_profile and "min-number-of-instances" in vdu_profile:
6617 min_instance_count = vdu_profile["min-number-of-instances"]
6618
garciadeblas5697b8b2021-03-24 09:17:02 +01006619 default_instance_num = get_number_of_instances(
6620 db_vnfd, vdu_delta["id"]
6621 )
aktas5f75f102021-03-15 11:26:10 +03006622 instance_num = vdu_delta.get("number-of-instances", 1)
6623 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006624
aktas5f75f102021-03-15 11:26:10 +03006625 new_instance_count = nb_scale_op + default_instance_num
6626
6627 if new_instance_count < min_instance_count < vdu_count:
6628 instances_number = min_instance_count - new_instance_count
6629 else:
6630 instances_number = instance_num
6631
6632 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006633 raise LcmException(
6634 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006635 "scaling-group-descriptor '{}'".format(
6636 nb_scale_op, scaling_group
6637 )
bravof832f8992020-12-07 12:57:31 -03006638 )
aktas13251562021-02-12 22:19:10 +03006639 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006640 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006641 {
6642 "osm_vdu_id": vdu_delta["id"],
6643 "member-vnf-index": vnf_index,
6644 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006645 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006646 }
6647 )
aktas5f75f102021-03-15 11:26:10 +03006648 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6649 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006650 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006651 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006652 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006653
6654 if not scaling_info["kdu-delete"].get(kdu_name, None):
6655 scaling_info["kdu-delete"][kdu_name] = []
6656
6657 kdur = get_kdur(db_vnfr, kdu_name)
6658 if kdur.get("helm-chart"):
6659 k8s_cluster_type = "helm-chart-v3"
6660 self.logger.debug("kdur: {}".format(kdur))
6661 if (
6662 kdur.get("helm-version")
6663 and kdur.get("helm-version") == "v2"
6664 ):
6665 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006666 elif kdur.get("juju-bundle"):
6667 k8s_cluster_type = "juju-bundle"
6668 else:
6669 raise LcmException(
6670 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6671 "juju-bundle. Maybe an old NBI version is running".format(
6672 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6673 )
6674 )
6675
6676 min_instance_count = 0
6677 if kdu_profile and "min-number-of-instances" in kdu_profile:
6678 min_instance_count = kdu_profile["min-number-of-instances"]
6679
6680 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6681 deployed_kdu, _ = get_deployed_kdu(
6682 nsr_deployed, kdu_name, vnf_index
6683 )
6684 if deployed_kdu is None:
6685 raise LcmException(
6686 "KDU '{}' for vnf '{}' not deployed".format(
6687 kdu_name, vnf_index
6688 )
6689 )
6690 kdu_instance = deployed_kdu.get("kdu-instance")
6691 instance_num = await self.k8scluster_map[
6692 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006693 ].get_scale_count(
6694 resource_name,
6695 kdu_instance,
6696 vca_id=vca_id,
6697 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6698 kdu_model=deployed_kdu.get("kdu-model"),
6699 )
aktas5f75f102021-03-15 11:26:10 +03006700 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006701 "number-of-instances", 1
6702 )
tierno59d22d22018-09-25 18:10:19 +02006703
aktas5f75f102021-03-15 11:26:10 +03006704 if kdu_replica_count < min_instance_count < instance_num:
6705 kdu_replica_count = min_instance_count
6706 if kdu_replica_count < min_instance_count:
6707 raise LcmException(
6708 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6709 "scaling-group-descriptor '{}'".format(
6710 instance_num, scaling_group
6711 )
6712 )
6713
6714 for x in range(kdu_delta.get("number-of-instances", 1)):
6715 vca_scaling_info.append(
6716 {
6717 "osm_kdu_id": kdu_name,
6718 "member-vnf-index": vnf_index,
6719 "type": "delete",
6720 "kdu_index": instance_num - x - 1,
6721 }
6722 )
6723 scaling_info["kdu-delete"][kdu_name].append(
6724 {
6725 "member-vnf-index": vnf_index,
6726 "type": "delete",
6727 "k8s-cluster-type": k8s_cluster_type,
6728 "resource-name": resource_name,
6729 "scale": kdu_replica_count,
6730 }
6731 )
6732
tierno59d22d22018-09-25 18:10:19 +02006733 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006734 vdu_delete = copy(scaling_info.get("vdu-delete"))
6735 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006736 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006737 if vdu_delete.get(vdur["vdu-id-ref"]):
6738 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006739 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006740 {
6741 "name": vdur.get("name") or vdur.get("vdu-name"),
6742 "vdu_id": vdur["vdu-id-ref"],
6743 "interface": [],
6744 }
6745 )
tierno59d22d22018-09-25 18:10:19 +02006746 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006747 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006748 {
6749 "name": interface["name"],
6750 "ip_address": interface["ip-address"],
6751 "mac_address": interface.get("mac-address"),
6752 }
6753 )
tierno2357f4e2020-10-19 16:38:59 +00006754 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006755
kuuseac3a8882019-10-03 10:48:06 +02006756 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006757 step = "Executing pre-scale vnf-config-primitive"
6758 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006759 for scaling_config_action in scaling_descriptor[
6760 "scaling-config-action"
6761 ]:
6762 if (
6763 scaling_config_action.get("trigger") == "pre-scale-in"
6764 and scaling_type == "SCALE_IN"
6765 ) or (
6766 scaling_config_action.get("trigger") == "pre-scale-out"
6767 and scaling_type == "SCALE_OUT"
6768 ):
6769 vnf_config_primitive = scaling_config_action[
6770 "vnf-config-primitive-name-ref"
6771 ]
6772 step = db_nslcmop_update[
6773 "detailed-status"
6774 ] = "executing pre-scale scaling-config-action '{}'".format(
6775 vnf_config_primitive
6776 )
tiernoda964822019-01-14 15:53:47 +00006777
tierno59d22d22018-09-25 18:10:19 +02006778 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006779 for config_primitive in (
6780 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6781 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006782 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006783 break
6784 else:
6785 raise LcmException(
6786 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006787 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006788 "primitive".format(scaling_group, vnf_config_primitive)
6789 )
tiernoda964822019-01-14 15:53:47 +00006790
aktas5f75f102021-03-15 11:26:10 +03006791 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006792 if db_vnfr.get("additionalParamsForVnf"):
6793 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006794
tierno9ab95942018-10-10 16:44:22 +02006795 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006796 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006797 primitive_params = self._map_primitive_params(
6798 config_primitive, {}, vnfr_params
6799 )
kuuseac3a8882019-10-03 10:48:06 +02006800
tierno7c4e24c2020-05-13 08:41:35 +00006801 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006802 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006803 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006804 vnf_index,
6805 vnf_config_primitive,
6806 primitive_params,
6807 "PRE-SCALE",
6808 )
tierno7c4e24c2020-05-13 08:41:35 +00006809 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006810 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006811 result = "COMPLETED"
6812 result_detail = "Done"
6813 self.logger.debug(
6814 logging_text
6815 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6816 vnf_config_primitive, result, result_detail
6817 )
6818 )
kuuseac3a8882019-10-03 10:48:06 +02006819 else:
tierno7c4e24c2020-05-13 08:41:35 +00006820 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006821 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006822 op_index = (
6823 len(db_nslcmop.get("_admin", {}).get("operations"))
6824 - 1
6825 )
6826 self.logger.debug(
6827 logging_text
6828 + "vnf_config_primitive={} New sub-operation".format(
6829 vnf_config_primitive
6830 )
6831 )
kuuseac3a8882019-10-03 10:48:06 +02006832 else:
tierno7c4e24c2020-05-13 08:41:35 +00006833 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006834 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6835 op_index
6836 ]
6837 vnf_index = op.get("member_vnf_index")
6838 vnf_config_primitive = op.get("primitive")
6839 primitive_params = op.get("primitive_params")
6840 self.logger.debug(
6841 logging_text
6842 + "vnf_config_primitive={} Sub-operation retry".format(
6843 vnf_config_primitive
6844 )
6845 )
tierno588547c2020-07-01 15:30:20 +00006846 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006847 ee_descriptor_id = config_primitive.get(
6848 "execution-environment-ref"
6849 )
6850 primitive_name = config_primitive.get(
6851 "execution-environment-primitive", vnf_config_primitive
6852 )
6853 ee_id, vca_type = self._look_for_deployed_vca(
6854 nsr_deployed["VCA"],
6855 member_vnf_index=vnf_index,
6856 vdu_id=None,
6857 vdu_count_index=None,
6858 ee_descriptor_id=ee_descriptor_id,
6859 )
kuuseac3a8882019-10-03 10:48:06 +02006860 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006861 ee_id,
6862 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006863 primitive_params,
6864 vca_type=vca_type,
6865 vca_id=vca_id,
6866 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006867 self.logger.debug(
6868 logging_text
6869 + "vnf_config_primitive={} Done with result {} {}".format(
6870 vnf_config_primitive, result, result_detail
6871 )
6872 )
kuuseac3a8882019-10-03 10:48:06 +02006873 # Update operationState = COMPLETED | FAILED
6874 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006875 db_nslcmop, op_index, result, result_detail
6876 )
kuuseac3a8882019-10-03 10:48:06 +02006877
tierno59d22d22018-09-25 18:10:19 +02006878 if result == "FAILED":
6879 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006880 db_nsr_update["config-status"] = old_config_status
6881 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006882 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006883
garciadeblas5697b8b2021-03-24 09:17:02 +01006884 db_nsr_update[
6885 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6886 ] = nb_scale_op
6887 db_nsr_update[
6888 "_admin.scaling-group.{}.time".format(admin_scale_index)
6889 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006890
aktas13251562021-02-12 22:19:10 +03006891 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006892 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006893 step = db_nslcmop_update[
6894 "detailed-status"
6895 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03006896 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006897 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006898 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006899 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01006900 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03006901 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01006902 )
aktas5f75f102021-03-15 11:26:10 +03006903 if vca_info.get("osm_vdu_id"):
6904 vdu_id = vca_info["osm_vdu_id"]
6905 vdu_index = int(vca_info["vdu_index"])
6906 stage[
6907 1
6908 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
6909 member_vnf_index, vdu_id, vdu_index
6910 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006911 stage[2] = step = "Scaling in VCA"
6912 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03006913 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
6914 config_update = db_nsr["configurationStatus"]
6915 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01006916 if (
6917 (vca or vca.get("ee_id"))
6918 and vca["member-vnf-index"] == member_vnf_index
6919 and vca["vdu_count_index"] == vdu_index
6920 ):
aktas13251562021-02-12 22:19:10 +03006921 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006922 config_descriptor = get_configuration(
6923 db_vnfd, vca.get("vdu_id")
6924 )
aktas13251562021-02-12 22:19:10 +03006925 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006926 config_descriptor = get_configuration(
6927 db_vnfd, vca.get("kdu_name")
6928 )
aktas13251562021-02-12 22:19:10 +03006929 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006930 config_descriptor = get_configuration(
6931 db_vnfd, db_vnfd["id"]
6932 )
6933 operation_params = (
6934 db_nslcmop.get("operationParams") or {}
6935 )
6936 exec_terminate_primitives = not operation_params.get(
6937 "skip_terminate_primitives"
6938 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02006939 task = asyncio.ensure_future(
6940 asyncio.wait_for(
6941 self.destroy_N2VC(
6942 logging_text,
6943 db_nslcmop,
6944 vca,
6945 config_descriptor,
6946 vca_index,
6947 destroy_ee=True,
6948 exec_primitives=exec_terminate_primitives,
6949 scaling_in=True,
6950 vca_id=vca_id,
6951 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01006952 timeout=self.timeout_charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02006953 )
6954 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006955 tasks_dict_info[task] = "Terminating VCA {}".format(
6956 vca.get("ee_id")
6957 )
aktas13251562021-02-12 22:19:10 +03006958 del vca_update[vca_index]
6959 del config_update[vca_index]
6960 # wait for pending tasks of terminate primitives
6961 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006962 self.logger.debug(
6963 logging_text
6964 + "Waiting for tasks {}".format(
6965 list(tasks_dict_info.keys())
6966 )
6967 )
6968 error_list = await self._wait_for_tasks(
6969 logging_text,
6970 tasks_dict_info,
6971 min(
6972 self.timeout_charm_delete, self.timeout_ns_terminate
6973 ),
6974 stage,
6975 nslcmop_id,
6976 )
aktas13251562021-02-12 22:19:10 +03006977 tasks_dict_info.clear()
6978 if error_list:
6979 raise LcmException("; ".join(error_list))
6980
6981 db_vca_and_config_update = {
6982 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01006983 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03006984 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006985 self.update_db_2(
6986 "nsrs", db_nsr["_id"], db_vca_and_config_update
6987 )
aktas13251562021-02-12 22:19:10 +03006988 scale_process = None
6989 # SCALE-IN VCA - END
6990
kuuseac3a8882019-10-03 10:48:06 +02006991 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006992 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02006993 scale_process = "RO"
tierno2357f4e2020-10-19 16:38:59 +00006994 if self.ro_config.get("ng"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006995 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03006996 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01006997 )
aktas5f75f102021-03-15 11:26:10 +03006998 scaling_info.pop("vdu-create", None)
6999 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02007000
tierno9ab95942018-10-10 16:44:22 +02007001 scale_process = None
aktas13251562021-02-12 22:19:10 +03007002 # SCALE RO - END
7003
aktas5f75f102021-03-15 11:26:10 +03007004 # SCALE KDU - BEGIN
7005 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
7006 scale_process = "KDU"
7007 await self._scale_kdu(
7008 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7009 )
7010 scaling_info.pop("kdu-create", None)
7011 scaling_info.pop("kdu-delete", None)
7012
7013 scale_process = None
7014 # SCALE KDU - END
7015
7016 if db_nsr_update:
7017 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7018
aktas13251562021-02-12 22:19:10 +03007019 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03007020 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01007021 step = db_nslcmop_update[
7022 "detailed-status"
7023 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03007024 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03007025 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01007026 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03007027 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01007028 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03007029 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01007030 )
aktas13251562021-02-12 22:19:10 +03007031 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03007032 if vca_info.get("osm_vdu_id"):
7033 vdu_index = int(vca_info["vdu_index"])
7034 deploy_params = {"OSM": get_osm_params(db_vnfr)}
7035 if db_vnfr.get("additionalParamsForVnf"):
7036 deploy_params.update(
7037 parse_yaml_strings(
7038 db_vnfr["additionalParamsForVnf"].copy()
7039 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007040 )
aktas5f75f102021-03-15 11:26:10 +03007041 descriptor_config = get_configuration(
7042 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01007043 )
aktas5f75f102021-03-15 11:26:10 +03007044 if descriptor_config:
7045 vdu_id = None
7046 vdu_name = None
7047 kdu_name = None
7048 self._deploy_n2vc(
7049 logging_text=logging_text
7050 + "member_vnf_index={} ".format(member_vnf_index),
7051 db_nsr=db_nsr,
7052 db_vnfr=db_vnfr,
7053 nslcmop_id=nslcmop_id,
7054 nsr_id=nsr_id,
7055 nsi_id=nsi_id,
7056 vnfd_id=vnfd_id,
7057 vdu_id=vdu_id,
7058 kdu_name=kdu_name,
7059 member_vnf_index=member_vnf_index,
7060 vdu_index=vdu_index,
7061 vdu_name=vdu_name,
7062 deploy_params=deploy_params,
7063 descriptor_config=descriptor_config,
7064 base_folder=base_folder,
7065 task_instantiation_info=tasks_dict_info,
7066 stage=stage,
7067 )
7068 vdu_id = vca_info["osm_vdu_id"]
7069 vdur = find_in_list(
7070 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03007071 )
aktas5f75f102021-03-15 11:26:10 +03007072 descriptor_config = get_configuration(db_vnfd, vdu_id)
7073 if vdur.get("additionalParams"):
7074 deploy_params_vdu = parse_yaml_strings(
7075 vdur["additionalParams"]
7076 )
7077 else:
7078 deploy_params_vdu = deploy_params
7079 deploy_params_vdu["OSM"] = get_osm_params(
7080 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01007081 )
aktas5f75f102021-03-15 11:26:10 +03007082 if descriptor_config:
7083 vdu_name = None
7084 kdu_name = None
7085 stage[
7086 1
7087 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01007088 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03007089 )
7090 stage[2] = step = "Scaling out VCA"
7091 self._write_op_status(op_id=nslcmop_id, stage=stage)
7092 self._deploy_n2vc(
7093 logging_text=logging_text
7094 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
7095 member_vnf_index, vdu_id, vdu_index
7096 ),
7097 db_nsr=db_nsr,
7098 db_vnfr=db_vnfr,
7099 nslcmop_id=nslcmop_id,
7100 nsr_id=nsr_id,
7101 nsi_id=nsi_id,
7102 vnfd_id=vnfd_id,
7103 vdu_id=vdu_id,
7104 kdu_name=kdu_name,
7105 member_vnf_index=member_vnf_index,
7106 vdu_index=vdu_index,
7107 vdu_name=vdu_name,
7108 deploy_params=deploy_params_vdu,
7109 descriptor_config=descriptor_config,
7110 base_folder=base_folder,
7111 task_instantiation_info=tasks_dict_info,
7112 stage=stage,
7113 )
aktas13251562021-02-12 22:19:10 +03007114 # SCALE-UP VCA - END
7115 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02007116
kuuseac3a8882019-10-03 10:48:06 +02007117 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02007118 # execute primitive service POST-SCALING
7119 step = "Executing post-scale vnf-config-primitive"
7120 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007121 for scaling_config_action in scaling_descriptor[
7122 "scaling-config-action"
7123 ]:
7124 if (
7125 scaling_config_action.get("trigger") == "post-scale-in"
7126 and scaling_type == "SCALE_IN"
7127 ) or (
7128 scaling_config_action.get("trigger") == "post-scale-out"
7129 and scaling_type == "SCALE_OUT"
7130 ):
7131 vnf_config_primitive = scaling_config_action[
7132 "vnf-config-primitive-name-ref"
7133 ]
7134 step = db_nslcmop_update[
7135 "detailed-status"
7136 ] = "executing post-scale scaling-config-action '{}'".format(
7137 vnf_config_primitive
7138 )
tiernoda964822019-01-14 15:53:47 +00007139
aktas5f75f102021-03-15 11:26:10 +03007140 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00007141 if db_vnfr.get("additionalParamsForVnf"):
7142 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
7143
tierno59d22d22018-09-25 18:10:19 +02007144 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03007145 for config_primitive in (
7146 get_configuration(db_vnfd, db_vnfd["id"]) or {}
7147 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02007148 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02007149 break
7150 else:
tiernoa278b842020-07-08 15:33:55 +00007151 raise LcmException(
7152 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
7153 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01007154 "config-primitive".format(
7155 scaling_group, vnf_config_primitive
7156 )
7157 )
tierno9ab95942018-10-10 16:44:22 +02007158 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02007159 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01007160 primitive_params = self._map_primitive_params(
7161 config_primitive, {}, vnfr_params
7162 )
tiernod6de1992018-10-11 13:05:52 +02007163
tierno7c4e24c2020-05-13 08:41:35 +00007164 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02007165 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01007166 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01007167 vnf_index,
7168 vnf_config_primitive,
7169 primitive_params,
7170 "POST-SCALE",
7171 )
quilesj4cda56b2019-12-05 10:02:20 +00007172 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02007173 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007174 result = "COMPLETED"
7175 result_detail = "Done"
7176 self.logger.debug(
7177 logging_text
7178 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
7179 vnf_config_primitive, result, result_detail
7180 )
7181 )
kuuseac3a8882019-10-03 10:48:06 +02007182 else:
quilesj4cda56b2019-12-05 10:02:20 +00007183 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02007184 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007185 op_index = (
7186 len(db_nslcmop.get("_admin", {}).get("operations"))
7187 - 1
7188 )
7189 self.logger.debug(
7190 logging_text
7191 + "vnf_config_primitive={} New sub-operation".format(
7192 vnf_config_primitive
7193 )
7194 )
kuuseac3a8882019-10-03 10:48:06 +02007195 else:
tierno7c4e24c2020-05-13 08:41:35 +00007196 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01007197 op = db_nslcmop.get("_admin", {}).get("operations", [])[
7198 op_index
7199 ]
7200 vnf_index = op.get("member_vnf_index")
7201 vnf_config_primitive = op.get("primitive")
7202 primitive_params = op.get("primitive_params")
7203 self.logger.debug(
7204 logging_text
7205 + "vnf_config_primitive={} Sub-operation retry".format(
7206 vnf_config_primitive
7207 )
7208 )
tierno588547c2020-07-01 15:30:20 +00007209 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01007210 ee_descriptor_id = config_primitive.get(
7211 "execution-environment-ref"
7212 )
7213 primitive_name = config_primitive.get(
7214 "execution-environment-primitive", vnf_config_primitive
7215 )
7216 ee_id, vca_type = self._look_for_deployed_vca(
7217 nsr_deployed["VCA"],
7218 member_vnf_index=vnf_index,
7219 vdu_id=None,
7220 vdu_count_index=None,
7221 ee_descriptor_id=ee_descriptor_id,
7222 )
kuuseac3a8882019-10-03 10:48:06 +02007223 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007224 ee_id,
7225 primitive_name,
7226 primitive_params,
7227 vca_type=vca_type,
7228 vca_id=vca_id,
7229 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007230 self.logger.debug(
7231 logging_text
7232 + "vnf_config_primitive={} Done with result {} {}".format(
7233 vnf_config_primitive, result, result_detail
7234 )
7235 )
kuuseac3a8882019-10-03 10:48:06 +02007236 # Update operationState = COMPLETED | FAILED
7237 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007238 db_nslcmop, op_index, result, result_detail
7239 )
kuuseac3a8882019-10-03 10:48:06 +02007240
tierno59d22d22018-09-25 18:10:19 +02007241 if result == "FAILED":
7242 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007243 db_nsr_update["config-status"] = old_config_status
7244 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007245 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007246
garciadeblas5697b8b2021-03-24 09:17:02 +01007247 db_nsr_update[
7248 "detailed-status"
7249 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7250 db_nsr_update["operational-status"] = (
7251 "running"
7252 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007253 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007254 )
tiernod6de1992018-10-11 13:05:52 +02007255 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007256 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007257 except (
7258 ROclient.ROClientException,
7259 DbException,
7260 LcmException,
7261 NgRoException,
7262 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007263 self.logger.error(logging_text + "Exit Exception {}".format(e))
7264 exc = e
7265 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007266 self.logger.error(
7267 logging_text + "Cancelled Exception while '{}'".format(step)
7268 )
tierno59d22d22018-09-25 18:10:19 +02007269 exc = "Operation was cancelled"
7270 except Exception as e:
7271 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007272 self.logger.critical(
7273 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7274 exc_info=True,
7275 )
tierno59d22d22018-09-25 18:10:19 +02007276 finally:
garciadeblas5697b8b2021-03-24 09:17:02 +01007277 self._write_ns_status(
7278 nsr_id=nsr_id,
7279 ns_state=None,
7280 current_operation="IDLE",
7281 current_operation_id=None,
7282 )
aktas13251562021-02-12 22:19:10 +03007283 if tasks_dict_info:
7284 stage[1] = "Waiting for instantiate pending tasks."
7285 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01007286 exc = await self._wait_for_tasks(
7287 logging_text,
7288 tasks_dict_info,
7289 self.timeout_ns_deploy,
7290 stage,
7291 nslcmop_id,
7292 nsr_id=nsr_id,
7293 )
tierno59d22d22018-09-25 18:10:19 +02007294 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01007295 db_nslcmop_update[
7296 "detailed-status"
7297 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tiernoa17d4f42020-04-28 09:59:23 +00007298 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007299 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007300 db_nsr_update["operational-status"] = old_operational_status
7301 db_nsr_update["config-status"] = old_config_status
7302 db_nsr_update["detailed-status"] = ""
7303 if scale_process:
7304 if "VCA" in scale_process:
7305 db_nsr_update["config-status"] = "failed"
7306 if "RO" in scale_process:
7307 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007308 db_nsr_update[
7309 "detailed-status"
7310 ] = "FAILED scaling nslcmop={} {}: {}".format(
7311 nslcmop_id, step, exc
7312 )
tiernoa17d4f42020-04-28 09:59:23 +00007313 else:
7314 error_description_nslcmop = None
7315 nslcmop_operation_state = "COMPLETED"
7316 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00007317
garciadeblas5697b8b2021-03-24 09:17:02 +01007318 self._write_op_status(
7319 op_id=nslcmop_id,
7320 stage="",
7321 error_message=error_description_nslcmop,
7322 operation_state=nslcmop_operation_state,
7323 other_update=db_nslcmop_update,
7324 )
tiernoa17d4f42020-04-28 09:59:23 +00007325 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007326 self._write_ns_status(
7327 nsr_id=nsr_id,
7328 ns_state=None,
7329 current_operation="IDLE",
7330 current_operation_id=None,
7331 other_update=db_nsr_update,
7332 )
tiernoa17d4f42020-04-28 09:59:23 +00007333
tierno59d22d22018-09-25 18:10:19 +02007334 if nslcmop_operation_state:
7335 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007336 msg = {
7337 "nsr_id": nsr_id,
7338 "nslcmop_id": nslcmop_id,
7339 "operationState": nslcmop_operation_state,
7340 }
bravof922c4172020-11-24 21:21:43 -03007341 await self.msg.aiowrite("ns", "scaled", msg, loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02007342 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007343 self.logger.error(
7344 logging_text + "kafka_write notification Exception {}".format(e)
7345 )
tierno59d22d22018-09-25 18:10:19 +02007346 self.logger.debug(logging_text + "Exit")
7347 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007348
aktas5f75f102021-03-15 11:26:10 +03007349 async def _scale_kdu(
7350 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7351 ):
7352 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7353 for kdu_name in _scaling_info:
7354 for kdu_scaling_info in _scaling_info[kdu_name]:
7355 deployed_kdu, index = get_deployed_kdu(
7356 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7357 )
7358 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7359 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007360 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007361 scale = int(kdu_scaling_info["scale"])
7362 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7363
7364 db_dict = {
7365 "collection": "nsrs",
7366 "filter": {"_id": nsr_id},
7367 "path": "_admin.deployed.K8s.{}".format(index),
7368 }
7369
7370 step = "scaling application {}".format(
7371 kdu_scaling_info["resource-name"]
7372 )
7373 self.logger.debug(logging_text + step)
7374
7375 if kdu_scaling_info["type"] == "delete":
7376 kdu_config = get_configuration(db_vnfd, kdu_name)
7377 if (
7378 kdu_config
7379 and kdu_config.get("terminate-config-primitive")
7380 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7381 ):
7382 terminate_config_primitive_list = kdu_config.get(
7383 "terminate-config-primitive"
7384 )
7385 terminate_config_primitive_list.sort(
7386 key=lambda val: int(val["seq"])
7387 )
7388
7389 for (
7390 terminate_config_primitive
7391 ) in terminate_config_primitive_list:
7392 primitive_params_ = self._map_primitive_params(
7393 terminate_config_primitive, {}, {}
7394 )
7395 step = "execute terminate config primitive"
7396 self.logger.debug(logging_text + step)
7397 await asyncio.wait_for(
7398 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7399 cluster_uuid=cluster_uuid,
7400 kdu_instance=kdu_instance,
7401 primitive_name=terminate_config_primitive["name"],
7402 params=primitive_params_,
7403 db_dict=db_dict,
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007404 total_timeout=self.timeout_primitive,
aktas5f75f102021-03-15 11:26:10 +03007405 vca_id=vca_id,
7406 ),
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007407 timeout=self.timeout_primitive
7408 * self.timeout_primitive_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007409 )
7410
7411 await asyncio.wait_for(
7412 self.k8scluster_map[k8s_cluster_type].scale(
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007413 kdu_instance=kdu_instance,
7414 scale=scale,
7415 resource_name=kdu_scaling_info["resource-name"],
7416 total_timeout=self.timeout_scale_on_error,
aktas5f75f102021-03-15 11:26:10 +03007417 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007418 cluster_uuid=cluster_uuid,
7419 kdu_model=kdu_model,
7420 atomic=True,
7421 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007422 ),
Pedro Escaleira3b610a42022-07-23 23:16:06 +01007423 timeout=self.timeout_scale_on_error
7424 * self.timeout_scale_on_error_outer_factor,
aktas5f75f102021-03-15 11:26:10 +03007425 )
7426
7427 if kdu_scaling_info["type"] == "create":
7428 kdu_config = get_configuration(db_vnfd, kdu_name)
7429 if (
7430 kdu_config
7431 and kdu_config.get("initial-config-primitive")
7432 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7433 ):
7434 initial_config_primitive_list = kdu_config.get(
7435 "initial-config-primitive"
7436 )
7437 initial_config_primitive_list.sort(
7438 key=lambda val: int(val["seq"])
7439 )
7440
7441 for initial_config_primitive in initial_config_primitive_list:
7442 primitive_params_ = self._map_primitive_params(
7443 initial_config_primitive, {}, {}
7444 )
7445 step = "execute initial config primitive"
7446 self.logger.debug(logging_text + step)
7447 await asyncio.wait_for(
7448 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7449 cluster_uuid=cluster_uuid,
7450 kdu_instance=kdu_instance,
7451 primitive_name=initial_config_primitive["name"],
7452 params=primitive_params_,
7453 db_dict=db_dict,
7454 vca_id=vca_id,
7455 ),
7456 timeout=600,
7457 )
7458
garciadeblas5697b8b2021-03-24 09:17:02 +01007459 async def _scale_ng_ro(
7460 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7461 ):
tierno2357f4e2020-10-19 16:38:59 +00007462 nsr_id = db_nslcmop["nsInstanceId"]
7463 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7464 db_vnfrs = {}
7465
7466 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007467 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007468
7469 # for each vnf in ns, read vnfd
7470 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7471 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7472 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007473 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007474 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007475 # read from db
7476 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007477 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007478 n2vc_key = self.n2vc.get_public_key()
7479 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007480 self.scale_vnfr(
7481 db_vnfr,
7482 vdu_scaling_info.get("vdu-create"),
7483 vdu_scaling_info.get("vdu-delete"),
7484 mark_delete=True,
7485 )
tierno2357f4e2020-10-19 16:38:59 +00007486 # db_vnfr has been updated, update db_vnfrs to use it
7487 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007488 await self._instantiate_ng_ro(
7489 logging_text,
7490 nsr_id,
7491 db_nsd,
7492 db_nsr,
7493 db_nslcmop,
7494 db_vnfrs,
7495 db_vnfds,
7496 n2vc_key_list,
7497 stage=stage,
7498 start_deploy=time(),
7499 timeout_ns_deploy=self.timeout_ns_deploy,
7500 )
tierno2357f4e2020-10-19 16:38:59 +00007501 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007502 self.scale_vnfr(
7503 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7504 )
tierno2357f4e2020-10-19 16:38:59 +00007505
bravof73bac502021-05-11 07:38:47 -04007506 async def extract_prometheus_scrape_jobs(
aticig15db6142022-01-24 12:51:26 +03007507 self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip
garciadeblas5697b8b2021-03-24 09:17:02 +01007508 ):
tiernob996d942020-07-03 14:52:28 +00007509 # look if exist a file called 'prometheus*.j2' and
7510 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007511 job_file = next(
7512 (
7513 f
7514 for f in artifact_content
7515 if f.startswith("prometheus") and f.endswith(".j2")
7516 ),
7517 None,
7518 )
tiernob996d942020-07-03 14:52:28 +00007519 if not job_file:
7520 return
7521 with self.fs.file_open((artifact_path, job_file), "r") as f:
7522 job_data = f.read()
7523
7524 # TODO get_service
garciadeblas5697b8b2021-03-24 09:17:02 +01007525 _, _, service = ee_id.partition(".") # remove prefix "namespace."
tiernob996d942020-07-03 14:52:28 +00007526 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
7527 host_port = "80"
7528 vnfr_id = vnfr_id.replace("-", "")
7529 variables = {
7530 "JOB_NAME": vnfr_id,
7531 "TARGET_IP": target_ip,
7532 "EXPORTER_POD_IP": host_name,
7533 "EXPORTER_POD_PORT": host_port,
7534 }
bravof73bac502021-05-11 07:38:47 -04007535 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007536 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7537 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007538 if (
7539 not isinstance(job.get("job_name"), str)
7540 or vnfr_id not in job["job_name"]
7541 ):
tiernob996d942020-07-03 14:52:28 +00007542 job["job_name"] = vnfr_id + "_" + str(randint(1, 10000))
7543 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007544 job["vnfr_id"] = vnfr_id
7545 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007546
preethika.p28b0bf82022-09-23 07:36:28 +00007547 async def rebuild_start_stop(
7548 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7549 ):
k4.rahulb827de92022-05-02 16:35:02 +00007550 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7551 self.logger.info(logging_text + "Enter")
7552 stage = ["Preparing the environment", ""]
7553 # database nsrs record
7554 db_nsr_update = {}
7555 vdu_vim_name = None
7556 vim_vm_id = None
7557 # in case of error, indicates what part of scale was failed to put nsr at error status
7558 start_deploy = time()
7559 try:
7560 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7561 vim_account_id = db_vnfr.get("vim-account-id")
7562 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007563 vdu_id = additional_param["vdu_id"]
7564 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007565 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007566 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007567 )
k4.rahulb827de92022-05-02 16:35:02 +00007568 if vdur:
7569 vdu_vim_name = vdur["name"]
7570 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7571 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007572 else:
7573 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007574 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7575 # wait for any previous tasks in process
7576 stage[1] = "Waiting for previous operations to terminate"
7577 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007578 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007579
7580 stage[1] = "Reading from database."
7581 self.logger.info(stage[1])
7582 self._write_ns_status(
7583 nsr_id=nsr_id,
7584 ns_state=None,
7585 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007586 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007587 )
7588 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7589
7590 # read from db: ns
7591 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7592 db_nsr_update["operational-status"] = operation_type
7593 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7594 # Payload for RO
7595 desc = {
7596 operation_type: {
7597 "vim_vm_id": vim_vm_id,
7598 "vnf_id": vnf_id,
7599 "vdu_index": additional_param["count-index"],
7600 "vdu_id": vdur["id"],
7601 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007602 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007603 }
7604 }
7605 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7606 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7607 self.logger.info("ro nsr id: {}".format(nsr_id))
7608 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7609 self.logger.info("response from RO: {}".format(result_dict))
7610 action_id = result_dict["action_id"]
7611 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007612 nsr_id,
7613 action_id,
7614 nslcmop_id,
7615 start_deploy,
7616 self.timeout_operate,
7617 None,
7618 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007619 )
7620 return "COMPLETED", "Done"
7621 except (ROclient.ROClientException, DbException, LcmException) as e:
7622 self.logger.error("Exit Exception {}".format(e))
7623 exc = e
7624 except asyncio.CancelledError:
7625 self.logger.error("Cancelled Exception while '{}'".format(stage))
7626 exc = "Operation was cancelled"
7627 except Exception as e:
7628 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007629 self.logger.critical(
7630 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7631 )
k4.rahulb827de92022-05-02 16:35:02 +00007632 return "FAILED", "Error in operate VNF {}".format(exc)
7633
David Garciaaae391f2020-11-09 11:12:54 +01007634 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7635 """
7636 Get VCA Cloud and VCA Cloud Credentials for the VIM account
7637
7638 :param: vim_account_id: VIM Account ID
7639
7640 :return: (cloud_name, cloud_credential)
7641 """
bravof922c4172020-11-24 21:21:43 -03007642 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007643 return config.get("vca_cloud"), config.get("vca_cloud_credential")
7644
7645 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7646 """
7647 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
7648
7649 :param: vim_account_id: VIM Account ID
7650
7651 :return: (cloud_name, cloud_credential)
7652 """
bravof922c4172020-11-24 21:21:43 -03007653 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007654 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")
elumalai80bcf1c2022-04-28 18:05:01 +05307655
7656 async def migrate(self, nsr_id, nslcmop_id):
7657 """
7658 Migrate VNFs and VDUs instances in a NS
7659
7660 :param: nsr_id: NS Instance ID
7661 :param: nslcmop_id: nslcmop ID of migrate
7662
7663 """
7664 # Try to lock HA task here
7665 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7666 if not task_is_locked_by_me:
7667 return
7668 logging_text = "Task ns={} migrate ".format(nsr_id)
7669 self.logger.debug(logging_text + "Enter")
7670 # get all needed from database
7671 db_nslcmop = None
7672 db_nslcmop_update = {}
7673 nslcmop_operation_state = None
7674 db_nsr_update = {}
7675 target = {}
7676 exc = None
7677 # in case of error, indicates what part of scale was failed to put nsr at error status
7678 start_deploy = time()
7679
7680 try:
7681 # wait for any previous tasks in process
7682 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007683 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307684
7685 self._write_ns_status(
7686 nsr_id=nsr_id,
7687 ns_state=None,
7688 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007689 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307690 )
7691 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007692 self.logger.debug(
7693 step + " after having waited for previous tasks to be completed"
7694 )
elumalai80bcf1c2022-04-28 18:05:01 +05307695 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7696 migrate_params = db_nslcmop.get("operationParams")
7697
7698 target = {}
7699 target.update(migrate_params)
7700 desc = await self.RO.migrate(nsr_id, target)
7701 self.logger.debug("RO return > {}".format(desc))
7702 action_id = desc["action_id"]
7703 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007704 nsr_id,
7705 action_id,
7706 nslcmop_id,
7707 start_deploy,
7708 self.timeout_migrate,
7709 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307710 )
7711 except (ROclient.ROClientException, DbException, LcmException) as e:
7712 self.logger.error("Exit Exception {}".format(e))
7713 exc = e
7714 except asyncio.CancelledError:
7715 self.logger.error("Cancelled Exception while '{}'".format(step))
7716 exc = "Operation was cancelled"
7717 except Exception as e:
7718 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007719 self.logger.critical(
7720 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7721 )
elumalai80bcf1c2022-04-28 18:05:01 +05307722 finally:
7723 self._write_ns_status(
7724 nsr_id=nsr_id,
7725 ns_state=None,
7726 current_operation="IDLE",
7727 current_operation_id=None,
7728 )
7729 if exc:
aticig349aa462022-05-19 12:29:35 +03007730 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05307731 nslcmop_operation_state = "FAILED"
7732 else:
7733 nslcmop_operation_state = "COMPLETED"
7734 db_nslcmop_update["detailed-status"] = "Done"
7735 db_nsr_update["detailed-status"] = "Done"
7736
7737 self._write_op_status(
7738 op_id=nslcmop_id,
7739 stage="",
7740 error_message="",
7741 operation_state=nslcmop_operation_state,
7742 other_update=db_nslcmop_update,
7743 )
7744 if nslcmop_operation_state:
7745 try:
7746 msg = {
7747 "nsr_id": nsr_id,
7748 "nslcmop_id": nslcmop_id,
7749 "operationState": nslcmop_operation_state,
7750 }
7751 await self.msg.aiowrite("ns", "migrated", msg, loop=self.loop)
7752 except Exception as e:
7753 self.logger.error(
7754 logging_text + "kafka_write notification Exception {}".format(e)
7755 )
7756 self.logger.debug(logging_text + "Exit")
7757 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007758
garciadeblas07f4e4c2022-06-09 09:42:58 +02007759 async def heal(self, nsr_id, nslcmop_id):
7760 """
7761 Heal NS
7762
7763 :param nsr_id: ns instance to heal
7764 :param nslcmop_id: operation to run
7765 :return:
7766 """
7767
7768 # Try to lock HA task here
7769 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7770 if not task_is_locked_by_me:
7771 return
7772
7773 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
7774 stage = ["", "", ""]
7775 tasks_dict_info = {}
7776 # ^ stage, step, VIM progress
7777 self.logger.debug(logging_text + "Enter")
7778 # get all needed from database
7779 db_nsr = None
7780 db_nslcmop_update = {}
7781 db_nsr_update = {}
7782 db_vnfrs = {} # vnf's info indexed by _id
7783 exc = None
7784 old_operational_status = ""
7785 old_config_status = ""
7786 nsi_id = None
7787 try:
7788 # wait for any previous tasks in process
7789 step = "Waiting for previous operations to terminate"
7790 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
7791 self._write_ns_status(
7792 nsr_id=nsr_id,
7793 ns_state=None,
7794 current_operation="HEALING",
7795 current_operation_id=nslcmop_id,
7796 )
7797
7798 step = "Getting nslcmop from database"
7799 self.logger.debug(
7800 step + " after having waited for previous tasks to be completed"
7801 )
7802 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7803
7804 step = "Getting nsr from database"
7805 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
7806 old_operational_status = db_nsr["operational-status"]
7807 old_config_status = db_nsr["config-status"]
7808
7809 db_nsr_update = {
7810 "_admin.deployed.RO.operational-status": "healing",
7811 }
7812 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7813
7814 step = "Sending heal order to VIM"
Gabriel Cuba4c9f8892022-11-07 19:28:14 -05007815 await self.heal_RO(
7816 logging_text=logging_text,
7817 nsr_id=nsr_id,
7818 db_nslcmop=db_nslcmop,
7819 stage=stage,
garciadeblas07f4e4c2022-06-09 09:42:58 +02007820 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007821 # VCA tasks
7822 # read from db: nsd
7823 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
7824 self.logger.debug(logging_text + stage[1])
7825 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7826 self.fs.sync(db_nsr["nsd-id"])
7827 db_nsr["nsd"] = nsd
7828 # read from db: vnfr's of this ns
7829 step = "Getting vnfrs from db"
7830 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
7831 for vnfr in db_vnfrs_list:
7832 db_vnfrs[vnfr["_id"]] = vnfr
7833 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
7834
7835 # Check for each target VNF
7836 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
7837 for target_vnf in target_list:
7838 # Find this VNF in the list from DB
7839 vnfr_id = target_vnf.get("vnfInstanceId", None)
7840 if vnfr_id:
7841 db_vnfr = db_vnfrs[vnfr_id]
7842 vnfd_id = db_vnfr.get("vnfd-id")
7843 vnfd_ref = db_vnfr.get("vnfd-ref")
7844 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
7845 base_folder = vnfd["_admin"]["storage"]
7846 vdu_id = None
7847 vdu_index = 0
7848 vdu_name = None
7849 kdu_name = None
7850 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
7851 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
7852
7853 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00007854 target_vdu_list = target_vnf.get("additionalParams", {}).get(
7855 "vdu", []
7856 )
garciadeblas50639832022-09-01 13:09:47 +02007857 if not target_vdu_list:
7858 # Codigo nuevo para crear diccionario
7859 target_vdu_list = []
7860 for existing_vdu in db_vnfr.get("vdur"):
7861 vdu_name = existing_vdu.get("vdu-name", None)
7862 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00007863 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
7864 "run-day1", False
7865 )
7866 vdu_to_be_healed = {
7867 "vdu-id": vdu_name,
7868 "count-index": vdu_index,
7869 "run-day1": vdu_run_day1,
7870 }
garciadeblas50639832022-09-01 13:09:47 +02007871 target_vdu_list.append(vdu_to_be_healed)
7872 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02007873 deploy_params_vdu = target_vdu
7874 # Set run-day1 vnf level value if not vdu level value exists
preethika.p28b0bf82022-09-23 07:36:28 +00007875 if not deploy_params_vdu.get("run-day1") and target_vnf[
7876 "additionalParams"
7877 ].get("run-day1"):
7878 deploy_params_vdu["run-day1"] = target_vnf[
7879 "additionalParams"
7880 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007881 vdu_name = target_vdu.get("vdu-id", None)
7882 # TODO: Get vdu_id from vdud.
7883 vdu_id = vdu_name
7884 # For multi instance VDU count-index is mandatory
7885 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00007886 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007887
7888 # n2vc_redesign STEP 3 to 6 Deploy N2VC
7889 stage[1] = "Deploying Execution Environments."
7890 self.logger.debug(logging_text + stage[1])
7891
7892 # VNF Level charm. Normal case when proxy charms.
7893 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
7894 descriptor_config = get_configuration(vnfd, vnfd_ref)
7895 if descriptor_config:
7896 # Continue if healed machine is management machine
7897 vnf_ip_address = db_vnfr.get("ip-address")
7898 target_instance = None
7899 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00007900 if (
7901 instance["vdu-name"] == vdu_name
7902 and instance["count-index"] == vdu_index
7903 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02007904 target_instance = instance
7905 break
7906 if vnf_ip_address == target_instance.get("ip-address"):
7907 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00007908 logging_text=logging_text
7909 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
7910 member_vnf_index, vdu_name, vdu_index
7911 ),
7912 db_nsr=db_nsr,
7913 db_vnfr=db_vnfr,
7914 nslcmop_id=nslcmop_id,
7915 nsr_id=nsr_id,
7916 nsi_id=nsi_id,
7917 vnfd_id=vnfd_ref,
7918 vdu_id=None,
7919 kdu_name=None,
7920 member_vnf_index=member_vnf_index,
7921 vdu_index=0,
7922 vdu_name=None,
7923 deploy_params=deploy_params_vdu,
7924 descriptor_config=descriptor_config,
7925 base_folder=base_folder,
7926 task_instantiation_info=tasks_dict_info,
7927 stage=stage,
7928 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007929
7930 # VDU Level charm. Normal case with native charms.
7931 descriptor_config = get_configuration(vnfd, vdu_name)
7932 if descriptor_config:
7933 self._heal_n2vc(
7934 logging_text=logging_text
7935 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
7936 member_vnf_index, vdu_name, vdu_index
7937 ),
7938 db_nsr=db_nsr,
7939 db_vnfr=db_vnfr,
7940 nslcmop_id=nslcmop_id,
7941 nsr_id=nsr_id,
7942 nsi_id=nsi_id,
7943 vnfd_id=vnfd_ref,
7944 vdu_id=vdu_id,
7945 kdu_name=kdu_name,
7946 member_vnf_index=member_vnf_index,
7947 vdu_index=vdu_index,
7948 vdu_name=vdu_name,
7949 deploy_params=deploy_params_vdu,
7950 descriptor_config=descriptor_config,
7951 base_folder=base_folder,
7952 task_instantiation_info=tasks_dict_info,
7953 stage=stage,
7954 )
7955
7956 except (
7957 ROclient.ROClientException,
7958 DbException,
7959 LcmException,
7960 NgRoException,
7961 ) as e:
7962 self.logger.error(logging_text + "Exit Exception {}".format(e))
7963 exc = e
7964 except asyncio.CancelledError:
7965 self.logger.error(
7966 logging_text + "Cancelled Exception while '{}'".format(step)
7967 )
7968 exc = "Operation was cancelled"
7969 except Exception as e:
7970 exc = traceback.format_exc()
7971 self.logger.critical(
7972 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7973 exc_info=True,
7974 )
7975 finally:
7976 if tasks_dict_info:
7977 stage[1] = "Waiting for healing pending tasks."
7978 self.logger.debug(logging_text + stage[1])
7979 exc = await self._wait_for_tasks(
7980 logging_text,
7981 tasks_dict_info,
7982 self.timeout_ns_deploy,
7983 stage,
7984 nslcmop_id,
7985 nsr_id=nsr_id,
7986 )
7987 if exc:
7988 db_nslcmop_update[
7989 "detailed-status"
7990 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
7991 nslcmop_operation_state = "FAILED"
7992 if db_nsr:
7993 db_nsr_update["operational-status"] = old_operational_status
7994 db_nsr_update["config-status"] = old_config_status
7995 db_nsr_update[
7996 "detailed-status"
preethika.p28b0bf82022-09-23 07:36:28 +00007997 ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007998 for task, task_name in tasks_dict_info.items():
7999 if not task.done() or task.cancelled() or task.exception():
8000 if task_name.startswith(self.task_name_deploy_vca):
8001 # A N2VC task is pending
8002 db_nsr_update["config-status"] = "failed"
8003 else:
8004 # RO task is pending
8005 db_nsr_update["operational-status"] = "failed"
8006 else:
8007 error_description_nslcmop = None
8008 nslcmop_operation_state = "COMPLETED"
8009 db_nslcmop_update["detailed-status"] = "Done"
8010 db_nsr_update["detailed-status"] = "Done"
8011 db_nsr_update["operational-status"] = "running"
8012 db_nsr_update["config-status"] = "configured"
8013
8014 self._write_op_status(
8015 op_id=nslcmop_id,
8016 stage="",
8017 error_message=error_description_nslcmop,
8018 operation_state=nslcmop_operation_state,
8019 other_update=db_nslcmop_update,
8020 )
8021 if db_nsr:
8022 self._write_ns_status(
8023 nsr_id=nsr_id,
8024 ns_state=None,
8025 current_operation="IDLE",
8026 current_operation_id=None,
8027 other_update=db_nsr_update,
8028 )
8029
8030 if nslcmop_operation_state:
8031 try:
8032 msg = {
8033 "nsr_id": nsr_id,
8034 "nslcmop_id": nslcmop_id,
8035 "operationState": nslcmop_operation_state,
8036 }
8037 await self.msg.aiowrite("ns", "healed", msg, loop=self.loop)
8038 except Exception as e:
8039 self.logger.error(
8040 logging_text + "kafka_write notification Exception {}".format(e)
8041 )
8042 self.logger.debug(logging_text + "Exit")
8043 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
8044
8045 async def heal_RO(
8046 self,
8047 logging_text,
8048 nsr_id,
8049 db_nslcmop,
8050 stage,
8051 ):
8052 """
8053 Heal at RO
8054 :param logging_text: preffix text to use at logging
8055 :param nsr_id: nsr identity
8056 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
8057 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
8058 :return: None or exception
8059 """
preethika.p28b0bf82022-09-23 07:36:28 +00008060
garciadeblas07f4e4c2022-06-09 09:42:58 +02008061 def get_vim_account(vim_account_id):
8062 nonlocal db_vims
8063 if vim_account_id in db_vims:
8064 return db_vims[vim_account_id]
8065 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
8066 db_vims[vim_account_id] = db_vim
8067 return db_vim
8068
8069 try:
8070 start_heal = time()
8071 ns_params = db_nslcmop.get("operationParams")
8072 if ns_params and ns_params.get("timeout_ns_heal"):
8073 timeout_ns_heal = ns_params["timeout_ns_heal"]
8074 else:
preethika.p28b0bf82022-09-23 07:36:28 +00008075 timeout_ns_heal = self.timeout.get("ns_heal", self.timeout_ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008076
8077 db_vims = {}
8078
8079 nslcmop_id = db_nslcmop["_id"]
8080 target = {
8081 "action_id": nslcmop_id,
8082 }
preethika.p28b0bf82022-09-23 07:36:28 +00008083 self.logger.warning(
8084 "db_nslcmop={} and timeout_ns_heal={}".format(
8085 db_nslcmop, timeout_ns_heal
8086 )
8087 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008088 target.update(db_nslcmop.get("operationParams", {}))
8089
8090 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
8091 desc = await self.RO.recreate(nsr_id, target)
8092 self.logger.debug("RO return > {}".format(desc))
8093 action_id = desc["action_id"]
8094 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
8095 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008096 nsr_id,
8097 action_id,
8098 nslcmop_id,
8099 start_heal,
8100 timeout_ns_heal,
8101 stage,
8102 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02008103 )
8104
8105 # Updating NSR
8106 db_nsr_update = {
8107 "_admin.deployed.RO.operational-status": "running",
8108 "detailed-status": " ".join(stage),
8109 }
8110 self.update_db_2("nsrs", nsr_id, db_nsr_update)
8111 self._write_op_status(nslcmop_id, stage)
8112 self.logger.debug(
8113 logging_text + "ns healed at RO. RO_id={}".format(action_id)
8114 )
8115
8116 except Exception as e:
8117 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00008118 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008119 self.logger.error(
8120 "Error healing at VIM {}".format(e),
8121 exc_info=not isinstance(
8122 e,
8123 (
8124 ROclient.ROClientException,
8125 LcmException,
8126 DbException,
8127 NgRoException,
8128 ),
8129 ),
8130 )
8131 raise
8132
8133 def _heal_n2vc(
8134 self,
8135 logging_text,
8136 db_nsr,
8137 db_vnfr,
8138 nslcmop_id,
8139 nsr_id,
8140 nsi_id,
8141 vnfd_id,
8142 vdu_id,
8143 kdu_name,
8144 member_vnf_index,
8145 vdu_index,
8146 vdu_name,
8147 deploy_params,
8148 descriptor_config,
8149 base_folder,
8150 task_instantiation_info,
8151 stage,
8152 ):
8153 # launch instantiate_N2VC in a asyncio task and register task object
8154 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
8155 # if not found, create one entry and update database
8156 # fill db_nsr._admin.deployed.VCA.<index>
8157
8158 self.logger.debug(
8159 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
8160 )
aticig9bc63ac2022-07-27 09:32:06 +03008161
8162 charm_name = ""
8163 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02008164 if "execution-environment-list" in descriptor_config:
8165 ee_list = descriptor_config.get("execution-environment-list", [])
8166 elif "juju" in descriptor_config:
8167 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03008168 if "execution-environment-list" not in descriptor_config:
8169 # charm name is only required for ns charms
8170 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02008171 else: # other types as script are not supported
8172 ee_list = []
8173
8174 for ee_item in ee_list:
8175 self.logger.debug(
8176 logging_text
8177 + "_deploy_n2vc ee_item juju={}, helm={}".format(
8178 ee_item.get("juju"), ee_item.get("helm-chart")
8179 )
8180 )
8181 ee_descriptor_id = ee_item.get("id")
8182 if ee_item.get("juju"):
8183 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03008184 if get_charm_name:
8185 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas07f4e4c2022-06-09 09:42:58 +02008186 vca_type = (
8187 "lxc_proxy_charm"
8188 if ee_item["juju"].get("charm") is not None
8189 else "native_charm"
8190 )
8191 if ee_item["juju"].get("cloud") == "k8s":
8192 vca_type = "k8s_proxy_charm"
8193 elif ee_item["juju"].get("proxy") is False:
8194 vca_type = "native_charm"
8195 elif ee_item.get("helm-chart"):
8196 vca_name = ee_item["helm-chart"]
8197 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
8198 vca_type = "helm"
8199 else:
8200 vca_type = "helm-v3"
8201 else:
8202 self.logger.debug(
8203 logging_text + "skipping non juju neither charm configuration"
8204 )
8205 continue
8206
8207 vca_index = -1
8208 for vca_index, vca_deployed in enumerate(
8209 db_nsr["_admin"]["deployed"]["VCA"]
8210 ):
8211 if not vca_deployed:
8212 continue
8213 if (
8214 vca_deployed.get("member-vnf-index") == member_vnf_index
8215 and vca_deployed.get("vdu_id") == vdu_id
8216 and vca_deployed.get("kdu_name") == kdu_name
8217 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8218 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8219 ):
8220 break
8221 else:
8222 # not found, create one.
8223 target = (
8224 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8225 )
8226 if vdu_id:
8227 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8228 elif kdu_name:
8229 target += "/kdu/{}".format(kdu_name)
8230 vca_deployed = {
8231 "target_element": target,
8232 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8233 "member-vnf-index": member_vnf_index,
8234 "vdu_id": vdu_id,
8235 "kdu_name": kdu_name,
8236 "vdu_count_index": vdu_index,
8237 "operational-status": "init", # TODO revise
8238 "detailed-status": "", # TODO revise
8239 "step": "initial-deploy", # TODO revise
8240 "vnfd_id": vnfd_id,
8241 "vdu_name": vdu_name,
8242 "type": vca_type,
8243 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008244 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008245 }
8246 vca_index += 1
8247
8248 # create VCA and configurationStatus in db
8249 db_dict = {
8250 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8251 "configurationStatus.{}".format(vca_index): dict(),
8252 }
8253 self.update_db_2("nsrs", nsr_id, db_dict)
8254
8255 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8256
8257 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8258 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8259 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8260
8261 # Launch task
8262 task_n2vc = asyncio.ensure_future(
8263 self.heal_N2VC(
8264 logging_text=logging_text,
8265 vca_index=vca_index,
8266 nsi_id=nsi_id,
8267 db_nsr=db_nsr,
8268 db_vnfr=db_vnfr,
8269 vdu_id=vdu_id,
8270 kdu_name=kdu_name,
8271 vdu_index=vdu_index,
8272 deploy_params=deploy_params,
8273 config_descriptor=descriptor_config,
8274 base_folder=base_folder,
8275 nslcmop_id=nslcmop_id,
8276 stage=stage,
8277 vca_type=vca_type,
8278 vca_name=vca_name,
8279 ee_config_descriptor=ee_item,
8280 )
8281 )
8282 self.lcm_tasks.register(
8283 "ns",
8284 nsr_id,
8285 nslcmop_id,
8286 "instantiate_N2VC-{}".format(vca_index),
8287 task_n2vc,
8288 )
8289 task_instantiation_info[
8290 task_n2vc
8291 ] = self.task_name_deploy_vca + " {}.{}".format(
8292 member_vnf_index or "", vdu_id or ""
8293 )
8294
8295 async def heal_N2VC(
8296 self,
8297 logging_text,
8298 vca_index,
8299 nsi_id,
8300 db_nsr,
8301 db_vnfr,
8302 vdu_id,
8303 kdu_name,
8304 vdu_index,
8305 config_descriptor,
8306 deploy_params,
8307 base_folder,
8308 nslcmop_id,
8309 stage,
8310 vca_type,
8311 vca_name,
8312 ee_config_descriptor,
8313 ):
8314 nsr_id = db_nsr["_id"]
8315 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8316 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8317 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8318 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8319 db_dict = {
8320 "collection": "nsrs",
8321 "filter": {"_id": nsr_id},
8322 "path": db_update_entry,
8323 }
8324 step = ""
8325 try:
8326
8327 element_type = "NS"
8328 element_under_configuration = nsr_id
8329
8330 vnfr_id = None
8331 if db_vnfr:
8332 vnfr_id = db_vnfr["_id"]
8333 osm_config["osm"]["vnf_id"] = vnfr_id
8334
8335 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8336
8337 if vca_type == "native_charm":
8338 index_number = 0
8339 else:
8340 index_number = vdu_index or 0
8341
8342 if vnfr_id:
8343 element_type = "VNF"
8344 element_under_configuration = vnfr_id
8345 namespace += ".{}-{}".format(vnfr_id, index_number)
8346 if vdu_id:
8347 namespace += ".{}-{}".format(vdu_id, index_number)
8348 element_type = "VDU"
8349 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8350 osm_config["osm"]["vdu_id"] = vdu_id
8351 elif kdu_name:
8352 namespace += ".{}".format(kdu_name)
8353 element_type = "KDU"
8354 element_under_configuration = kdu_name
8355 osm_config["osm"]["kdu_name"] = kdu_name
8356
8357 # Get artifact path
8358 if base_folder["pkg-dir"]:
8359 artifact_path = "{}/{}/{}/{}".format(
8360 base_folder["folder"],
8361 base_folder["pkg-dir"],
8362 "charms"
8363 if vca_type
8364 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8365 else "helm-charts",
8366 vca_name,
8367 )
8368 else:
8369 artifact_path = "{}/Scripts/{}/{}/".format(
8370 base_folder["folder"],
8371 "charms"
8372 if vca_type
8373 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8374 else "helm-charts",
8375 vca_name,
8376 )
8377
8378 self.logger.debug("Artifact path > {}".format(artifact_path))
8379
8380 # get initial_config_primitive_list that applies to this element
8381 initial_config_primitive_list = config_descriptor.get(
8382 "initial-config-primitive"
8383 )
8384
8385 self.logger.debug(
8386 "Initial config primitive list > {}".format(
8387 initial_config_primitive_list
8388 )
8389 )
8390
8391 # add config if not present for NS charm
8392 ee_descriptor_id = ee_config_descriptor.get("id")
8393 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8394 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8395 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8396 )
8397
8398 self.logger.debug(
8399 "Initial config primitive list #2 > {}".format(
8400 initial_config_primitive_list
8401 )
8402 )
8403 # n2vc_redesign STEP 3.1
8404 # find old ee_id if exists
8405 ee_id = vca_deployed.get("ee_id")
8406
8407 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8408 # create or register execution environment in VCA. Only for native charms when healing
8409 if vca_type == "native_charm":
8410 step = "Waiting to VM being up and getting IP address"
8411 self.logger.debug(logging_text + step)
8412 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8413 logging_text,
8414 nsr_id,
8415 vnfr_id,
8416 vdu_id,
8417 vdu_index,
8418 user=None,
8419 pub_key=None,
8420 )
8421 credentials = {"hostname": rw_mgmt_ip}
8422 # get username
8423 username = deep_get(
8424 config_descriptor, ("config-access", "ssh-access", "default-user")
8425 )
8426 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8427 # merged. Meanwhile let's get username from initial-config-primitive
8428 if not username and initial_config_primitive_list:
8429 for config_primitive in initial_config_primitive_list:
8430 for param in config_primitive.get("parameter", ()):
8431 if param["name"] == "ssh-username":
8432 username = param["value"]
8433 break
8434 if not username:
8435 raise LcmException(
8436 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8437 "'config-access.ssh-access.default-user'"
8438 )
8439 credentials["username"] = username
8440
8441 # n2vc_redesign STEP 3.2
8442 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8443 self._write_configuration_status(
8444 nsr_id=nsr_id,
8445 vca_index=vca_index,
8446 status="REGISTERING",
8447 element_under_configuration=element_under_configuration,
8448 element_type=element_type,
8449 )
8450
8451 step = "register execution environment {}".format(credentials)
8452 self.logger.debug(logging_text + step)
8453 ee_id = await self.vca_map[vca_type].register_execution_environment(
8454 credentials=credentials,
8455 namespace=namespace,
8456 db_dict=db_dict,
8457 vca_id=vca_id,
8458 )
8459
8460 # update ee_id en db
8461 db_dict_ee_id = {
8462 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8463 }
8464 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8465
8466 # for compatibility with MON/POL modules, the need model and application name at database
8467 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8468 # Not sure if this need to be done when healing
8469 """
8470 ee_id_parts = ee_id.split(".")
8471 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8472 if len(ee_id_parts) >= 2:
8473 model_name = ee_id_parts[0]
8474 application_name = ee_id_parts[1]
8475 db_nsr_update[db_update_entry + "model"] = model_name
8476 db_nsr_update[db_update_entry + "application"] = application_name
8477 """
8478
8479 # n2vc_redesign STEP 3.3
8480 # Install configuration software. Only for native charms.
8481 step = "Install configuration Software"
8482
8483 self._write_configuration_status(
8484 nsr_id=nsr_id,
8485 vca_index=vca_index,
8486 status="INSTALLING SW",
8487 element_under_configuration=element_under_configuration,
8488 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008489 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008490 other_update=None,
8491 )
8492
8493 # TODO check if already done
8494 self.logger.debug(logging_text + step)
8495 config = None
8496 if vca_type == "native_charm":
8497 config_primitive = next(
8498 (p for p in initial_config_primitive_list if p["name"] == "config"),
8499 None,
8500 )
8501 if config_primitive:
8502 config = self._map_primitive_params(
8503 config_primitive, {}, deploy_params
8504 )
8505 await self.vca_map[vca_type].install_configuration_sw(
8506 ee_id=ee_id,
8507 artifact_path=artifact_path,
8508 db_dict=db_dict,
8509 config=config,
8510 num_units=1,
8511 vca_id=vca_id,
8512 vca_type=vca_type,
8513 )
8514
8515 # write in db flag of configuration_sw already installed
8516 self.update_db_2(
8517 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8518 )
8519
8520 # Not sure if this need to be done when healing
8521 """
8522 # add relations for this VCA (wait for other peers related with this VCA)
8523 await self._add_vca_relations(
8524 logging_text=logging_text,
8525 nsr_id=nsr_id,
8526 vca_type=vca_type,
8527 vca_index=vca_index,
8528 )
8529 """
8530
8531 # if SSH access is required, then get execution environment SSH public
8532 # if native charm we have waited already to VM be UP
8533 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
8534 pub_key = None
8535 user = None
8536 # self.logger.debug("get ssh key block")
8537 if deep_get(
8538 config_descriptor, ("config-access", "ssh-access", "required")
8539 ):
8540 # self.logger.debug("ssh key needed")
8541 # Needed to inject a ssh key
8542 user = deep_get(
8543 config_descriptor,
8544 ("config-access", "ssh-access", "default-user"),
8545 )
8546 step = "Install configuration Software, getting public ssh key"
8547 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8548 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8549 )
8550
8551 step = "Insert public key into VM user={} ssh_key={}".format(
8552 user, pub_key
8553 )
8554 else:
8555 # self.logger.debug("no need to get ssh key")
8556 step = "Waiting to VM being up and getting IP address"
8557 self.logger.debug(logging_text + step)
8558
8559 # n2vc_redesign STEP 5.1
8560 # wait for RO (ip-address) Insert pub_key into VM
8561 # IMPORTANT: We need do wait for RO to complete healing operation.
preethika.p28b0bf82022-09-23 07:36:28 +00008562 await self._wait_heal_ro(nsr_id, self.timeout_ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008563 if vnfr_id:
8564 if kdu_name:
8565 rw_mgmt_ip = await self.wait_kdu_up(
8566 logging_text, nsr_id, vnfr_id, kdu_name
8567 )
8568 else:
8569 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8570 logging_text,
8571 nsr_id,
8572 vnfr_id,
8573 vdu_id,
8574 vdu_index,
8575 user=user,
8576 pub_key=pub_key,
8577 )
8578 else:
8579 rw_mgmt_ip = None # This is for a NS configuration
8580
8581 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8582
8583 # store rw_mgmt_ip in deploy params for later replacement
8584 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8585
8586 # Day1 operations.
8587 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008588 runDay1 = deploy_params.get("run-day1", False)
8589 self.logger.debug(
8590 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8591 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008592 if runDay1:
8593 # n2vc_redesign STEP 6 Execute initial config primitive
8594 step = "execute initial config primitive"
8595
8596 # wait for dependent primitives execution (NS -> VNF -> VDU)
8597 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008598 await self._wait_dependent_n2vc(
8599 nsr_id, vca_deployed_list, vca_index
8600 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008601
8602 # stage, in function of element type: vdu, kdu, vnf or ns
8603 my_vca = vca_deployed_list[vca_index]
8604 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8605 # VDU or KDU
8606 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8607 elif my_vca.get("member-vnf-index"):
8608 # VNF
8609 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8610 else:
8611 # NS
8612 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8613
8614 self._write_configuration_status(
8615 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8616 )
8617
8618 self._write_op_status(op_id=nslcmop_id, stage=stage)
8619
8620 check_if_terminated_needed = True
8621 for initial_config_primitive in initial_config_primitive_list:
8622 # adding information on the vca_deployed if it is a NS execution environment
8623 if not vca_deployed["member-vnf-index"]:
8624 deploy_params["ns_config_info"] = json.dumps(
8625 self._get_ns_config_info(nsr_id)
8626 )
8627 # TODO check if already done
8628 primitive_params_ = self._map_primitive_params(
8629 initial_config_primitive, {}, deploy_params
8630 )
8631
8632 step = "execute primitive '{}' params '{}'".format(
8633 initial_config_primitive["name"], primitive_params_
8634 )
8635 self.logger.debug(logging_text + step)
8636 await self.vca_map[vca_type].exec_primitive(
8637 ee_id=ee_id,
8638 primitive_name=initial_config_primitive["name"],
8639 params_dict=primitive_params_,
8640 db_dict=db_dict,
8641 vca_id=vca_id,
8642 vca_type=vca_type,
8643 )
8644 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8645 if check_if_terminated_needed:
8646 if config_descriptor.get("terminate-config-primitive"):
8647 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008648 "nsrs",
8649 nsr_id,
8650 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008651 )
8652 check_if_terminated_needed = False
8653
8654 # TODO register in database that primitive is done
8655
8656 # STEP 7 Configure metrics
8657 # Not sure if this need to be done when healing
8658 """
8659 if vca_type == "helm" or vca_type == "helm-v3":
8660 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8661 ee_id=ee_id,
8662 artifact_path=artifact_path,
8663 ee_config_descriptor=ee_config_descriptor,
8664 vnfr_id=vnfr_id,
8665 nsr_id=nsr_id,
8666 target_ip=rw_mgmt_ip,
8667 )
8668 if prometheus_jobs:
8669 self.update_db_2(
8670 "nsrs",
8671 nsr_id,
8672 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8673 )
8674
8675 for job in prometheus_jobs:
8676 self.db.set_one(
8677 "prometheus_jobs",
8678 {"job_name": job["job_name"]},
8679 job,
8680 upsert=True,
8681 fail_on_empty=False,
8682 )
8683
8684 """
8685 step = "instantiated at VCA"
8686 self.logger.debug(logging_text + step)
8687
8688 self._write_configuration_status(
8689 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8690 )
8691
8692 except Exception as e: # TODO not use Exception but N2VC exception
8693 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8694 if not isinstance(
8695 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8696 ):
8697 self.logger.error(
8698 "Exception while {} : {}".format(step, e), exc_info=True
8699 )
8700 self._write_configuration_status(
8701 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8702 )
8703 raise LcmException("{} {}".format(step, e)) from e
8704
8705 async def _wait_heal_ro(
8706 self,
8707 nsr_id,
8708 timeout=600,
8709 ):
8710 start_time = time()
8711 while time() <= start_time + timeout:
8712 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00008713 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
8714 "operational-status"
8715 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02008716 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
8717 if operational_status_ro != "healing":
8718 break
8719 await asyncio.sleep(15, loop=self.loop)
8720 else: # timeout_ns_deploy
8721 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05308722
8723 async def vertical_scale(self, nsr_id, nslcmop_id):
8724 """
8725 Vertical Scale the VDUs in a NS
8726
8727 :param: nsr_id: NS Instance ID
8728 :param: nslcmop_id: nslcmop ID of migrate
8729
8730 """
8731 # Try to lock HA task here
8732 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8733 if not task_is_locked_by_me:
8734 return
8735 logging_text = "Task ns={} vertical scale ".format(nsr_id)
8736 self.logger.debug(logging_text + "Enter")
8737 # get all needed from database
8738 db_nslcmop = None
8739 db_nslcmop_update = {}
8740 nslcmop_operation_state = None
8741 db_nsr_update = {}
8742 target = {}
8743 exc = None
8744 # in case of error, indicates what part of scale was failed to put nsr at error status
8745 start_deploy = time()
8746
8747 try:
8748 # wait for any previous tasks in process
8749 step = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00008750 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05308751
8752 self._write_ns_status(
8753 nsr_id=nsr_id,
8754 ns_state=None,
8755 current_operation="VerticalScale",
preethika.p28b0bf82022-09-23 07:36:28 +00008756 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05308757 )
8758 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00008759 self.logger.debug(
8760 step + " after having waited for previous tasks to be completed"
8761 )
govindarajul4ff4b512022-05-02 20:02:41 +05308762 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8763 operationParams = db_nslcmop.get("operationParams")
8764 target = {}
8765 target.update(operationParams)
8766 desc = await self.RO.vertical_scale(nsr_id, target)
8767 self.logger.debug("RO return > {}".format(desc))
8768 action_id = desc["action_id"]
8769 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008770 nsr_id,
8771 action_id,
8772 nslcmop_id,
8773 start_deploy,
8774 self.timeout_verticalscale,
8775 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05308776 )
8777 except (ROclient.ROClientException, DbException, LcmException) as e:
8778 self.logger.error("Exit Exception {}".format(e))
8779 exc = e
8780 except asyncio.CancelledError:
8781 self.logger.error("Cancelled Exception while '{}'".format(step))
8782 exc = "Operation was cancelled"
8783 except Exception as e:
8784 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00008785 self.logger.critical(
8786 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8787 )
govindarajul4ff4b512022-05-02 20:02:41 +05308788 finally:
8789 self._write_ns_status(
8790 nsr_id=nsr_id,
8791 ns_state=None,
8792 current_operation="IDLE",
8793 current_operation_id=None,
8794 )
8795 if exc:
preethika.p28b0bf82022-09-23 07:36:28 +00008796 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
govindarajul4ff4b512022-05-02 20:02:41 +05308797 nslcmop_operation_state = "FAILED"
8798 else:
8799 nslcmop_operation_state = "COMPLETED"
8800 db_nslcmop_update["detailed-status"] = "Done"
8801 db_nsr_update["detailed-status"] = "Done"
8802
8803 self._write_op_status(
8804 op_id=nslcmop_id,
8805 stage="",
8806 error_message="",
8807 operation_state=nslcmop_operation_state,
8808 other_update=db_nslcmop_update,
8809 )
8810 if nslcmop_operation_state:
8811 try:
8812 msg = {
8813 "nsr_id": nsr_id,
8814 "nslcmop_id": nslcmop_id,
8815 "operationState": nslcmop_operation_state,
8816 }
8817 await self.msg.aiowrite("ns", "verticalscaled", msg, loop=self.loop)
8818 except Exception as e:
8819 self.logger.error(
8820 logging_text + "kafka_write notification Exception {}".format(e)
8821 )
8822 self.logger.debug(logging_text + "Exit")
8823 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")