blob: d267065928f53731030f5bc6c07a50d7ff03d3fe [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,
garciadeblas5697b8b2021-03-24 09:17:02 +010062)
David Garciab4ebcd02021-10-28 02:00:43 +020063from osm_lcm.data_utils.nsd import (
64 get_ns_configuration_relation_list,
65 get_vnf_profile,
66 get_vnf_profiles,
67)
garciadeblas5697b8b2021-03-24 09:17:02 +010068from osm_lcm.data_utils.vnfd import (
David Garcia78b6e6d2022-04-29 05:50:46 +020069 get_kdu,
70 get_kdu_services,
David Garciab4ebcd02021-10-28 02:00:43 +020071 get_relation_list,
garciadeblas5697b8b2021-03-24 09:17:02 +010072 get_vdu_list,
73 get_vdu_profile,
74 get_ee_sorted_initial_config_primitive_list,
75 get_ee_sorted_terminate_config_primitive_list,
76 get_kdu_list,
77 get_virtual_link_profiles,
78 get_vdu,
79 get_configuration,
80 get_vdu_index,
81 get_scaling_aspect,
82 get_number_of_instances,
83 get_juju_ee_ref,
David Garciab4ebcd02021-10-28 02:00:43 +020084 get_kdu_resource_profile,
aticigdffa6212022-04-12 15:27:53 +030085 find_software_version,
garciadeblas5697b8b2021-03-24 09:17:02 +010086)
bravof922c4172020-11-24 21:21:43 -030087from osm_lcm.data_utils.list_utils import find_in_list
aticig349aa462022-05-19 12:29:35 +030088from osm_lcm.data_utils.vnfr import (
89 get_osm_params,
90 get_vdur_index,
91 get_kdur,
92 get_volumes_from_instantiation_params,
93)
bravof922c4172020-11-24 21:21:43 -030094from osm_lcm.data_utils.dict_utils import parse_yaml_strings
95from osm_lcm.data_utils.database.vim_account import VimAccountDB
David Garciab4ebcd02021-10-28 02:00:43 +020096from n2vc.definitions import RelationEndpoint
calvinosanch9f9c6f22019-11-04 13:37:39 +010097from n2vc.k8s_helm_conn import K8sHelmConnector
lloretgalleg18ebc3a2020-10-22 09:54:51 +000098from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -050099from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +0200100
tierno27246d82018-09-27 15:59:09 +0200101from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +0200102from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +0200103
bravof922c4172020-11-24 21:21:43 -0300104from osm_lcm.data_utils.database.database import Database
105from osm_lcm.data_utils.filesystem.filesystem import Filesystem
106
quilesj7e13aeb2019-10-08 13:34:55 +0200107from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +0000108from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +0200109
tierno588547c2020-07-01 15:30:20 +0000110from osm_lcm.lcm_helm_conn import LCMHelmConn
David Garcia78b6e6d2022-04-29 05:50:46 +0200111from osm_lcm.osm_config import OsmConfigBuilder
bravof73bac502021-05-11 07:38:47 -0400112from osm_lcm.prometheus import parse_job
tierno588547c2020-07-01 15:30:20 +0000113
tierno27246d82018-09-27 15:59:09 +0200114from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +0200115from time import time
tierno27246d82018-09-27 15:59:09 +0200116from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +0000117
tiernob996d942020-07-03 14:52:28 +0000118from random import randint
tierno59d22d22018-09-25 18:10:19 +0200119
tierno69f0d382020-05-07 13:08:09 +0000120__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +0200121
122
123class NsLcm(LcmBase):
garciadeblas5697b8b2021-03-24 09:17:02 +0100124 timeout_vca_on_error = (
125 5 * 60
126 ) # Time for charm from first time at blocked,error status to mark as failed
127 timeout_ns_deploy = 2 * 3600 # default global timeout for deployment a ns
128 timeout_ns_terminate = 1800 # default global timeout for un deployment a ns
garciadeblas07f4e4c2022-06-09 09:42:58 +0200129 timeout_ns_heal = 1800 # default global timeout for un deployment a ns
garciadeblasf9b04952019-04-09 18:53:58 +0200130 timeout_charm_delete = 10 * 60
David Garciaf6919842020-05-21 16:41:07 +0200131 timeout_primitive = 30 * 60 # timeout for primitive execution
aticigdffa6212022-04-12 15:27:53 +0300132 timeout_ns_update = 30 * 60 # timeout for ns update
garciadeblas5697b8b2021-03-24 09:17:02 +0100133 timeout_progress_primitive = (
134 10 * 60
135 ) # timeout for some progress in a primitive execution
elumalai80bcf1c2022-04-28 18:05:01 +0530136 timeout_migrate = 1800 # default global timeout for migrating vnfs
k4.rahulb827de92022-05-02 16:35:02 +0000137 timeout_operate = 1800 # default global timeout for migrating vnfs
preethika.p28b0bf82022-09-23 07:36:28 +0000138 timeout_verticalscale = 1800 # default global timeout for Vertical Sclaing
kuuseac3a8882019-10-03 10:48:06 +0200139 SUBOPERATION_STATUS_NOT_FOUND = -1
140 SUBOPERATION_STATUS_NEW = -2
141 SUBOPERATION_STATUS_SKIP = -3
tiernoa2143262020-03-27 16:20:40 +0000142 task_name_deploy_vca = "Deploying VCA"
kuuseac3a8882019-10-03 10:48:06 +0200143
bravof73bac502021-05-11 07:38:47 -0400144 def __init__(self, msg, lcm_tasks, config, loop):
tierno59d22d22018-09-25 18:10:19 +0200145 """
146 Init, Connect to database, filesystem storage, and messaging
147 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
148 :return: None
149 """
garciadeblas5697b8b2021-03-24 09:17:02 +0100150 super().__init__(msg=msg, logger=logging.getLogger("lcm.ns"))
quilesj7e13aeb2019-10-08 13:34:55 +0200151
bravof922c4172020-11-24 21:21:43 -0300152 self.db = Database().instance.db
153 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +0200154 self.loop = loop
155 self.lcm_tasks = lcm_tasks
tierno744303e2020-01-13 16:46:31 +0000156 self.timeout = config["timeout"]
157 self.ro_config = config["ro_config"]
tierno69f0d382020-05-07 13:08:09 +0000158 self.ng_ro = config["ro_config"].get("ng")
tierno744303e2020-01-13 16:46:31 +0000159 self.vca_config = config["VCA"].copy()
tierno59d22d22018-09-25 18:10:19 +0200160
quilesj7e13aeb2019-10-08 13:34:55 +0200161 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +0100162 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +0200163 log=self.logger,
quilesj7e13aeb2019-10-08 13:34:55 +0200164 loop=self.loop,
bravof922c4172020-11-24 21:21:43 -0300165 on_update_db=self._on_update_n2vc_db,
166 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100167 db=self.db,
tierno59d22d22018-09-25 18:10:19 +0200168 )
quilesj7e13aeb2019-10-08 13:34:55 +0200169
tierno588547c2020-07-01 15:30:20 +0000170 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000171 log=self.logger,
172 loop=self.loop,
tierno588547c2020-07-01 15:30:20 +0000173 vca_config=self.vca_config,
garciadeblas5697b8b2021-03-24 09:17:02 +0100174 on_update_db=self._on_update_n2vc_db,
tierno588547c2020-07-01 15:30:20 +0000175 )
176
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000177 self.k8sclusterhelm2 = K8sHelmConnector(
calvinosanch9f9c6f22019-11-04 13:37:39 +0100178 kubectl_command=self.vca_config.get("kubectlpath"),
179 helm_command=self.vca_config.get("helmpath"),
calvinosanch9f9c6f22019-11-04 13:37:39 +0100180 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100181 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300182 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100183 db=self.db,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100184 )
185
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000186 self.k8sclusterhelm3 = K8sHelm3Connector(
187 kubectl_command=self.vca_config.get("kubectlpath"),
188 helm_command=self.vca_config.get("helm3path"),
189 fs=self.fs,
190 log=self.logger,
191 db=self.db,
192 on_update_db=None,
193 )
194
Adam Israelbaacc302019-12-01 12:41:39 -0500195 self.k8sclusterjuju = K8sJujuConnector(
196 kubectl_command=self.vca_config.get("kubectlpath"),
197 juju_command=self.vca_config.get("jujupath"),
Adam Israelbaacc302019-12-01 12:41:39 -0500198 log=self.logger,
David Garciaba89cbb2020-10-16 13:05:34 +0200199 loop=self.loop,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530200 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300201 fs=self.fs,
garciadeblas5697b8b2021-03-24 09:17:02 +0100202 db=self.db,
Adam Israelbaacc302019-12-01 12:41:39 -0500203 )
204
tiernoa2143262020-03-27 16:20:40 +0000205 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000206 "helm-chart": self.k8sclusterhelm2,
207 "helm-chart-v3": self.k8sclusterhelm3,
208 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000209 "juju-bundle": self.k8sclusterjuju,
210 "juju": self.k8sclusterjuju,
211 }
tierno588547c2020-07-01 15:30:20 +0000212
213 self.vca_map = {
214 "lxc_proxy_charm": self.n2vc,
215 "native_charm": self.n2vc,
216 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000217 "helm": self.conn_helm_ee,
garciadeblas5697b8b2021-03-24 09:17:02 +0100218 "helm-v3": self.conn_helm_ee,
tierno588547c2020-07-01 15:30:20 +0000219 }
220
quilesj7e13aeb2019-10-08 13:34:55 +0200221 # create RO client
bravof922c4172020-11-24 21:21:43 -0300222 self.RO = NgRoClient(self.loop, **self.ro_config)
tierno59d22d22018-09-25 18:10:19 +0200223
garciadeblas07f4e4c2022-06-09 09:42:58 +0200224 self.op_status_map = {
225 "instantiation": self.RO.status,
226 "termination": self.RO.status,
227 "migrate": self.RO.status,
228 "healing": self.RO.recreate_status,
govindarajul12794ee2022-07-06 10:47:00 +0000229 "verticalscale": self.RO.status,
k4.rahul08cc70b2022-07-07 07:23:53 +0000230 "start_stop_rebuild": self.RO.status,
garciadeblas07f4e4c2022-06-09 09:42:58 +0200231 }
232
tierno2357f4e2020-10-19 16:38:59 +0000233 @staticmethod
234 def increment_ip_mac(ip_mac, vm_index=1):
235 if not isinstance(ip_mac, str):
236 return ip_mac
237 try:
238 # try with ipv4 look for last dot
239 i = ip_mac.rfind(".")
240 if i > 0:
241 i += 1
242 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
243 # try with ipv6 or mac look for last colon. Operate in hex
244 i = ip_mac.rfind(":")
245 if i > 0:
246 i += 1
247 # format in hex, len can be 2 for mac or 4 for ipv6
garciadeblas5697b8b2021-03-24 09:17:02 +0100248 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(
249 ip_mac[:i], int(ip_mac[i:], 16) + vm_index
250 )
tierno2357f4e2020-10-19 16:38:59 +0000251 except Exception:
252 pass
253 return None
254
quilesj3655ae02019-12-12 16:08:35 +0000255 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj7e13aeb2019-10-08 13:34:55 +0200256
quilesj3655ae02019-12-12 16:08:35 +0000257 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
258
259 try:
260 # TODO filter RO descriptor fields...
261
262 # write to database
263 db_dict = dict()
264 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
garciadeblas5697b8b2021-03-24 09:17:02 +0100265 db_dict["deploymentStatus"] = ro_descriptor
quilesj3655ae02019-12-12 16:08:35 +0000266 self.update_db_2("nsrs", nsrs_id, db_dict)
267
268 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100269 self.logger.warn(
270 "Cannot write database RO deployment for ns={} -> {}".format(nsrs_id, e)
271 )
quilesj3655ae02019-12-12 16:08:35 +0000272
David Garciac1fe90a2021-03-31 19:12:02 +0200273 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj3655ae02019-12-12 16:08:35 +0000274
quilesj69a722c2020-01-09 08:30:17 +0000275 # remove last dot from path (if exists)
garciadeblas5697b8b2021-03-24 09:17:02 +0100276 if path.endswith("."):
quilesj69a722c2020-01-09 08:30:17 +0000277 path = path[:-1]
278
quilesj3655ae02019-12-12 16:08:35 +0000279 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
280 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000281 try:
282
garciadeblas5697b8b2021-03-24 09:17:02 +0100283 nsr_id = filter.get("_id")
quilesj3655ae02019-12-12 16:08:35 +0000284
285 # read ns record from database
garciadeblas5697b8b2021-03-24 09:17:02 +0100286 nsr = self.db.get_one(table="nsrs", q_filter=filter)
287 current_ns_status = nsr.get("nsState")
quilesj3655ae02019-12-12 16:08:35 +0000288
289 # get vca status for NS
garciadeblas5697b8b2021-03-24 09:17:02 +0100290 status_dict = await self.n2vc.get_status(
291 namespace="." + nsr_id, yaml_format=False, vca_id=vca_id
292 )
quilesj3655ae02019-12-12 16:08:35 +0000293
294 # vcaStatus
295 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100296 db_dict["vcaStatus"] = status_dict
quilesj3655ae02019-12-12 16:08:35 +0000297
298 # update configurationStatus for this VCA
299 try:
garciadeblas5697b8b2021-03-24 09:17:02 +0100300 vca_index = int(path[path.rfind(".") + 1 :])
quilesj3655ae02019-12-12 16:08:35 +0000301
garciadeblas5697b8b2021-03-24 09:17:02 +0100302 vca_list = deep_get(
303 target_dict=nsr, key_list=("_admin", "deployed", "VCA")
304 )
305 vca_status = vca_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000306
garciadeblas5697b8b2021-03-24 09:17:02 +0100307 configuration_status_list = nsr.get("configurationStatus")
308 config_status = configuration_status_list[vca_index].get("status")
quilesj3655ae02019-12-12 16:08:35 +0000309
garciadeblas5697b8b2021-03-24 09:17:02 +0100310 if config_status == "BROKEN" and vca_status != "failed":
311 db_dict["configurationStatus"][vca_index] = "READY"
312 elif config_status != "BROKEN" and vca_status == "failed":
313 db_dict["configurationStatus"][vca_index] = "BROKEN"
quilesj3655ae02019-12-12 16:08:35 +0000314 except Exception as e:
315 # not update configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +0100316 self.logger.debug("Error updating vca_index (ignore): {}".format(e))
quilesj3655ae02019-12-12 16:08:35 +0000317
318 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
319 # if nsState = 'DEGRADED' check if all is OK
320 is_degraded = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100321 if current_ns_status in ("READY", "DEGRADED"):
322 error_description = ""
quilesj3655ae02019-12-12 16:08:35 +0000323 # check machines
garciadeblas5697b8b2021-03-24 09:17:02 +0100324 if status_dict.get("machines"):
325 for machine_id in status_dict.get("machines"):
326 machine = status_dict.get("machines").get(machine_id)
quilesj3655ae02019-12-12 16:08:35 +0000327 # check machine agent-status
garciadeblas5697b8b2021-03-24 09:17:02 +0100328 if machine.get("agent-status"):
329 s = machine.get("agent-status").get("status")
330 if s != "started":
quilesj3655ae02019-12-12 16:08:35 +0000331 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100332 error_description += (
333 "machine {} agent-status={} ; ".format(
334 machine_id, s
335 )
336 )
quilesj3655ae02019-12-12 16:08:35 +0000337 # check machine instance status
garciadeblas5697b8b2021-03-24 09:17:02 +0100338 if machine.get("instance-status"):
339 s = machine.get("instance-status").get("status")
340 if s != "running":
quilesj3655ae02019-12-12 16:08:35 +0000341 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100342 error_description += (
343 "machine {} instance-status={} ; ".format(
344 machine_id, s
345 )
346 )
quilesj3655ae02019-12-12 16:08:35 +0000347 # check applications
garciadeblas5697b8b2021-03-24 09:17:02 +0100348 if status_dict.get("applications"):
349 for app_id in status_dict.get("applications"):
350 app = status_dict.get("applications").get(app_id)
quilesj3655ae02019-12-12 16:08:35 +0000351 # check application status
garciadeblas5697b8b2021-03-24 09:17:02 +0100352 if app.get("status"):
353 s = app.get("status").get("status")
354 if s != "active":
quilesj3655ae02019-12-12 16:08:35 +0000355 is_degraded = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100356 error_description += (
357 "application {} status={} ; ".format(app_id, s)
358 )
quilesj3655ae02019-12-12 16:08:35 +0000359
360 if error_description:
garciadeblas5697b8b2021-03-24 09:17:02 +0100361 db_dict["errorDescription"] = error_description
362 if current_ns_status == "READY" and is_degraded:
363 db_dict["nsState"] = "DEGRADED"
364 if current_ns_status == "DEGRADED" and not is_degraded:
365 db_dict["nsState"] = "READY"
quilesj3655ae02019-12-12 16:08:35 +0000366
367 # write to database
368 self.update_db_2("nsrs", nsr_id, db_dict)
369
tierno51183952020-04-03 15:48:18 +0000370 except (asyncio.CancelledError, asyncio.TimeoutError):
371 raise
quilesj3655ae02019-12-12 16:08:35 +0000372 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100373 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200374
garciadeblas5697b8b2021-03-24 09:17:02 +0100375 async def _on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100376 self, cluster_uuid, kdu_instance, filter=None, vca_id=None, cluster_type="juju"
garciadeblas5697b8b2021-03-24 09:17:02 +0100377 ):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530378 """
379 Updating vca status in NSR record
380 :param cluster_uuid: UUID of a k8s cluster
381 :param kdu_instance: The unique name of the KDU instance
382 :param filter: To get nsr_id
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100383 :cluster_type: The cluster type (juju, k8s)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530384 :return: none
385 """
386
387 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
388 # .format(cluster_uuid, kdu_instance, filter))
389
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100390 nsr_id = filter.get("_id")
ksaikiranr656b6dd2021-02-19 10:25:18 +0530391 try:
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100392 vca_status = await self.k8scluster_map[cluster_type].status_kdu(
393 cluster_uuid=cluster_uuid,
394 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +0200395 yaml_format=False,
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100396 complete_status=True,
David Garciac1fe90a2021-03-31 19:12:02 +0200397 vca_id=vca_id,
398 )
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100399
ksaikiranr656b6dd2021-02-19 10:25:18 +0530400 # vcaStatus
401 db_dict = dict()
garciadeblas5697b8b2021-03-24 09:17:02 +0100402 db_dict["vcaStatus"] = {nsr_id: vca_status}
ksaikiranr656b6dd2021-02-19 10:25:18 +0530403
Pedro Escaleira75b620d2022-04-01 01:49:22 +0100404 self.logger.debug(
405 f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}"
David Garciac1fe90a2021-03-31 19:12:02 +0200406 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530407
408 # write to database
409 self.update_db_2("nsrs", nsr_id, db_dict)
ksaikiranr656b6dd2021-02-19 10:25:18 +0530410 except (asyncio.CancelledError, asyncio.TimeoutError):
411 raise
412 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100413 self.logger.warn("Error updating NS state for ns={}: {}".format(nsr_id, e))
ksaikiranr656b6dd2021-02-19 10:25:18 +0530414
tierno72ef84f2020-10-06 08:22:07 +0000415 @staticmethod
416 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
417 try:
garciadeblasef91e082022-08-02 15:12:18 +0200418 env = Environment(
preethika.p28b0bf82022-09-23 07:36:28 +0000419 undefined=StrictUndefined,
420 autoescape=select_autoescape(default_for_string=True, default=True),
421 )
tierno72ef84f2020-10-06 08:22:07 +0000422 template = env.from_string(cloud_init_text)
423 return template.render(additional_params or {})
424 except UndefinedError as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100425 raise LcmException(
426 "Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
427 "file, must be provided in the instantiation parameters inside the "
428 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id)
429 )
tierno72ef84f2020-10-06 08:22:07 +0000430 except (TemplateError, TemplateNotFound) as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100431 raise LcmException(
432 "Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".format(
433 vnfd_id, vdu_id, e
434 )
435 )
tierno72ef84f2020-10-06 08:22:07 +0000436
bravof922c4172020-11-24 21:21:43 -0300437 def _get_vdu_cloud_init_content(self, vdu, vnfd):
438 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000439 try:
tierno72ef84f2020-10-06 08:22:07 +0000440 if vdu.get("cloud-init-file"):
441 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -0300442 if base_folder["pkg-dir"]:
443 cloud_init_file = "{}/{}/cloud_init/{}".format(
444 base_folder["folder"],
445 base_folder["pkg-dir"],
446 vdu["cloud-init-file"],
447 )
448 else:
449 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
450 base_folder["folder"],
451 vdu["cloud-init-file"],
452 )
tierno72ef84f2020-10-06 08:22:07 +0000453 with self.fs.file_open(cloud_init_file, "r") as ci_file:
454 cloud_init_content = ci_file.read()
455 elif vdu.get("cloud-init"):
456 cloud_init_content = vdu["cloud-init"]
457
458 return cloud_init_content
459 except FsException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100460 raise LcmException(
461 "Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".format(
462 vnfd["id"], vdu["id"], cloud_init_file, e
463 )
464 )
tierno72ef84f2020-10-06 08:22:07 +0000465
tierno72ef84f2020-10-06 08:22:07 +0000466 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
garciadeblas5697b8b2021-03-24 09:17:02 +0100467 vdur = next(
aticig349aa462022-05-19 12:29:35 +0300468 (vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"]), {}
garciadeblas5697b8b2021-03-24 09:17:02 +0100469 )
tierno72ef84f2020-10-06 08:22:07 +0000470 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300471 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000472
gcalvino35be9152018-12-20 09:33:12 +0100473 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200474 """
475 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
476 :param vnfd: input vnfd
477 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000478 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100479 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200480 :return: copy of vnfd
481 """
tierno72ef84f2020-10-06 08:22:07 +0000482 vnfd_RO = deepcopy(vnfd)
483 # remove unused by RO configuration, monitoring, scaling and internal keys
484 vnfd_RO.pop("_id", None)
485 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000486 vnfd_RO.pop("monitoring-param", None)
487 vnfd_RO.pop("scaling-group-descriptor", None)
488 vnfd_RO.pop("kdu", None)
489 vnfd_RO.pop("k8s-cluster", None)
490 if new_id:
491 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000492
tierno72ef84f2020-10-06 08:22:07 +0000493 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
494 for vdu in get_iterable(vnfd_RO, "vdu"):
495 vdu.pop("cloud-init-file", None)
496 vdu.pop("cloud-init", None)
497 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200498
tierno2357f4e2020-10-19 16:38:59 +0000499 @staticmethod
500 def ip_profile_2_RO(ip_profile):
501 RO_ip_profile = deepcopy(ip_profile)
502 if "dns-server" in RO_ip_profile:
503 if isinstance(RO_ip_profile["dns-server"], list):
504 RO_ip_profile["dns-address"] = []
505 for ds in RO_ip_profile.pop("dns-server"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100506 RO_ip_profile["dns-address"].append(ds["address"])
tierno2357f4e2020-10-19 16:38:59 +0000507 else:
508 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
509 if RO_ip_profile.get("ip-version") == "ipv4":
510 RO_ip_profile["ip-version"] = "IPv4"
511 if RO_ip_profile.get("ip-version") == "ipv6":
512 RO_ip_profile["ip-version"] = "IPv6"
513 if "dhcp-params" in RO_ip_profile:
514 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
515 return RO_ip_profile
516
bravof922c4172020-11-24 21:21:43 -0300517 def _get_ro_vim_id_for_vim_account(self, vim_account):
518 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
519 if db_vim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100520 raise LcmException(
521 "VIM={} is not available. operationalState={}".format(
522 vim_account, db_vim["_admin"]["operationalState"]
523 )
524 )
bravof922c4172020-11-24 21:21:43 -0300525 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
526 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200527
bravof922c4172020-11-24 21:21:43 -0300528 def get_ro_wim_id_for_wim_account(self, wim_account):
529 if isinstance(wim_account, str):
530 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
531 if db_wim["_admin"]["operationalState"] != "ENABLED":
garciadeblas5697b8b2021-03-24 09:17:02 +0100532 raise LcmException(
533 "WIM={} is not available. operationalState={}".format(
534 wim_account, db_wim["_admin"]["operationalState"]
535 )
536 )
bravof922c4172020-11-24 21:21:43 -0300537 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
538 return RO_wim_id
539 else:
540 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200541
tierno2357f4e2020-10-19 16:38:59 +0000542 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno27246d82018-09-27 15:59:09 +0200543
tierno2357f4e2020-10-19 16:38:59 +0000544 db_vdu_push_list = []
vegall8d625f12022-03-22 16:23:30 +0000545 template_vdur = []
tierno2357f4e2020-10-19 16:38:59 +0000546 db_update = {"_admin.modified": time()}
547 if vdu_create:
548 for vdu_id, vdu_count in vdu_create.items():
garciadeblas5697b8b2021-03-24 09:17:02 +0100549 vdur = next(
550 (
551 vdur
552 for vdur in reversed(db_vnfr["vdur"])
553 if vdur["vdu-id-ref"] == vdu_id
554 ),
555 None,
556 )
tierno2357f4e2020-10-19 16:38:59 +0000557 if not vdur:
vegall8d625f12022-03-22 16:23:30 +0000558 # Read the template saved in the db:
aticig349aa462022-05-19 12:29:35 +0300559 self.logger.debug(
560 "No vdur in the database. Using the vdur-template to scale"
561 )
vegall8d625f12022-03-22 16:23:30 +0000562 vdur_template = db_vnfr.get("vdur-template")
563 if not vdur_template:
564 raise LcmException(
aticig349aa462022-05-19 12:29:35 +0300565 "Error scaling OUT VNFR for {}. No vnfr or template exists".format(
566 vdu_id
vegall8d625f12022-03-22 16:23:30 +0000567 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100568 )
vegall8d625f12022-03-22 16:23:30 +0000569 vdur = vdur_template[0]
aticig349aa462022-05-19 12:29:35 +0300570 # Delete a template from the database after using it
571 self.db.set_one(
572 "vnfrs",
573 {"_id": db_vnfr["_id"]},
574 None,
575 pull={"vdur-template": {"_id": vdur["_id"]}},
576 )
tierno2357f4e2020-10-19 16:38:59 +0000577 for count in range(vdu_count):
578 vdur_copy = deepcopy(vdur)
579 vdur_copy["status"] = "BUILD"
580 vdur_copy["status-detailed"] = None
Guillermo Calvino57c68152022-01-26 17:40:31 +0100581 vdur_copy["ip-address"] = None
tierno683eb392020-09-25 12:33:15 +0000582 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000583 vdur_copy["count-index"] += count + 1
garciadeblas5697b8b2021-03-24 09:17:02 +0100584 vdur_copy["id"] = "{}-{}".format(
585 vdur_copy["vdu-id-ref"], vdur_copy["count-index"]
586 )
tierno2357f4e2020-10-19 16:38:59 +0000587 vdur_copy.pop("vim_info", None)
588 for iface in vdur_copy["interfaces"]:
589 if iface.get("fixed-ip"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100590 iface["ip-address"] = self.increment_ip_mac(
591 iface["ip-address"], count + 1
592 )
tierno2357f4e2020-10-19 16:38:59 +0000593 else:
594 iface.pop("ip-address", None)
595 if iface.get("fixed-mac"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100596 iface["mac-address"] = self.increment_ip_mac(
597 iface["mac-address"], count + 1
598 )
tierno2357f4e2020-10-19 16:38:59 +0000599 else:
600 iface.pop("mac-address", None)
vegall8d625f12022-03-22 16:23:30 +0000601 if db_vnfr["vdur"]:
602 iface.pop(
603 "mgmt_vnf", None
604 ) # only first vdu can be managment of vnf
tierno2357f4e2020-10-19 16:38:59 +0000605 db_vdu_push_list.append(vdur_copy)
606 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200607 if vdu_delete:
vegall8d625f12022-03-22 16:23:30 +0000608 if len(db_vnfr["vdur"]) == 1:
609 # The scale will move to 0 instances
aticig349aa462022-05-19 12:29:35 +0300610 self.logger.debug(
611 "Scaling to 0 !, creating the template with the last vdur"
612 )
vegall8d625f12022-03-22 16:23:30 +0000613 template_vdur = [db_vnfr["vdur"][0]]
tierno2357f4e2020-10-19 16:38:59 +0000614 for vdu_id, vdu_count in vdu_delete.items():
615 if mark_delete:
garciadeblas5697b8b2021-03-24 09:17:02 +0100616 indexes_to_delete = [
617 iv[0]
618 for iv in enumerate(db_vnfr["vdur"])
619 if iv[1]["vdu-id-ref"] == vdu_id
620 ]
621 db_update.update(
622 {
623 "vdur.{}.status".format(i): "DELETING"
624 for i in indexes_to_delete[-vdu_count:]
625 }
626 )
tierno2357f4e2020-10-19 16:38:59 +0000627 else:
628 # it must be deleted one by one because common.db does not allow otherwise
garciadeblas5697b8b2021-03-24 09:17:02 +0100629 vdus_to_delete = [
630 v
631 for v in reversed(db_vnfr["vdur"])
632 if v["vdu-id-ref"] == vdu_id
633 ]
tierno2357f4e2020-10-19 16:38:59 +0000634 for vdu in vdus_to_delete[:vdu_count]:
garciadeblas5697b8b2021-03-24 09:17:02 +0100635 self.db.set_one(
636 "vnfrs",
637 {"_id": db_vnfr["_id"]},
638 None,
639 pull={"vdur": {"_id": vdu["_id"]}},
640 )
vegall8d625f12022-03-22 16:23:30 +0000641 db_push = {}
642 if db_vdu_push_list:
643 db_push["vdur"] = db_vdu_push_list
644 if template_vdur:
645 db_push["vdur-template"] = template_vdur
646 if not db_push:
647 db_push = None
648 db_vnfr["vdur-template"] = template_vdur
tierno2357f4e2020-10-19 16:38:59 +0000649 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
650 # modify passed dictionary db_vnfr
651 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
652 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200653
tiernof578e552018-11-08 19:07:20 +0100654 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
655 """
656 Updates database nsr with the RO info for the created vld
657 :param ns_update_nsr: dictionary to be filled with the updated info
658 :param db_nsr: content of db_nsr. This is also modified
659 :param nsr_desc_RO: nsr descriptor from RO
660 :return: Nothing, LcmException is raised on errors
661 """
662
663 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
664 for net_RO in get_iterable(nsr_desc_RO, "nets"):
665 if vld["id"] != net_RO.get("ns_net_osm_id"):
666 continue
667 vld["vim-id"] = net_RO.get("vim_net_id")
668 vld["name"] = net_RO.get("vim_name")
669 vld["status"] = net_RO.get("status")
670 vld["status-detailed"] = net_RO.get("error_msg")
671 ns_update_nsr["vld.{}".format(vld_index)] = vld
672 break
673 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100674 raise LcmException(
675 "ns_update_nsr: Not found vld={} at RO info".format(vld["id"])
676 )
tiernof578e552018-11-08 19:07:20 +0100677
tiernoe876f672020-02-13 14:34:48 +0000678 def set_vnfr_at_error(self, db_vnfrs, error_text):
679 try:
680 for db_vnfr in db_vnfrs.values():
681 vnfr_update = {"status": "ERROR"}
682 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
683 if "status" not in vdur:
684 vdur["status"] = "ERROR"
685 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
686 if error_text:
687 vdur["status-detailed"] = str(error_text)
garciadeblas5697b8b2021-03-24 09:17:02 +0100688 vnfr_update[
689 "vdur.{}.status-detailed".format(vdu_index)
690 ] = "ERROR"
tiernoe876f672020-02-13 14:34:48 +0000691 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
692 except DbException as e:
693 self.logger.error("Cannot update vnf. {}".format(e))
694
tierno59d22d22018-09-25 18:10:19 +0200695 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
696 """
697 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 +0200698 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
699 :param nsr_desc_RO: nsr descriptor from RO
700 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200701 """
702 for vnf_index, db_vnfr in db_vnfrs.items():
703 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200704 if vnf_RO["member_vnf_index"] != vnf_index:
705 continue
706 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100707 if vnf_RO.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100708 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO[
709 "ip_address"
710 ].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100711 elif not db_vnfr.get("ip-address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100712 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
713 raise LcmExceptionNoMgmtIP(
714 "ns member_vnf_index '{}' has no IP address".format(
715 vnf_index
716 )
717 )
tierno59d22d22018-09-25 18:10:19 +0200718
tierno27246d82018-09-27 15:59:09 +0200719 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
720 vdur_RO_count_index = 0
721 if vdur.get("pdu-type"):
722 continue
723 for vdur_RO in get_iterable(vnf_RO, "vms"):
724 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
725 continue
726 if vdur["count-index"] != vdur_RO_count_index:
727 vdur_RO_count_index += 1
728 continue
729 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000730 if vdur_RO.get("ip_address"):
731 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000732 else:
733 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200734 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
735 vdur["name"] = vdur_RO.get("vim_name")
736 vdur["status"] = vdur_RO.get("status")
737 vdur["status-detailed"] = vdur_RO.get("error_msg")
738 for ifacer in get_iterable(vdur, "interfaces"):
739 for interface_RO in get_iterable(vdur_RO, "interfaces"):
740 if ifacer["name"] == interface_RO.get("internal_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100741 ifacer["ip-address"] = interface_RO.get(
742 "ip_address"
743 )
744 ifacer["mac-address"] = interface_RO.get(
745 "mac_address"
746 )
tierno27246d82018-09-27 15:59:09 +0200747 break
748 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100749 raise LcmException(
750 "ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
751 "from VIM info".format(
752 vnf_index, vdur["vdu-id-ref"], ifacer["name"]
753 )
754 )
tierno27246d82018-09-27 15:59:09 +0200755 vnfr_update["vdur.{}".format(vdu_index)] = vdur
756 break
757 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100758 raise LcmException(
759 "ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
760 "VIM info".format(
761 vnf_index, vdur["vdu-id-ref"], vdur["count-index"]
762 )
763 )
tiernof578e552018-11-08 19:07:20 +0100764
765 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
766 for net_RO in get_iterable(nsr_desc_RO, "nets"):
767 if vld["id"] != net_RO.get("vnf_net_osm_id"):
768 continue
769 vld["vim-id"] = net_RO.get("vim_net_id")
770 vld["name"] = net_RO.get("vim_name")
771 vld["status"] = net_RO.get("status")
772 vld["status-detailed"] = net_RO.get("error_msg")
773 vnfr_update["vld.{}".format(vld_index)] = vld
774 break
775 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100776 raise LcmException(
777 "ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
778 vnf_index, vld["id"]
779 )
780 )
tiernof578e552018-11-08 19:07:20 +0100781
tierno27246d82018-09-27 15:59:09 +0200782 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
783 break
tierno59d22d22018-09-25 18:10:19 +0200784
785 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100786 raise LcmException(
787 "ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(
788 vnf_index
789 )
790 )
tierno59d22d22018-09-25 18:10:19 +0200791
tierno5ee02052019-12-05 19:55:02 +0000792 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000793 """
794 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000795 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000796 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
797 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
798 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
799 """
tierno5ee02052019-12-05 19:55:02 +0000800 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
801 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000802 mapping = {}
803 ns_config_info = {"osm-config-mapping": mapping}
804 for vca in vca_deployed_list:
805 if not vca["member-vnf-index"]:
806 continue
807 if not vca["vdu_id"]:
808 mapping[vca["member-vnf-index"]] = vca["application"]
809 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100810 mapping[
811 "{}.{}.{}".format(
812 vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"]
813 )
814 ] = vca["application"]
tiernoc3f2a822019-11-05 13:45:04 +0000815 return ns_config_info
816
garciadeblas5697b8b2021-03-24 09:17:02 +0100817 async def _instantiate_ng_ro(
818 self,
819 logging_text,
820 nsr_id,
821 nsd,
822 db_nsr,
823 db_nslcmop,
824 db_vnfrs,
825 db_vnfds,
826 n2vc_key_list,
827 stage,
828 start_deploy,
829 timeout_ns_deploy,
830 ):
tierno2357f4e2020-10-19 16:38:59 +0000831
832 db_vims = {}
833
834 def get_vim_account(vim_account_id):
835 nonlocal db_vims
836 if vim_account_id in db_vims:
837 return db_vims[vim_account_id]
838 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
839 db_vims[vim_account_id] = db_vim
840 return db_vim
841
842 # modify target_vld info with instantiation parameters
garciadeblas5697b8b2021-03-24 09:17:02 +0100843 def parse_vld_instantiation_params(
844 target_vim, target_vld, vld_params, target_sdn
845 ):
tierno2357f4e2020-10-19 16:38:59 +0000846 if vld_params.get("ip-profile"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100847 target_vld["vim_info"][target_vim]["ip_profile"] = vld_params[
848 "ip-profile"
849 ]
tierno2357f4e2020-10-19 16:38:59 +0000850 if vld_params.get("provider-network"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100851 target_vld["vim_info"][target_vim]["provider_network"] = vld_params[
852 "provider-network"
853 ]
tierno2357f4e2020-10-19 16:38:59 +0000854 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
garciadeblas5697b8b2021-03-24 09:17:02 +0100855 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
856 "provider-network"
857 ]["sdn-ports"]
tierno2357f4e2020-10-19 16:38:59 +0000858 if vld_params.get("wimAccountId"):
859 target_wim = "wim:{}".format(vld_params["wimAccountId"])
860 target_vld["vim_info"][target_wim] = {}
861 for param in ("vim-network-name", "vim-network-id"):
862 if vld_params.get(param):
863 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300864 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300865 other_target_vim = "vim:" + vim
garciadeblas5697b8b2021-03-24 09:17:02 +0100866 populate_dict(
867 target_vld["vim_info"],
868 (other_target_vim, param.replace("-", "_")),
869 vim_net,
870 )
tierno2357f4e2020-10-19 16:38:59 +0000871 else: # isinstance str
garciadeblas5697b8b2021-03-24 09:17:02 +0100872 target_vld["vim_info"][target_vim][
873 param.replace("-", "_")
874 ] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300875 if vld_params.get("common_id"):
876 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000877
aticig15db6142022-01-24 12:51:26 +0300878 # modify target["ns"]["vld"] with instantiation parameters to override vnf vim-account
879 def update_ns_vld_target(target, ns_params):
880 for vnf_params in ns_params.get("vnf", ()):
881 if vnf_params.get("vimAccountId"):
882 target_vnf = next(
883 (
884 vnfr
885 for vnfr in db_vnfrs.values()
886 if vnf_params["member-vnf-index"]
887 == vnfr["member-vnf-index-ref"]
888 ),
889 None,
890 )
891 vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
892 for a_index, a_vld in enumerate(target["ns"]["vld"]):
893 target_vld = find_in_list(
894 get_iterable(vdur, "interfaces"),
895 lambda iface: iface.get("ns-vld-id") == a_vld["name"],
896 )
aticig84bd9a72022-06-14 03:01:36 +0300897
898 vld_params = find_in_list(
899 get_iterable(ns_params, "vld"),
900 lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
901 )
aticig15db6142022-01-24 12:51:26 +0300902 if target_vld:
aticig84bd9a72022-06-14 03:01:36 +0300903
aticig15db6142022-01-24 12:51:26 +0300904 if vnf_params.get("vimAccountId") not in a_vld.get(
905 "vim_info", {}
906 ):
aticig84bd9a72022-06-14 03:01:36 +0300907 target_vim_network_list = [
908 v for _, v in a_vld.get("vim_info").items()
909 ]
910 target_vim_network_name = next(
911 (
912 item.get("vim_network_name", "")
913 for item in target_vim_network_list
914 ),
915 "",
916 )
917
aticig15db6142022-01-24 12:51:26 +0300918 target["ns"]["vld"][a_index].get("vim_info").update(
919 {
920 "vim:{}".format(vnf_params["vimAccountId"]): {
aticig84bd9a72022-06-14 03:01:36 +0300921 "vim_network_name": target_vim_network_name,
aticig15db6142022-01-24 12:51:26 +0300922 }
923 }
924 )
925
aticig84bd9a72022-06-14 03:01:36 +0300926 if vld_params:
927 for param in ("vim-network-name", "vim-network-id"):
928 if vld_params.get(param) and isinstance(
929 vld_params[param], dict
930 ):
931 for vim, vim_net in vld_params[
932 param
933 ].items():
934 other_target_vim = "vim:" + vim
935 populate_dict(
936 target["ns"]["vld"][a_index].get(
937 "vim_info"
938 ),
939 (
940 other_target_vim,
941 param.replace("-", "_"),
942 ),
943 vim_net,
944 )
945
tierno69f0d382020-05-07 13:08:09 +0000946 nslcmop_id = db_nslcmop["_id"]
947 target = {
948 "name": db_nsr["name"],
949 "ns": {"vld": []},
950 "vnf": [],
951 "image": deepcopy(db_nsr["image"]),
952 "flavor": deepcopy(db_nsr["flavor"]),
953 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000954 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000955 }
956 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000957 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000958 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000959 flavor["vim_info"] = {}
Alexis Romero305b5c42022-03-11 15:29:18 +0100960 if db_nsr.get("affinity-or-anti-affinity-group"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +0100961 target["affinity-or-anti-affinity-group"] = deepcopy(
962 db_nsr["affinity-or-anti-affinity-group"]
963 )
964 for affinity_or_anti_affinity_group in target[
965 "affinity-or-anti-affinity-group"
966 ]:
Alexis Romero305b5c42022-03-11 15:29:18 +0100967 affinity_or_anti_affinity_group["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000968
tierno2357f4e2020-10-19 16:38:59 +0000969 if db_nslcmop.get("lcmOperationType") != "instantiate":
970 # get parameters of instantiation:
garciadeblas5697b8b2021-03-24 09:17:02 +0100971 db_nslcmop_instantiate = self.db.get_list(
972 "nslcmops",
973 {
974 "nsInstanceId": db_nslcmop["nsInstanceId"],
975 "lcmOperationType": "instantiate",
976 },
977 )[-1]
tierno2357f4e2020-10-19 16:38:59 +0000978 ns_params = db_nslcmop_instantiate.get("operationParams")
979 else:
980 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300981 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
982 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000983
984 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000985 for vld_index, vld in enumerate(db_nsr.get("vld")):
986 target_vim = "vim:{}".format(ns_params["vimAccountId"])
987 target_vld = {
988 "id": vld["id"],
989 "name": vld["name"],
990 "mgmt-network": vld.get("mgmt-network", False),
991 "type": vld.get("type"),
992 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300993 target_vim: {
994 "vim_network_name": vld.get("vim-network-name"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100995 "vim_account_id": ns_params["vimAccountId"],
bravof922c4172020-11-24 21:21:43 -0300996 }
garciadeblas5697b8b2021-03-24 09:17:02 +0100997 },
tierno2357f4e2020-10-19 16:38:59 +0000998 }
999 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +00001000 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +00001001 db_vim = get_vim_account(ns_params["vimAccountId"])
tierno2357f4e2020-10-19 16:38:59 +00001002 sdnc_id = db_vim["config"].get("sdn-controller")
1003 if sdnc_id:
garciadeblasa5ae90b2021-02-12 11:26:46 +00001004 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
1005 target_sdn = "sdn:{}".format(sdnc_id)
1006 target_vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001007 "sdn": True,
1008 "target_vim": target_vim,
1009 "vlds": [sdn_vld],
1010 "type": vld.get("type"),
1011 }
tierno2357f4e2020-10-19 16:38:59 +00001012
bravof922c4172020-11-24 21:21:43 -03001013 nsd_vnf_profiles = get_vnf_profiles(nsd)
1014 for nsd_vnf_profile in nsd_vnf_profiles:
1015 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
1016 if cp["virtual-link-profile-id"] == vld["id"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01001017 cp2target[
1018 "member_vnf:{}.{}".format(
1019 cp["constituent-cpd-id"][0][
1020 "constituent-base-element-id"
1021 ],
1022 cp["constituent-cpd-id"][0]["constituent-cpd-id"],
1023 )
1024 ] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +00001025
1026 # check at nsd descriptor, if there is an ip-profile
1027 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +00001028 nsd_vlp = find_in_list(
1029 get_virtual_link_profiles(nsd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001030 lambda a_link_profile: a_link_profile["virtual-link-desc-id"]
1031 == vld["id"],
1032 )
1033 if (
1034 nsd_vlp
1035 and nsd_vlp.get("virtual-link-protocol-data")
1036 and nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1037 ):
1038 ip_profile_source_data = nsd_vlp["virtual-link-protocol-data"][
1039 "l3-protocol-data"
1040 ]
lloretgalleg19008482021-04-19 11:40:18 +00001041 ip_profile_dest_data = {}
1042 if "ip-version" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001043 ip_profile_dest_data["ip-version"] = ip_profile_source_data[
1044 "ip-version"
1045 ]
lloretgalleg19008482021-04-19 11:40:18 +00001046 if "cidr" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001047 ip_profile_dest_data["subnet-address"] = ip_profile_source_data[
1048 "cidr"
1049 ]
lloretgalleg19008482021-04-19 11:40:18 +00001050 if "gateway-ip" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001051 ip_profile_dest_data["gateway-address"] = ip_profile_source_data[
1052 "gateway-ip"
1053 ]
lloretgalleg19008482021-04-19 11:40:18 +00001054 if "dhcp-enabled" in ip_profile_source_data:
1055 ip_profile_dest_data["dhcp-params"] = {
1056 "enabled": ip_profile_source_data["dhcp-enabled"]
1057 }
1058 vld_params["ip-profile"] = ip_profile_dest_data
bravof922c4172020-11-24 21:21:43 -03001059
tierno2357f4e2020-10-19 16:38:59 +00001060 # update vld_params with instantiation params
garciadeblas5697b8b2021-03-24 09:17:02 +01001061 vld_instantiation_params = find_in_list(
1062 get_iterable(ns_params, "vld"),
1063 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]),
1064 )
tierno2357f4e2020-10-19 16:38:59 +00001065 if vld_instantiation_params:
1066 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -03001067 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +00001068 target["ns"]["vld"].append(target_vld)
aticig15db6142022-01-24 12:51:26 +03001069 # Update the target ns_vld if vnf vim_account is overriden by instantiation params
1070 update_ns_vld_target(target, ns_params)
bravof922c4172020-11-24 21:21:43 -03001071
tierno69f0d382020-05-07 13:08:09 +00001072 for vnfr in db_vnfrs.values():
garciadeblas5697b8b2021-03-24 09:17:02 +01001073 vnfd = find_in_list(
1074 db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"]
1075 )
1076 vnf_params = find_in_list(
1077 get_iterable(ns_params, "vnf"),
1078 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"],
1079 )
tierno69f0d382020-05-07 13:08:09 +00001080 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +00001081 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +00001082 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +00001083 # check if connected to a ns.vld, to fill target'
garciadeblas5697b8b2021-03-24 09:17:02 +01001084 vnf_cp = find_in_list(
1085 vnfd.get("int-virtual-link-desc", ()),
1086 lambda cpd: cpd.get("id") == vld["id"],
1087 )
tierno69f0d382020-05-07 13:08:09 +00001088 if vnf_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01001089 ns_cp = "member_vnf:{}.{}".format(
1090 vnfr["member-vnf-index-ref"], vnf_cp["id"]
1091 )
tierno69f0d382020-05-07 13:08:09 +00001092 if cp2target.get(ns_cp):
1093 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -03001094
garciadeblas5697b8b2021-03-24 09:17:02 +01001095 vld["vim_info"] = {
1096 target_vim: {"vim_network_name": vld.get("vim-network-name")}
1097 }
tierno2357f4e2020-10-19 16:38:59 +00001098 # check if this network needs SDN assist
1099 target_sdn = None
1100 if vld.get("pci-interfaces"):
1101 db_vim = get_vim_account(vnfr["vim-account-id"])
1102 sdnc_id = db_vim["config"].get("sdn-controller")
1103 if sdnc_id:
1104 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
1105 target_sdn = "sdn:{}".format(sdnc_id)
1106 vld["vim_info"][target_sdn] = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001107 "sdn": True,
1108 "target_vim": target_vim,
1109 "vlds": [sdn_vld],
1110 "type": vld.get("type"),
1111 }
tierno69f0d382020-05-07 13:08:09 +00001112
tierno2357f4e2020-10-19 16:38:59 +00001113 # check at vnfd descriptor, if there is an ip-profile
1114 vld_params = {}
bravof922c4172020-11-24 21:21:43 -03001115 vnfd_vlp = find_in_list(
1116 get_virtual_link_profiles(vnfd),
garciadeblas5697b8b2021-03-24 09:17:02 +01001117 lambda a_link_profile: a_link_profile["id"] == vld["id"],
bravof922c4172020-11-24 21:21:43 -03001118 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001119 if (
1120 vnfd_vlp
1121 and vnfd_vlp.get("virtual-link-protocol-data")
1122 and vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data")
1123 ):
1124 ip_profile_source_data = vnfd_vlp["virtual-link-protocol-data"][
1125 "l3-protocol-data"
1126 ]
bravof922c4172020-11-24 21:21:43 -03001127 ip_profile_dest_data = {}
1128 if "ip-version" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001129 ip_profile_dest_data["ip-version"] = ip_profile_source_data[
1130 "ip-version"
1131 ]
bravof922c4172020-11-24 21:21:43 -03001132 if "cidr" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001133 ip_profile_dest_data["subnet-address"] = ip_profile_source_data[
1134 "cidr"
1135 ]
bravof922c4172020-11-24 21:21:43 -03001136 if "gateway-ip" in ip_profile_source_data:
garciadeblas5697b8b2021-03-24 09:17:02 +01001137 ip_profile_dest_data[
1138 "gateway-address"
1139 ] = ip_profile_source_data["gateway-ip"]
bravof922c4172020-11-24 21:21:43 -03001140 if "dhcp-enabled" in ip_profile_source_data:
1141 ip_profile_dest_data["dhcp-params"] = {
1142 "enabled": ip_profile_source_data["dhcp-enabled"]
1143 }
1144
1145 vld_params["ip-profile"] = ip_profile_dest_data
tierno2357f4e2020-10-19 16:38:59 +00001146 # update vld_params with instantiation params
1147 if vnf_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01001148 vld_instantiation_params = find_in_list(
1149 get_iterable(vnf_params, "internal-vld"),
1150 lambda i_vld: i_vld["name"] == vld["id"],
1151 )
tierno2357f4e2020-10-19 16:38:59 +00001152 if vld_instantiation_params:
1153 vld_params.update(vld_instantiation_params)
1154 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
1155
1156 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +00001157 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +00001158 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
1159 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -03001160 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +00001161
bravof922c4172020-11-24 21:21:43 -03001162 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
1163
1164 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -03001165 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
1166 vnf_configuration = get_configuration(vnfd, vnfd["id"])
garciadeblas5697b8b2021-03-24 09:17:02 +01001167 if (
1168 vdu_configuration
1169 and vdu_configuration.get("config-access")
1170 and vdu_configuration.get("config-access").get("ssh-access")
1171 ):
bravof922c4172020-11-24 21:21:43 -03001172 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001173 vdur["ssh-access-required"] = vdu_configuration[
1174 "config-access"
1175 ]["ssh-access"]["required"]
1176 elif (
1177 vnf_configuration
1178 and vnf_configuration.get("config-access")
1179 and vnf_configuration.get("config-access").get("ssh-access")
1180 and any(iface.get("mgmt-vnf") for iface in vdur["interfaces"])
1181 ):
bravof922c4172020-11-24 21:21:43 -03001182 vdur["ssh-keys"] = ssh_keys_all
garciadeblas5697b8b2021-03-24 09:17:02 +01001183 vdur["ssh-access-required"] = vnf_configuration[
1184 "config-access"
1185 ]["ssh-access"]["required"]
1186 elif ssh_keys_instantiation and find_in_list(
1187 vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")
1188 ):
bravof922c4172020-11-24 21:21:43 -03001189 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +00001190
bravof922c4172020-11-24 21:21:43 -03001191 self.logger.debug("NS > vdur > {}".format(vdur))
1192
1193 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +00001194 # cloud-init
1195 if vdud.get("cloud-init-file"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001196 vdur["cloud-init"] = "{}:file:{}".format(
1197 vnfd["_id"], vdud.get("cloud-init-file")
1198 )
tierno2357f4e2020-10-19 16:38:59 +00001199 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
1200 if vdur["cloud-init"] not in target["cloud_init_content"]:
1201 base_folder = vnfd["_admin"]["storage"]
bravof486707f2021-11-08 17:18:50 -03001202 if base_folder["pkg-dir"]:
1203 cloud_init_file = "{}/{}/cloud_init/{}".format(
1204 base_folder["folder"],
1205 base_folder["pkg-dir"],
1206 vdud.get("cloud-init-file"),
1207 )
1208 else:
1209 cloud_init_file = "{}/Scripts/cloud_init/{}".format(
1210 base_folder["folder"],
1211 vdud.get("cloud-init-file"),
1212 )
tierno2357f4e2020-10-19 16:38:59 +00001213 with self.fs.file_open(cloud_init_file, "r") as ci_file:
garciadeblas5697b8b2021-03-24 09:17:02 +01001214 target["cloud_init_content"][
1215 vdur["cloud-init"]
1216 ] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +00001217 elif vdud.get("cloud-init"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001218 vdur["cloud-init"] = "{}:vdu:{}".format(
1219 vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"])
1220 )
tierno2357f4e2020-10-19 16:38:59 +00001221 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
garciadeblas5697b8b2021-03-24 09:17:02 +01001222 target["cloud_init_content"][vdur["cloud-init"]] = vdud[
1223 "cloud-init"
1224 ]
tierno2357f4e2020-10-19 16:38:59 +00001225 vdur["additionalParams"] = vdur.get("additionalParams") or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01001226 deploy_params_vdu = self._format_additional_params(
1227 vdur.get("additionalParams") or {}
1228 )
1229 deploy_params_vdu["OSM"] = get_osm_params(
1230 vnfr, vdur["vdu-id-ref"], vdur["count-index"]
1231 )
tierno2357f4e2020-10-19 16:38:59 +00001232 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +00001233
1234 # flavor
1235 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +00001236 if target_vim not in ns_flavor["vim_info"]:
1237 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +00001238
1239 # deal with images
1240 # in case alternative images are provided we must check if they should be applied
1241 # for the vim_type, modify the vim_type taking into account
1242 ns_image_id = int(vdur["ns-image-id"])
1243 if vdur.get("alt-image-ids"):
1244 db_vim = get_vim_account(vnfr["vim-account-id"])
1245 vim_type = db_vim["vim_type"]
1246 for alt_image_id in vdur.get("alt-image-ids"):
1247 ns_alt_image = target["image"][int(alt_image_id)]
1248 if vim_type == ns_alt_image.get("vim-type"):
1249 # must use alternative image
garciadeblas5697b8b2021-03-24 09:17:02 +01001250 self.logger.debug(
1251 "use alternative image id: {}".format(alt_image_id)
1252 )
lloretgalleg7dc94672021-02-08 11:49:50 +00001253 ns_image_id = alt_image_id
1254 vdur["ns-image-id"] = ns_image_id
1255 break
1256 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +00001257 if target_vim not in ns_image["vim_info"]:
1258 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +00001259
Alexis Romero305b5c42022-03-11 15:29:18 +01001260 # Affinity groups
1261 if vdur.get("affinity-or-anti-affinity-group-id"):
1262 for ags_id in vdur["affinity-or-anti-affinity-group-id"]:
1263 ns_ags = target["affinity-or-anti-affinity-group"][int(ags_id)]
1264 if target_vim not in ns_ags["vim_info"]:
1265 ns_ags["vim_info"][target_vim] = {}
1266
tierno2357f4e2020-10-19 16:38:59 +00001267 vdur["vim_info"] = {target_vim: {}}
1268 # instantiation parameters
aticig349aa462022-05-19 12:29:35 +03001269 if vnf_params:
1270 vdu_instantiation_params = find_in_list(
1271 get_iterable(vnf_params, "vdu"),
1272 lambda i_vdu: i_vdu["id"] == vdud["id"],
1273 )
1274 if vdu_instantiation_params:
1275 # Parse the vdu_volumes from the instantiation params
1276 vdu_volumes = get_volumes_from_instantiation_params(
1277 vdu_instantiation_params, vdud
1278 )
1279 vdur["additionalParams"]["OSM"]["vdu_volumes"] = vdu_volumes
tierno2357f4e2020-10-19 16:38:59 +00001280 vdur_list.append(vdur)
1281 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +00001282 target["vnf"].append(target_vnf)
1283
garciadeblas07f4e4c2022-06-09 09:42:58 +02001284 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
tierno69f0d382020-05-07 13:08:09 +00001285 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -03001286 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +00001287 action_id = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01001288 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001289 nsr_id,
1290 action_id,
1291 nslcmop_id,
1292 start_deploy,
1293 timeout_ns_deploy,
1294 stage,
1295 operation="instantiation",
garciadeblas5697b8b2021-03-24 09:17:02 +01001296 )
tierno69f0d382020-05-07 13:08:09 +00001297
1298 # Updating NSR
1299 db_nsr_update = {
1300 "_admin.deployed.RO.operational-status": "running",
garciadeblas5697b8b2021-03-24 09:17:02 +01001301 "detailed-status": " ".join(stage),
tierno69f0d382020-05-07 13:08:09 +00001302 }
1303 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
1304 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1305 self._write_op_status(nslcmop_id, stage)
garciadeblas5697b8b2021-03-24 09:17:02 +01001306 self.logger.debug(
1307 logging_text + "ns deployed at RO. RO_id={}".format(action_id)
1308 )
tierno69f0d382020-05-07 13:08:09 +00001309 return
1310
garciadeblas5697b8b2021-03-24 09:17:02 +01001311 async def _wait_ng_ro(
1312 self,
1313 nsr_id,
1314 action_id,
1315 nslcmop_id=None,
1316 start_time=None,
1317 timeout=600,
1318 stage=None,
garciadeblas07f4e4c2022-06-09 09:42:58 +02001319 operation=None,
garciadeblas5697b8b2021-03-24 09:17:02 +01001320 ):
tierno69f0d382020-05-07 13:08:09 +00001321 detailed_status_old = None
1322 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +00001323 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +00001324 while time() <= start_time + timeout:
garciadeblas07f4e4c2022-06-09 09:42:58 +02001325 desc_status = await self.op_status_map[operation](nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -03001326 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +00001327 if desc_status["status"] == "FAILED":
1328 raise NgRoException(desc_status["details"])
1329 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +00001330 if stage:
1331 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +00001332 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +00001333 if stage:
1334 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +00001335 break
1336 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001337 assert False, "ROclient.check_ns_status returns unknown {}".format(
1338 desc_status["status"]
1339 )
tierno2357f4e2020-10-19 16:38:59 +00001340 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +00001341 detailed_status_old = stage[2]
1342 db_nsr_update["detailed-status"] = " ".join(stage)
1343 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1344 self._write_op_status(nslcmop_id, stage)
bravof922c4172020-11-24 21:21:43 -03001345 await asyncio.sleep(15, loop=self.loop)
tierno69f0d382020-05-07 13:08:09 +00001346 else: # timeout_ns_deploy
1347 raise NgRoException("Timeout waiting ns to deploy")
1348
garciadeblas5697b8b2021-03-24 09:17:02 +01001349 async def _terminate_ng_ro(
1350 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
1351 ):
tierno69f0d382020-05-07 13:08:09 +00001352 db_nsr_update = {}
1353 failed_detail = []
1354 action_id = None
1355 start_deploy = time()
1356 try:
1357 target = {
1358 "ns": {"vld": []},
1359 "vnf": [],
1360 "image": [],
1361 "flavor": [],
garciadeblas5697b8b2021-03-24 09:17:02 +01001362 "action_id": nslcmop_id,
tierno69f0d382020-05-07 13:08:09 +00001363 }
1364 desc = await self.RO.deploy(nsr_id, target)
1365 action_id = desc["action_id"]
1366 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = action_id
1367 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
garciadeblas5697b8b2021-03-24 09:17:02 +01001368 self.logger.debug(
1369 logging_text
1370 + "ns terminate action at RO. action_id={}".format(action_id)
1371 )
tierno69f0d382020-05-07 13:08:09 +00001372
1373 # wait until done
1374 delete_timeout = 20 * 60 # 20 minutes
garciadeblas5697b8b2021-03-24 09:17:02 +01001375 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00001376 nsr_id,
1377 action_id,
1378 nslcmop_id,
1379 start_deploy,
1380 delete_timeout,
1381 stage,
1382 operation="termination",
garciadeblas5697b8b2021-03-24 09:17:02 +01001383 )
tierno69f0d382020-05-07 13:08:09 +00001384
1385 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
1386 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1387 # delete all nsr
1388 await self.RO.delete(nsr_id)
1389 except Exception as e:
1390 if isinstance(e, NgRoException) and e.http_code == 404: # not found
1391 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
1392 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
1393 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01001394 self.logger.debug(
1395 logging_text + "RO_action_id={} already deleted".format(action_id)
1396 )
tierno69f0d382020-05-07 13:08:09 +00001397 elif isinstance(e, NgRoException) and e.http_code == 409: # conflict
1398 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001399 self.logger.debug(
1400 logging_text
1401 + "RO_action_id={} delete conflict: {}".format(action_id, e)
1402 )
tierno69f0d382020-05-07 13:08:09 +00001403 else:
1404 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001405 self.logger.error(
1406 logging_text
1407 + "RO_action_id={} delete error: {}".format(action_id, e)
1408 )
tierno69f0d382020-05-07 13:08:09 +00001409
1410 if failed_detail:
1411 stage[2] = "Error deleting from VIM"
1412 else:
1413 stage[2] = "Deleted from VIM"
1414 db_nsr_update["detailed-status"] = " ".join(stage)
1415 self.update_db_2("nsrs", nsr_id, db_nsr_update)
1416 self._write_op_status(nslcmop_id, stage)
1417
1418 if failed_detail:
1419 raise LcmException("; ".join(failed_detail))
1420 return
1421
garciadeblas5697b8b2021-03-24 09:17:02 +01001422 async def instantiate_RO(
1423 self,
1424 logging_text,
1425 nsr_id,
1426 nsd,
1427 db_nsr,
1428 db_nslcmop,
1429 db_vnfrs,
1430 db_vnfds,
1431 n2vc_key_list,
1432 stage,
1433 ):
tiernoe95ed362020-04-23 08:24:57 +00001434 """
1435 Instantiate at RO
1436 :param logging_text: preffix text to use at logging
1437 :param nsr_id: nsr identity
1438 :param nsd: database content of ns descriptor
1439 :param db_nsr: database content of ns record
1440 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
1441 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -03001442 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +00001443 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
1444 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
1445 :return: None or exception
1446 """
tiernoe876f672020-02-13 14:34:48 +00001447 try:
tiernoe876f672020-02-13 14:34:48 +00001448 start_deploy = time()
1449 ns_params = db_nslcmop.get("operationParams")
1450 if ns_params and ns_params.get("timeout_ns_deploy"):
1451 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1452 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001453 timeout_ns_deploy = self.timeout.get(
1454 "ns_deploy", self.timeout_ns_deploy
1455 )
quilesj7e13aeb2019-10-08 13:34:55 +02001456
tiernoe876f672020-02-13 14:34:48 +00001457 # Check for and optionally request placement optimization. Database will be updated if placement activated
1458 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +00001459 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
1460 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
1461 for vnfr in db_vnfrs.values():
1462 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
1463 break
1464 else:
1465 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +02001466
garciadeblas5697b8b2021-03-24 09:17:02 +01001467 return await self._instantiate_ng_ro(
1468 logging_text,
1469 nsr_id,
1470 nsd,
1471 db_nsr,
1472 db_nslcmop,
1473 db_vnfrs,
1474 db_vnfds,
1475 n2vc_key_list,
1476 stage,
1477 start_deploy,
1478 timeout_ns_deploy,
1479 )
tierno2357f4e2020-10-19 16:38:59 +00001480 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +00001481 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +00001482 self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01001483 self.logger.error(
1484 "Error deploying at VIM {}".format(e),
1485 exc_info=not isinstance(
1486 e,
1487 (
1488 ROclient.ROClientException,
1489 LcmException,
1490 DbException,
1491 NgRoException,
1492 ),
1493 ),
1494 )
tiernoe876f672020-02-13 14:34:48 +00001495 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001496
tierno7ecbc342020-09-21 14:05:39 +00001497 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1498 """
1499 Wait for kdu to be up, get ip address
1500 :param logging_text: prefix use for logging
1501 :param nsr_id:
1502 :param vnfr_id:
1503 :param kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02001504 :return: IP address, K8s services
tierno7ecbc342020-09-21 14:05:39 +00001505 """
1506
1507 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1508 nb_tries = 0
1509
1510 while nb_tries < 360:
1511 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001512 kdur = next(
1513 (
1514 x
1515 for x in get_iterable(db_vnfr, "kdur")
1516 if x.get("kdu-name") == kdu_name
1517 ),
1518 None,
1519 )
tierno7ecbc342020-09-21 14:05:39 +00001520 if not kdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001521 raise LcmException(
1522 "Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name)
1523 )
tierno7ecbc342020-09-21 14:05:39 +00001524 if kdur.get("status"):
1525 if kdur["status"] in ("READY", "ENABLED"):
David Garcia78b6e6d2022-04-29 05:50:46 +02001526 return kdur.get("ip-address"), kdur.get("services")
tierno7ecbc342020-09-21 14:05:39 +00001527 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001528 raise LcmException(
1529 "target KDU={} is in error state".format(kdu_name)
1530 )
tierno7ecbc342020-09-21 14:05:39 +00001531
1532 await asyncio.sleep(10, loop=self.loop)
1533 nb_tries += 1
1534 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1535
garciadeblas5697b8b2021-03-24 09:17:02 +01001536 async def wait_vm_up_insert_key_ro(
1537 self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None
1538 ):
tiernoa5088192019-11-26 16:12:53 +00001539 """
1540 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1541 :param logging_text: prefix use for logging
1542 :param nsr_id:
1543 :param vnfr_id:
1544 :param vdu_id:
1545 :param vdu_index:
1546 :param pub_key: public ssh key to inject, None to skip
1547 :param user: user to apply the public ssh key
1548 :return: IP address
1549 """
quilesj7e13aeb2019-10-08 13:34:55 +02001550
tierno2357f4e2020-10-19 16:38:59 +00001551 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001552 ro_nsr_id = None
1553 ip_address = None
1554 nb_tries = 0
1555 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001556 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001557
tiernod8323042019-08-09 11:32:23 +00001558 while True:
quilesj7e13aeb2019-10-08 13:34:55 +02001559
quilesj3149f262019-12-03 10:58:10 +00001560 ro_retries += 1
1561 if ro_retries >= 360: # 1 hour
garciadeblas5697b8b2021-03-24 09:17:02 +01001562 raise LcmException(
1563 "Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id)
1564 )
quilesj3149f262019-12-03 10:58:10 +00001565
tiernod8323042019-08-09 11:32:23 +00001566 await asyncio.sleep(10, loop=self.loop)
quilesj7e13aeb2019-10-08 13:34:55 +02001567
1568 # get ip address
tiernod8323042019-08-09 11:32:23 +00001569 if not target_vdu_id:
1570 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001571
1572 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001573 if db_vnfr.get("status") == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001574 raise LcmException(
1575 "Cannot inject ssh-key because target VNF is in error state"
1576 )
tiernod8323042019-08-09 11:32:23 +00001577 ip_address = db_vnfr.get("ip-address")
1578 if not ip_address:
1579 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001580 vdur = next(
1581 (
1582 x
1583 for x in get_iterable(db_vnfr, "vdur")
1584 if x.get("ip-address") == ip_address
1585 ),
1586 None,
1587 )
quilesj3149f262019-12-03 10:58:10 +00001588 else: # VDU case
garciadeblas5697b8b2021-03-24 09:17:02 +01001589 vdur = next(
1590 (
1591 x
1592 for x in get_iterable(db_vnfr, "vdur")
1593 if x.get("vdu-id-ref") == vdu_id
1594 and x.get("count-index") == vdu_index
1595 ),
1596 None,
1597 )
quilesj3149f262019-12-03 10:58:10 +00001598
garciadeblas5697b8b2021-03-24 09:17:02 +01001599 if (
1600 not vdur and len(db_vnfr.get("vdur", ())) == 1
1601 ): # If only one, this should be the target vdu
tierno0e8c3f02020-03-12 17:18:21 +00001602 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001603 if not vdur:
garciadeblas5697b8b2021-03-24 09:17:02 +01001604 raise LcmException(
1605 "Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(
1606 vnfr_id, vdu_id, vdu_index
1607 )
1608 )
tierno2357f4e2020-10-19 16:38:59 +00001609 # New generation RO stores information at "vim_info"
1610 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001611 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001612 if vdur.get("vim_info"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001613 target_vim = next(
1614 t for t in vdur["vim_info"]
1615 ) # there should be only one key
tierno2357f4e2020-10-19 16:38:59 +00001616 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001617 if (
1618 vdur.get("pdu-type")
1619 or vdur.get("status") == "ACTIVE"
1620 or ng_ro_status == "ACTIVE"
1621 ):
quilesj3149f262019-12-03 10:58:10 +00001622 ip_address = vdur.get("ip-address")
1623 if not ip_address:
1624 continue
1625 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001626 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
garciadeblas5697b8b2021-03-24 09:17:02 +01001627 raise LcmException(
1628 "Cannot inject ssh-key because target VM is in error state"
1629 )
quilesj3149f262019-12-03 10:58:10 +00001630
tiernod8323042019-08-09 11:32:23 +00001631 if not target_vdu_id:
1632 continue
tiernod8323042019-08-09 11:32:23 +00001633
quilesj7e13aeb2019-10-08 13:34:55 +02001634 # inject public key into machine
1635 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001636 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001637 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001638 if vdur.get("pdu-type"):
1639 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1640 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001641 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01001642 ro_vm_id = "{}-{}".format(
1643 db_vnfr["member-vnf-index-ref"], target_vdu_id
1644 ) # TODO add vdu_index
tierno69f0d382020-05-07 13:08:09 +00001645 if self.ng_ro:
garciadeblas5697b8b2021-03-24 09:17:02 +01001646 target = {
1647 "action": {
1648 "action": "inject_ssh_key",
1649 "key": pub_key,
1650 "user": user,
1651 },
1652 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
1653 }
tierno2357f4e2020-10-19 16:38:59 +00001654 desc = await self.RO.deploy(nsr_id, target)
1655 action_id = desc["action_id"]
preethika.p28b0bf82022-09-23 07:36:28 +00001656 await self._wait_ng_ro(
1657 nsr_id, action_id, timeout=600, operation="instantiation"
1658 )
tierno2357f4e2020-10-19 16:38:59 +00001659 break
tierno69f0d382020-05-07 13:08:09 +00001660 else:
tierno2357f4e2020-10-19 16:38:59 +00001661 # wait until NS is deployed at RO
1662 if not ro_nsr_id:
1663 db_nsrs = self.db.get_one("nsrs", {"_id": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01001664 ro_nsr_id = deep_get(
1665 db_nsrs, ("_admin", "deployed", "RO", "nsr_id")
1666 )
tierno2357f4e2020-10-19 16:38:59 +00001667 if not ro_nsr_id:
1668 continue
tierno69f0d382020-05-07 13:08:09 +00001669 result_dict = await self.RO.create_action(
1670 item="ns",
1671 item_id_name=ro_nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01001672 descriptor={
1673 "add_public_key": pub_key,
1674 "vms": [ro_vm_id],
1675 "user": user,
1676 },
tierno69f0d382020-05-07 13:08:09 +00001677 )
1678 # result_dict contains the format {VM-id: {vim_result: 200, description: text}}
1679 if not result_dict or not isinstance(result_dict, dict):
garciadeblas5697b8b2021-03-24 09:17:02 +01001680 raise LcmException(
1681 "Unknown response from RO when injecting key"
1682 )
tierno69f0d382020-05-07 13:08:09 +00001683 for result in result_dict.values():
1684 if result.get("vim_result") == 200:
1685 break
1686 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001687 raise ROclient.ROClientException(
1688 "error injecting key: {}".format(
1689 result.get("description")
1690 )
1691 )
tierno69f0d382020-05-07 13:08:09 +00001692 break
1693 except NgRoException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01001694 raise LcmException(
1695 "Reaching max tries injecting key. Error: {}".format(e)
1696 )
quilesj7e13aeb2019-10-08 13:34:55 +02001697 except ROclient.ROClientException as e:
tiernoa5088192019-11-26 16:12:53 +00001698 if not nb_tries:
garciadeblas5697b8b2021-03-24 09:17:02 +01001699 self.logger.debug(
1700 logging_text
1701 + "error injecting key: {}. Retrying until {} seconds".format(
1702 e, 20 * 10
1703 )
1704 )
quilesj7e13aeb2019-10-08 13:34:55 +02001705 nb_tries += 1
tiernoa5088192019-11-26 16:12:53 +00001706 if nb_tries >= 20:
garciadeblas5697b8b2021-03-24 09:17:02 +01001707 raise LcmException(
1708 "Reaching max tries injecting key. Error: {}".format(e)
1709 )
quilesj7e13aeb2019-10-08 13:34:55 +02001710 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001711 break
1712
1713 return ip_address
1714
tierno5ee02052019-12-05 19:55:02 +00001715 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1716 """
1717 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1718 """
1719 my_vca = vca_deployed_list[vca_index]
1720 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001721 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001722 return
1723 timeout = 300
1724 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001725 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1726 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1727 configuration_status_list = db_nsr["configurationStatus"]
1728 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001729 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001730 # myself
tierno5ee02052019-12-05 19:55:02 +00001731 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001732 if not my_vca.get("member-vnf-index") or (
1733 vca_deployed.get("member-vnf-index")
1734 == my_vca.get("member-vnf-index")
1735 ):
quilesj3655ae02019-12-12 16:08:35 +00001736 internal_status = configuration_status_list[index].get("status")
garciadeblas5697b8b2021-03-24 09:17:02 +01001737 if internal_status == "READY":
quilesj3655ae02019-12-12 16:08:35 +00001738 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01001739 elif internal_status == "BROKEN":
1740 raise LcmException(
1741 "Configuration aborted because dependent charm/s has failed"
1742 )
quilesj3655ae02019-12-12 16:08:35 +00001743 else:
1744 break
tierno5ee02052019-12-05 19:55:02 +00001745 else:
quilesj3655ae02019-12-12 16:08:35 +00001746 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001747 return
1748 await asyncio.sleep(10)
1749 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001750
1751 raise LcmException("Configuration aborted because dependent charm/s timeout")
1752
David Garciac1fe90a2021-03-31 19:12:02 +02001753 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
David Garcia5506c182021-10-21 17:03:48 +02001754 vca_id = None
1755 if db_vnfr:
1756 vca_id = deep_get(db_vnfr, ("vca-id",))
1757 elif db_nsr:
1758 vim_account_id = deep_get(db_nsr, ("instantiate_params", "vimAccountId"))
1759 vca_id = VimAccountDB.get_vim_account_with_id(vim_account_id).get("vca")
1760 return vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02001761
garciadeblas5697b8b2021-03-24 09:17:02 +01001762 async def instantiate_N2VC(
1763 self,
1764 logging_text,
1765 vca_index,
1766 nsi_id,
1767 db_nsr,
1768 db_vnfr,
1769 vdu_id,
1770 kdu_name,
1771 vdu_index,
1772 config_descriptor,
1773 deploy_params,
1774 base_folder,
1775 nslcmop_id,
1776 stage,
1777 vca_type,
1778 vca_name,
1779 ee_config_descriptor,
1780 ):
tiernod8323042019-08-09 11:32:23 +00001781 nsr_id = db_nsr["_id"]
1782 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001783 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001784 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001785 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001786 db_dict = {
garciadeblas5697b8b2021-03-24 09:17:02 +01001787 "collection": "nsrs",
1788 "filter": {"_id": nsr_id},
1789 "path": db_update_entry,
quilesj7e13aeb2019-10-08 13:34:55 +02001790 }
tiernod8323042019-08-09 11:32:23 +00001791 step = ""
1792 try:
quilesj3655ae02019-12-12 16:08:35 +00001793
garciadeblas5697b8b2021-03-24 09:17:02 +01001794 element_type = "NS"
quilesj3655ae02019-12-12 16:08:35 +00001795 element_under_configuration = nsr_id
1796
tiernod8323042019-08-09 11:32:23 +00001797 vnfr_id = None
1798 if db_vnfr:
1799 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001800 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001801
garciadeblas5697b8b2021-03-24 09:17:02 +01001802 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001803
aktas98488ed2021-07-29 17:42:49 +03001804 if vca_type == "native_charm":
1805 index_number = 0
1806 else:
1807 index_number = vdu_index or 0
1808
tiernod8323042019-08-09 11:32:23 +00001809 if vnfr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01001810 element_type = "VNF"
quilesj3655ae02019-12-12 16:08:35 +00001811 element_under_configuration = vnfr_id
aktas98488ed2021-07-29 17:42:49 +03001812 namespace += ".{}-{}".format(vnfr_id, index_number)
tiernod8323042019-08-09 11:32:23 +00001813 if vdu_id:
aktas98488ed2021-07-29 17:42:49 +03001814 namespace += ".{}-{}".format(vdu_id, index_number)
garciadeblas5697b8b2021-03-24 09:17:02 +01001815 element_type = "VDU"
aktas98488ed2021-07-29 17:42:49 +03001816 element_under_configuration = "{}-{}".format(vdu_id, index_number)
tiernob996d942020-07-03 14:52:28 +00001817 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001818 elif kdu_name:
aktas98488ed2021-07-29 17:42:49 +03001819 namespace += ".{}".format(kdu_name)
garciadeblas5697b8b2021-03-24 09:17:02 +01001820 element_type = "KDU"
tierno51183952020-04-03 15:48:18 +00001821 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001822 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001823
1824 # Get artifact path
bravof486707f2021-11-08 17:18:50 -03001825 if base_folder["pkg-dir"]:
1826 artifact_path = "{}/{}/{}/{}".format(
1827 base_folder["folder"],
1828 base_folder["pkg-dir"],
1829 "charms"
aticig15db6142022-01-24 12:51:26 +03001830 if vca_type
1831 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001832 else "helm-charts",
1833 vca_name,
1834 )
1835 else:
1836 artifact_path = "{}/Scripts/{}/{}/".format(
1837 base_folder["folder"],
1838 "charms"
aticig15db6142022-01-24 12:51:26 +03001839 if vca_type
1840 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
bravof486707f2021-11-08 17:18:50 -03001841 else "helm-charts",
1842 vca_name,
1843 )
bravof922c4172020-11-24 21:21:43 -03001844
1845 self.logger.debug("Artifact path > {}".format(artifact_path))
1846
tiernoa278b842020-07-08 15:33:55 +00001847 # get initial_config_primitive_list that applies to this element
garciadeblas5697b8b2021-03-24 09:17:02 +01001848 initial_config_primitive_list = config_descriptor.get(
1849 "initial-config-primitive"
1850 )
tiernoa278b842020-07-08 15:33:55 +00001851
garciadeblas5697b8b2021-03-24 09:17:02 +01001852 self.logger.debug(
1853 "Initial config primitive list > {}".format(
1854 initial_config_primitive_list
1855 )
1856 )
bravof922c4172020-11-24 21:21:43 -03001857
tiernoa278b842020-07-08 15:33:55 +00001858 # add config if not present for NS charm
1859 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001860 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
garciadeblas5697b8b2021-03-24 09:17:02 +01001861 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
1862 initial_config_primitive_list, vca_deployed, ee_descriptor_id
1863 )
tiernod8323042019-08-09 11:32:23 +00001864
garciadeblas5697b8b2021-03-24 09:17:02 +01001865 self.logger.debug(
1866 "Initial config primitive list #2 > {}".format(
1867 initial_config_primitive_list
1868 )
1869 )
tierno588547c2020-07-01 15:30:20 +00001870 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001871 # find old ee_id if exists
1872 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001873
David Garciac1fe90a2021-03-31 19:12:02 +02001874 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001875 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001876 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
quilesj7e13aeb2019-10-08 13:34:55 +02001877
tierno588547c2020-07-01 15:30:20 +00001878 self._write_configuration_status(
1879 nsr_id=nsr_id,
1880 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001881 status="CREATING",
tierno588547c2020-07-01 15:30:20 +00001882 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001883 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001884 )
tiernod8323042019-08-09 11:32:23 +00001885
tierno588547c2020-07-01 15:30:20 +00001886 step = "create execution environment"
garciadeblas5697b8b2021-03-24 09:17:02 +01001887 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001888
1889 ee_id = None
1890 credentials = None
1891 if vca_type == "k8s_proxy_charm":
1892 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
garciadeblas5697b8b2021-03-24 09:17:02 +01001893 charm_name=artifact_path[artifact_path.rfind("/") + 1 :],
David Garciaaae391f2020-11-09 11:12:54 +01001894 namespace=namespace,
1895 artifact_path=artifact_path,
1896 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001897 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001898 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001899 elif vca_type == "helm" or vca_type == "helm-v3":
1900 ee_id, credentials = await self.vca_map[
1901 vca_type
1902 ].create_execution_environment(
bravof922c4172020-11-24 21:21:43 -03001903 namespace=namespace,
1904 reuse_ee_id=ee_id,
1905 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001906 config=osm_config,
1907 artifact_path=artifact_path,
garciadeblas5697b8b2021-03-24 09:17:02 +01001908 vca_type=vca_type,
bravof922c4172020-11-24 21:21:43 -03001909 )
garciadeblas5697b8b2021-03-24 09:17:02 +01001910 else:
1911 ee_id, credentials = await self.vca_map[
1912 vca_type
1913 ].create_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001914 namespace=namespace,
1915 reuse_ee_id=ee_id,
1916 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001917 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001918 )
quilesj3655ae02019-12-12 16:08:35 +00001919
tierno588547c2020-07-01 15:30:20 +00001920 elif vca_type == "native_charm":
1921 step = "Waiting to VM being up and getting IP address"
1922 self.logger.debug(logging_text + step)
garciadeblas5697b8b2021-03-24 09:17:02 +01001923 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
1924 logging_text,
1925 nsr_id,
1926 vnfr_id,
1927 vdu_id,
1928 vdu_index,
1929 user=None,
1930 pub_key=None,
1931 )
tierno588547c2020-07-01 15:30:20 +00001932 credentials = {"hostname": rw_mgmt_ip}
1933 # get username
garciadeblas5697b8b2021-03-24 09:17:02 +01001934 username = deep_get(
1935 config_descriptor, ("config-access", "ssh-access", "default-user")
1936 )
tierno588547c2020-07-01 15:30:20 +00001937 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1938 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001939 if not username and initial_config_primitive_list:
1940 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001941 for param in config_primitive.get("parameter", ()):
1942 if param["name"] == "ssh-username":
1943 username = param["value"]
1944 break
1945 if not username:
garciadeblas5697b8b2021-03-24 09:17:02 +01001946 raise LcmException(
1947 "Cannot determine the username neither with 'initial-config-primitive' nor with "
1948 "'config-access.ssh-access.default-user'"
1949 )
tierno588547c2020-07-01 15:30:20 +00001950 credentials["username"] = username
1951 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001952
tierno588547c2020-07-01 15:30:20 +00001953 self._write_configuration_status(
1954 nsr_id=nsr_id,
1955 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001956 status="REGISTERING",
tierno588547c2020-07-01 15:30:20 +00001957 element_under_configuration=element_under_configuration,
garciadeblas5697b8b2021-03-24 09:17:02 +01001958 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001959 )
quilesj3655ae02019-12-12 16:08:35 +00001960
tierno588547c2020-07-01 15:30:20 +00001961 step = "register execution environment {}".format(credentials)
1962 self.logger.debug(logging_text + step)
1963 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001964 credentials=credentials,
1965 namespace=namespace,
1966 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001967 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001968 )
tierno3bedc9b2019-11-27 15:46:57 +00001969
tierno588547c2020-07-01 15:30:20 +00001970 # for compatibility with MON/POL modules, the need model and application name at database
1971 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
garciadeblas5697b8b2021-03-24 09:17:02 +01001972 ee_id_parts = ee_id.split(".")
tierno588547c2020-07-01 15:30:20 +00001973 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1974 if len(ee_id_parts) >= 2:
1975 model_name = ee_id_parts[0]
1976 application_name = ee_id_parts[1]
1977 db_nsr_update[db_update_entry + "model"] = model_name
1978 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001979
1980 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001981 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001982
tiernoc231a872020-01-21 08:49:05 +00001983 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001984 nsr_id=nsr_id,
1985 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01001986 status="INSTALLING SW",
quilesj3655ae02019-12-12 16:08:35 +00001987 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001988 element_type=element_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01001989 other_update=db_nsr_update,
quilesj3655ae02019-12-12 16:08:35 +00001990 )
1991
tierno3bedc9b2019-11-27 15:46:57 +00001992 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001993 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001994 config = None
tierno588547c2020-07-01 15:30:20 +00001995 if vca_type == "native_charm":
garciadeblas5697b8b2021-03-24 09:17:02 +01001996 config_primitive = next(
1997 (p for p in initial_config_primitive_list if p["name"] == "config"),
1998 None,
1999 )
tiernoa278b842020-07-08 15:33:55 +00002000 if config_primitive:
2001 config = self._map_primitive_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01002002 config_primitive, {}, deploy_params
tiernoa278b842020-07-08 15:33:55 +00002003 )
tierno588547c2020-07-01 15:30:20 +00002004 num_units = 1
2005 if vca_type == "lxc_proxy_charm":
2006 if element_type == "NS":
2007 num_units = db_nsr.get("config-units") or 1
2008 elif element_type == "VNF":
2009 num_units = db_vnfr.get("config-units") or 1
2010 elif element_type == "VDU":
2011 for v in db_vnfr["vdur"]:
2012 if vdu_id == v["vdu-id-ref"]:
2013 num_units = v.get("config-units") or 1
2014 break
David Garciaaae391f2020-11-09 11:12:54 +01002015 if vca_type != "k8s_proxy_charm":
2016 await self.vca_map[vca_type].install_configuration_sw(
2017 ee_id=ee_id,
2018 artifact_path=artifact_path,
2019 db_dict=db_dict,
2020 config=config,
2021 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02002022 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002023 vca_type=vca_type,
David Garciaaae391f2020-11-09 11:12:54 +01002024 )
quilesj7e13aeb2019-10-08 13:34:55 +02002025
quilesj63f90042020-01-17 09:53:55 +00002026 # write in db flag of configuration_sw already installed
garciadeblas5697b8b2021-03-24 09:17:02 +01002027 self.update_db_2(
2028 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
2029 )
quilesj63f90042020-01-17 09:53:55 +00002030
2031 # add relations for this VCA (wait for other peers related with this VCA)
garciadeblas5697b8b2021-03-24 09:17:02 +01002032 await self._add_vca_relations(
2033 logging_text=logging_text,
2034 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002035 vca_type=vca_type,
David Garciab4ebcd02021-10-28 02:00:43 +02002036 vca_index=vca_index,
garciadeblas5697b8b2021-03-24 09:17:02 +01002037 )
quilesj63f90042020-01-17 09:53:55 +00002038
quilesj7e13aeb2019-10-08 13:34:55 +02002039 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02002040 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002041 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00002042 pub_key = None
2043 user = None
tierno588547c2020-07-01 15:30:20 +00002044 # self.logger.debug("get ssh key block")
garciadeblas5697b8b2021-03-24 09:17:02 +01002045 if deep_get(
2046 config_descriptor, ("config-access", "ssh-access", "required")
2047 ):
tierno588547c2020-07-01 15:30:20 +00002048 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00002049 # Needed to inject a ssh key
garciadeblas5697b8b2021-03-24 09:17:02 +01002050 user = deep_get(
2051 config_descriptor,
2052 ("config-access", "ssh-access", "default-user"),
2053 )
tierno3bedc9b2019-11-27 15:46:57 +00002054 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02002055 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
garciadeblas5697b8b2021-03-24 09:17:02 +01002056 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
David Garciac1fe90a2021-03-31 19:12:02 +02002057 )
quilesj7e13aeb2019-10-08 13:34:55 +02002058
garciadeblas5697b8b2021-03-24 09:17:02 +01002059 step = "Insert public key into VM user={} ssh_key={}".format(
2060 user, pub_key
2061 )
tierno3bedc9b2019-11-27 15:46:57 +00002062 else:
tierno588547c2020-07-01 15:30:20 +00002063 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00002064 step = "Waiting to VM being up and getting IP address"
2065 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02002066
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002067 # default rw_mgmt_ip to None, avoiding the non definition of the variable
2068 rw_mgmt_ip = None
2069
tierno3bedc9b2019-11-27 15:46:57 +00002070 # n2vc_redesign STEP 5.1
2071 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00002072 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00002073 if kdu_name:
David Garcia78b6e6d2022-04-29 05:50:46 +02002074 rw_mgmt_ip, services = await self.wait_kdu_up(
garciadeblas5697b8b2021-03-24 09:17:02 +01002075 logging_text, nsr_id, vnfr_id, kdu_name
2076 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002077 vnfd = self.db.get_one(
2078 "vnfds_revisions",
2079 {"_id": f'{db_vnfr["vnfd-id"]}:{db_vnfr["revision"]}'},
2080 )
2081 kdu = get_kdu(vnfd, kdu_name)
2082 kdu_services = [
2083 service["name"] for service in get_kdu_services(kdu)
2084 ]
2085 exposed_services = []
2086 for service in services:
2087 if any(s in service["name"] for s in kdu_services):
2088 exposed_services.append(service)
2089 await self.vca_map[vca_type].exec_primitive(
2090 ee_id=ee_id,
2091 primitive_name="config",
2092 params_dict={
2093 "osm-config": json.dumps(
2094 OsmConfigBuilder(
2095 k8s={"services": exposed_services}
2096 ).build()
2097 )
2098 },
2099 vca_id=vca_id,
2100 )
Pedro Escaleira1e9c3e32022-05-30 15:37:01 +01002101
2102 # This verification is needed in order to avoid trying to add a public key
2103 # to a VM, when the VNF is a KNF (in the edge case where the user creates a VCA
2104 # for a KNF and not for its KDUs, the previous verification gives False, and the code
2105 # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
2106 # or it is a KNF)
preethika.p28b0bf82022-09-23 07:36:28 +00002107 elif db_vnfr.get("vdur"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002108 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
2109 logging_text,
2110 nsr_id,
2111 vnfr_id,
2112 vdu_id,
2113 vdu_index,
2114 user=user,
2115 pub_key=pub_key,
2116 )
David Garcia78b6e6d2022-04-29 05:50:46 +02002117
garciadeblas5697b8b2021-03-24 09:17:02 +01002118 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02002119
tiernoa5088192019-11-26 16:12:53 +00002120 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02002121 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00002122
2123 # n2vc_redesign STEP 6 Execute initial config primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01002124 step = "execute initial config primitive"
quilesj3655ae02019-12-12 16:08:35 +00002125
2126 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00002127 if initial_config_primitive_list:
2128 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00002129
2130 # stage, in function of element type: vdu, kdu, vnf or ns
2131 my_vca = vca_deployed_list[vca_index]
2132 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
2133 # VDU or KDU
garciadeblas5697b8b2021-03-24 09:17:02 +01002134 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
quilesj3655ae02019-12-12 16:08:35 +00002135 elif my_vca.get("member-vnf-index"):
2136 # VNF
garciadeblas5697b8b2021-03-24 09:17:02 +01002137 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
quilesj3655ae02019-12-12 16:08:35 +00002138 else:
2139 # NS
garciadeblas5697b8b2021-03-24 09:17:02 +01002140 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
quilesj3655ae02019-12-12 16:08:35 +00002141
tiernoc231a872020-01-21 08:49:05 +00002142 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002143 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
quilesj3655ae02019-12-12 16:08:35 +00002144 )
2145
garciadeblas5697b8b2021-03-24 09:17:02 +01002146 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002147
tiernoe876f672020-02-13 14:34:48 +00002148 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00002149 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00002150 # adding information on the vca_deployed if it is a NS execution environment
2151 if not vca_deployed["member-vnf-index"]:
garciadeblas5697b8b2021-03-24 09:17:02 +01002152 deploy_params["ns_config_info"] = json.dumps(
2153 self._get_ns_config_info(nsr_id)
2154 )
tiernod8323042019-08-09 11:32:23 +00002155 # TODO check if already done
garciadeblas5697b8b2021-03-24 09:17:02 +01002156 primitive_params_ = self._map_primitive_params(
2157 initial_config_primitive, {}, deploy_params
2158 )
tierno3bedc9b2019-11-27 15:46:57 +00002159
garciadeblas5697b8b2021-03-24 09:17:02 +01002160 step = "execute primitive '{}' params '{}'".format(
2161 initial_config_primitive["name"], primitive_params_
2162 )
tiernod8323042019-08-09 11:32:23 +00002163 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00002164 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02002165 ee_id=ee_id,
2166 primitive_name=initial_config_primitive["name"],
2167 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02002168 db_dict=db_dict,
2169 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03002170 vca_type=vca_type,
quilesj7e13aeb2019-10-08 13:34:55 +02002171 )
tiernoe876f672020-02-13 14:34:48 +00002172 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
2173 if check_if_terminated_needed:
garciadeblas5697b8b2021-03-24 09:17:02 +01002174 if config_descriptor.get("terminate-config-primitive"):
2175 self.update_db_2(
2176 "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
2177 )
tiernoe876f672020-02-13 14:34:48 +00002178 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00002179
tiernod8323042019-08-09 11:32:23 +00002180 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02002181
tiernob996d942020-07-03 14:52:28 +00002182 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002183 if vca_type == "helm" or vca_type == "helm-v3":
bravof73bac502021-05-11 07:38:47 -04002184 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
tiernob996d942020-07-03 14:52:28 +00002185 ee_id=ee_id,
2186 artifact_path=artifact_path,
2187 ee_config_descriptor=ee_config_descriptor,
2188 vnfr_id=vnfr_id,
2189 nsr_id=nsr_id,
2190 target_ip=rw_mgmt_ip,
2191 )
2192 if prometheus_jobs:
garciadeblas5697b8b2021-03-24 09:17:02 +01002193 self.update_db_2(
2194 "nsrs",
2195 nsr_id,
2196 {db_update_entry + "prometheus_jobs": prometheus_jobs},
2197 )
tiernob996d942020-07-03 14:52:28 +00002198
bravof73bac502021-05-11 07:38:47 -04002199 for job in prometheus_jobs:
2200 self.db.set_one(
2201 "prometheus_jobs",
aticig15db6142022-01-24 12:51:26 +03002202 {"job_name": job["job_name"]},
bravof73bac502021-05-11 07:38:47 -04002203 job,
2204 upsert=True,
aticig15db6142022-01-24 12:51:26 +03002205 fail_on_empty=False,
bravof73bac502021-05-11 07:38:47 -04002206 )
2207
quilesj7e13aeb2019-10-08 13:34:55 +02002208 step = "instantiated at VCA"
2209 self.logger.debug(logging_text + step)
2210
tiernoc231a872020-01-21 08:49:05 +00002211 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002212 nsr_id=nsr_id, vca_index=vca_index, status="READY"
quilesj3655ae02019-12-12 16:08:35 +00002213 )
2214
tiernod8323042019-08-09 11:32:23 +00002215 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00002216 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
garciadeblas5697b8b2021-03-24 09:17:02 +01002217 if not isinstance(
2218 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
2219 ):
2220 self.logger.error(
2221 "Exception while {} : {}".format(step, e), exc_info=True
2222 )
tiernoc231a872020-01-21 08:49:05 +00002223 self._write_configuration_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01002224 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
quilesj3655ae02019-12-12 16:08:35 +00002225 )
tiernoe876f672020-02-13 14:34:48 +00002226 raise LcmException("{} {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00002227
garciadeblas5697b8b2021-03-24 09:17:02 +01002228 def _write_ns_status(
2229 self,
2230 nsr_id: str,
2231 ns_state: str,
2232 current_operation: str,
2233 current_operation_id: str,
2234 error_description: str = None,
2235 error_detail: str = None,
2236 other_update: dict = None,
2237 ):
tiernoe876f672020-02-13 14:34:48 +00002238 """
2239 Update db_nsr fields.
2240 :param nsr_id:
2241 :param ns_state:
2242 :param current_operation:
2243 :param current_operation_id:
2244 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00002245 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00002246 :param other_update: Other required changes at database if provided, will be cleared
2247 :return:
2248 """
quilesj4cda56b2019-12-05 10:02:20 +00002249 try:
tiernoe876f672020-02-13 14:34:48 +00002250 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002251 db_dict[
2252 "_admin.nslcmop"
2253 ] = current_operation_id # for backward compatibility
tiernoe876f672020-02-13 14:34:48 +00002254 db_dict["_admin.current-operation"] = current_operation_id
garciadeblas5697b8b2021-03-24 09:17:02 +01002255 db_dict["_admin.operation-type"] = (
2256 current_operation if current_operation != "IDLE" else None
2257 )
quilesj4cda56b2019-12-05 10:02:20 +00002258 db_dict["currentOperation"] = current_operation
2259 db_dict["currentOperationID"] = current_operation_id
2260 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00002261 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00002262
2263 if ns_state:
2264 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00002265 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002266 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002267 self.logger.warn("Error writing NS status, ns={}: {}".format(nsr_id, e))
quilesj3655ae02019-12-12 16:08:35 +00002268
garciadeblas5697b8b2021-03-24 09:17:02 +01002269 def _write_op_status(
2270 self,
2271 op_id: str,
2272 stage: list = None,
2273 error_message: str = None,
2274 queuePosition: int = 0,
2275 operation_state: str = None,
2276 other_update: dict = None,
2277 ):
quilesj3655ae02019-12-12 16:08:35 +00002278 try:
tiernoe876f672020-02-13 14:34:48 +00002279 db_dict = other_update or {}
garciadeblas5697b8b2021-03-24 09:17:02 +01002280 db_dict["queuePosition"] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00002281 if isinstance(stage, list):
garciadeblas5697b8b2021-03-24 09:17:02 +01002282 db_dict["stage"] = stage[0]
2283 db_dict["detailed-status"] = " ".join(stage)
tiernoe876f672020-02-13 14:34:48 +00002284 elif stage is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002285 db_dict["stage"] = str(stage)
tiernoe876f672020-02-13 14:34:48 +00002286
2287 if error_message is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002288 db_dict["errorMessage"] = error_message
tiernoe876f672020-02-13 14:34:48 +00002289 if operation_state is not None:
garciadeblas5697b8b2021-03-24 09:17:02 +01002290 db_dict["operationState"] = operation_state
tiernoe876f672020-02-13 14:34:48 +00002291 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00002292 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002293 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002294 self.logger.warn(
2295 "Error writing OPERATION status for op_id: {} -> {}".format(op_id, e)
2296 )
quilesj3655ae02019-12-12 16:08:35 +00002297
tierno51183952020-04-03 15:48:18 +00002298 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00002299 try:
tierno51183952020-04-03 15:48:18 +00002300 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00002301 # configurationStatus
garciadeblas5697b8b2021-03-24 09:17:02 +01002302 config_status = db_nsr.get("configurationStatus")
quilesj3655ae02019-12-12 16:08:35 +00002303 if config_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002304 db_nsr_update = {
2305 "configurationStatus.{}.status".format(index): status
2306 for index, v in enumerate(config_status)
2307 if v
2308 }
quilesj3655ae02019-12-12 16:08:35 +00002309 # update status
tierno51183952020-04-03 15:48:18 +00002310 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00002311
tiernoe876f672020-02-13 14:34:48 +00002312 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002313 self.logger.warn(
2314 "Error writing all configuration status, ns={}: {}".format(nsr_id, e)
2315 )
quilesj3655ae02019-12-12 16:08:35 +00002316
garciadeblas5697b8b2021-03-24 09:17:02 +01002317 def _write_configuration_status(
2318 self,
2319 nsr_id: str,
2320 vca_index: int,
2321 status: str = None,
2322 element_under_configuration: str = None,
2323 element_type: str = None,
2324 other_update: dict = None,
2325 ):
quilesj3655ae02019-12-12 16:08:35 +00002326
2327 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
2328 # .format(vca_index, status))
2329
2330 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002331 db_path = "configurationStatus.{}.".format(vca_index)
tierno51183952020-04-03 15:48:18 +00002332 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00002333 if status:
garciadeblas5697b8b2021-03-24 09:17:02 +01002334 db_dict[db_path + "status"] = status
quilesj3655ae02019-12-12 16:08:35 +00002335 if element_under_configuration:
garciadeblas5697b8b2021-03-24 09:17:02 +01002336 db_dict[
2337 db_path + "elementUnderConfiguration"
2338 ] = element_under_configuration
quilesj3655ae02019-12-12 16:08:35 +00002339 if element_type:
garciadeblas5697b8b2021-03-24 09:17:02 +01002340 db_dict[db_path + "elementType"] = element_type
quilesj3655ae02019-12-12 16:08:35 +00002341 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00002342 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002343 self.logger.warn(
2344 "Error writing configuration status={}, ns={}, vca_index={}: {}".format(
2345 status, nsr_id, vca_index, e
2346 )
2347 )
quilesj4cda56b2019-12-05 10:02:20 +00002348
tierno38089af2020-04-16 07:56:58 +00002349 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
2350 """
2351 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
2352 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
2353 Database is used because the result can be obtained from a different LCM worker in case of HA.
2354 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
2355 :param db_nslcmop: database content of nslcmop
2356 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00002357 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
2358 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00002359 """
tierno8790a3d2020-04-23 22:49:52 +00002360 modified = False
garciadeblas5697b8b2021-03-24 09:17:02 +01002361 nslcmop_id = db_nslcmop["_id"]
2362 placement_engine = deep_get(db_nslcmop, ("operationParams", "placement-engine"))
magnussonle9198bb2020-01-21 13:00:51 +01002363 if placement_engine == "PLA":
garciadeblas5697b8b2021-03-24 09:17:02 +01002364 self.logger.debug(
2365 logging_text + "Invoke and wait for placement optimization"
2366 )
2367 await self.msg.aiowrite(
2368 "pla", "get_placement", {"nslcmopId": nslcmop_id}, loop=self.loop
2369 )
magnussonle9198bb2020-01-21 13:00:51 +01002370 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00002371 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01002372 pla_result = None
2373 while not pla_result and wait >= 0:
2374 await asyncio.sleep(db_poll_interval)
2375 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00002376 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01002377 pla_result = deep_get(db_nslcmop, ("_admin", "pla"))
magnussonle9198bb2020-01-21 13:00:51 +01002378
2379 if not pla_result:
garciadeblas5697b8b2021-03-24 09:17:02 +01002380 raise LcmException(
2381 "Placement timeout for nslcmopId={}".format(nslcmop_id)
2382 )
magnussonle9198bb2020-01-21 13:00:51 +01002383
garciadeblas5697b8b2021-03-24 09:17:02 +01002384 for pla_vnf in pla_result["vnf"]:
2385 vnfr = db_vnfrs.get(pla_vnf["member-vnf-index"])
2386 if not pla_vnf.get("vimAccountId") or not vnfr:
magnussonle9198bb2020-01-21 13:00:51 +01002387 continue
tierno8790a3d2020-04-23 22:49:52 +00002388 modified = True
garciadeblas5697b8b2021-03-24 09:17:02 +01002389 self.db.set_one(
2390 "vnfrs",
2391 {"_id": vnfr["_id"]},
2392 {"vim-account-id": pla_vnf["vimAccountId"]},
2393 )
tierno38089af2020-04-16 07:56:58 +00002394 # Modifies db_vnfrs
garciadeblas5697b8b2021-03-24 09:17:02 +01002395 vnfr["vim-account-id"] = pla_vnf["vimAccountId"]
tierno8790a3d2020-04-23 22:49:52 +00002396 return modified
magnussonle9198bb2020-01-21 13:00:51 +01002397
2398 def update_nsrs_with_pla_result(self, params):
2399 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002400 nslcmop_id = deep_get(params, ("placement", "nslcmopId"))
2401 self.update_db_2(
2402 "nslcmops", nslcmop_id, {"_admin.pla": params.get("placement")}
2403 )
magnussonle9198bb2020-01-21 13:00:51 +01002404 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002405 self.logger.warn("Update failed for nslcmop_id={}:{}".format(nslcmop_id, e))
magnussonle9198bb2020-01-21 13:00:51 +01002406
tierno59d22d22018-09-25 18:10:19 +02002407 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02002408 """
2409
2410 :param nsr_id: ns instance to deploy
2411 :param nslcmop_id: operation to run
2412 :return:
2413 """
kuused124bfe2019-06-18 12:09:24 +02002414
2415 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01002416 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002417 if not task_is_locked_by_me:
garciadeblas5697b8b2021-03-24 09:17:02 +01002418 self.logger.debug(
2419 "instantiate() task is not locked by me, ns={}".format(nsr_id)
2420 )
kuused124bfe2019-06-18 12:09:24 +02002421 return
2422
tierno59d22d22018-09-25 18:10:19 +02002423 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
2424 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02002425
tierno59d22d22018-09-25 18:10:19 +02002426 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02002427
2428 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02002429 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02002430
2431 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02002432 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02002433
2434 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00002435 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002436 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02002437 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02002438
tierno59d22d22018-09-25 18:10:19 +02002439 nslcmop_operation_state = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002440 db_vnfrs = {} # vnf's info indexed by member-index
quilesj7e13aeb2019-10-08 13:34:55 +02002441 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00002442 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02002443 exc = None
tiernoe876f672020-02-13 14:34:48 +00002444 error_list = []
garciadeblas5697b8b2021-03-24 09:17:02 +01002445 stage = [
2446 "Stage 1/5: preparation of the environment.",
2447 "Waiting for previous operations to terminate.",
2448 "",
2449 ]
tiernoe876f672020-02-13 14:34:48 +00002450 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02002451 try:
kuused124bfe2019-06-18 12:09:24 +02002452 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01002453 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02002454
quilesj7e13aeb2019-10-08 13:34:55 +02002455 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00002456 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00002457 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00002458 db_nsr_update["detailed-status"] = "creating"
2459 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00002460 self._write_ns_status(
2461 nsr_id=nsr_id,
2462 ns_state="BUILDING",
2463 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00002464 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01002465 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002466 )
garciadeblas5697b8b2021-03-24 09:17:02 +01002467 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
quilesj4cda56b2019-12-05 10:02:20 +00002468
quilesj7e13aeb2019-10-08 13:34:55 +02002469 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00002470 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02002471 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01002472 if db_nslcmop["operationParams"].get("additionalParamsForVnf"):
2473 db_nslcmop["operationParams"]["additionalParamsForVnf"] = json.loads(
2474 db_nslcmop["operationParams"]["additionalParamsForVnf"]
2475 )
tierno744303e2020-01-13 16:46:31 +00002476 ns_params = db_nslcmop.get("operationParams")
2477 if ns_params and ns_params.get("timeout_ns_deploy"):
2478 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
2479 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01002480 timeout_ns_deploy = self.timeout.get(
2481 "ns_deploy", self.timeout_ns_deploy
2482 )
quilesj7e13aeb2019-10-08 13:34:55 +02002483
2484 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00002485 stage[1] = "Getting nsr={} from db.".format(nsr_id)
garciadeblascd509f52021-11-23 10:04:12 +01002486 self.logger.debug(logging_text + stage[1])
tierno59d22d22018-09-25 18:10:19 +02002487 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00002488 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
garciadeblascd509f52021-11-23 10:04:12 +01002489 self.logger.debug(logging_text + stage[1])
tiernod732fb82020-05-21 13:18:23 +00002490 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
bravof021e70d2021-03-11 12:03:30 -03002491 self.fs.sync(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00002492 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00002493 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02002494
quilesj7e13aeb2019-10-08 13:34:55 +02002495 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00002496 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00002497 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002498 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02002499
quilesj7e13aeb2019-10-08 13:34:55 +02002500 # read from db: vnfd's for every vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01002501 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02002502
2503 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02002504 for vnfr in db_vnfrs_list:
Guillermo Calvino57c68152022-01-26 17:40:31 +01002505 if vnfr.get("kdur"):
2506 kdur_list = []
2507 for kdur in vnfr["kdur"]:
2508 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002509 kdur["additionalParams"] = json.loads(
2510 kdur["additionalParams"]
2511 )
Guillermo Calvino57c68152022-01-26 17:40:31 +01002512 kdur_list.append(kdur)
2513 vnfr["kdur"] = kdur_list
2514
bravof922c4172020-11-24 21:21:43 -03002515 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
2516 vnfd_id = vnfr["vnfd-id"]
2517 vnfd_ref = vnfr["vnfd-ref"]
bravof021e70d2021-03-11 12:03:30 -03002518 self.fs.sync(vnfd_id)
lloretgalleg6d488782020-07-22 10:13:46 +00002519
quilesj7e13aeb2019-10-08 13:34:55 +02002520 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02002521 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00002522 # read from db
garciadeblas5697b8b2021-03-24 09:17:02 +01002523 stage[1] = "Getting vnfd={} id='{}' from db.".format(
2524 vnfd_id, vnfd_ref
2525 )
tiernoe876f672020-02-13 14:34:48 +00002526 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02002527 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02002528
quilesj7e13aeb2019-10-08 13:34:55 +02002529 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01002530 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02002531
2532 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00002533 vca_deployed_list = None
2534 if db_nsr["_admin"].get("deployed"):
2535 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
2536 if vca_deployed_list is None:
2537 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00002538 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00002539 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00002540 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02002541 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002542 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002543 elif isinstance(vca_deployed_list, dict):
2544 # maintain backward compatibility. Change a dict to list at database
2545 vca_deployed_list = list(vca_deployed_list.values())
2546 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00002547 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00002548
garciadeblas5697b8b2021-03-24 09:17:02 +01002549 if not isinstance(
2550 deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list
2551 ):
tiernoa009e552019-01-30 16:45:44 +00002552 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
2553 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02002554
tiernobaa51102018-12-14 13:16:18 +00002555 # set state to INSTANTIATED. When instantiated NBI will not delete directly
2556 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
2557 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01002558 self.db.set_list(
2559 "vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}
2560 )
quilesj3655ae02019-12-12 16:08:35 +00002561
2562 # n2vc_redesign STEP 2 Deploy Network Scenario
garciadeblas5697b8b2021-03-24 09:17:02 +01002563 stage[0] = "Stage 2/5: deployment of KDUs, VMs and execution environments."
2564 self._write_op_status(op_id=nslcmop_id, stage=stage)
quilesj3655ae02019-12-12 16:08:35 +00002565
tiernob5203912020-08-11 11:20:13 +00002566 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00002567 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01002568 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00002569 await self.deploy_kdus(
2570 logging_text=logging_text,
2571 nsr_id=nsr_id,
2572 nslcmop_id=nslcmop_id,
2573 db_vnfrs=db_vnfrs,
2574 db_vnfds=db_vnfds,
2575 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002576 )
tiernoe876f672020-02-13 14:34:48 +00002577
2578 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00002579 # n2vc_redesign STEP 1 Get VCA public ssh-key
2580 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00002581 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00002582 n2vc_key_list = [n2vc_key]
2583 if self.vca_config.get("public_key"):
2584 n2vc_key_list.append(self.vca_config["public_key"])
tierno98ad6ea2019-05-30 17:16:28 +00002585
tiernoe876f672020-02-13 14:34:48 +00002586 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00002587 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02002588 self.instantiate_RO(
2589 logging_text=logging_text,
2590 nsr_id=nsr_id,
2591 nsd=nsd,
2592 db_nsr=db_nsr,
2593 db_nslcmop=db_nslcmop,
2594 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03002595 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00002596 n2vc_key_list=n2vc_key_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01002597 stage=stage,
tierno98ad6ea2019-05-30 17:16:28 +00002598 )
tiernod8323042019-08-09 11:32:23 +00002599 )
2600 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00002601 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00002602
tiernod8323042019-08-09 11:32:23 +00002603 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00002604 stage[1] = "Deploying Execution Environments."
2605 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00002606
tiernod8323042019-08-09 11:32:23 +00002607 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03002608 for vnf_profile in get_vnf_profiles(nsd):
2609 vnfd_id = vnf_profile["vnfd-id"]
2610 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
2611 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00002612 db_vnfr = db_vnfrs[member_vnf_index]
2613 base_folder = vnfd["_admin"]["storage"]
2614 vdu_id = None
2615 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00002616 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002617 kdu_name = None
tierno59d22d22018-09-25 18:10:19 +02002618
tierno8a518872018-12-21 13:42:14 +00002619 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03002620 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00002621 if db_vnfr.get("additionalParamsForVnf"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002622 deploy_params.update(
2623 parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy())
2624 )
tierno8a518872018-12-21 13:42:14 +00002625
bravofe5a31bc2021-02-17 19:09:12 -03002626 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00002627 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02002628 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002629 logging_text=logging_text
2630 + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02002631 db_nsr=db_nsr,
2632 db_vnfr=db_vnfr,
2633 nslcmop_id=nslcmop_id,
2634 nsr_id=nsr_id,
2635 nsi_id=nsi_id,
2636 vnfd_id=vnfd_id,
2637 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002638 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002639 member_vnf_index=member_vnf_index,
2640 vdu_index=vdu_index,
2641 vdu_name=vdu_name,
2642 deploy_params=deploy_params,
2643 descriptor_config=descriptor_config,
2644 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00002645 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002646 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002647 )
tierno59d22d22018-09-25 18:10:19 +02002648
2649 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03002650 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00002651 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03002652 descriptor_config = get_configuration(vnfd, vdu_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01002653 vdur = find_in_list(
2654 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
2655 )
bravof922c4172020-11-24 21:21:43 -03002656
tierno626e0152019-11-29 14:16:16 +00002657 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03002658 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00002659 else:
2660 deploy_params_vdu = deploy_params
garciadeblas5697b8b2021-03-24 09:17:02 +01002661 deploy_params_vdu["OSM"] = get_osm_params(
2662 db_vnfr, vdu_id, vdu_count_index=0
2663 )
endika76ba9232021-06-21 18:55:07 +02002664 vdud_count = get_number_of_instances(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03002665
2666 self.logger.debug("VDUD > {}".format(vdud))
garciadeblas5697b8b2021-03-24 09:17:02 +01002667 self.logger.debug(
2668 "Descriptor config > {}".format(descriptor_config)
2669 )
tierno588547c2020-07-01 15:30:20 +00002670 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00002671 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002672 kdu_name = None
bravof922c4172020-11-24 21:21:43 -03002673 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00002674 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02002675 self._deploy_n2vc(
garciadeblas5697b8b2021-03-24 09:17:02 +01002676 logging_text=logging_text
2677 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
2678 member_vnf_index, vdu_id, vdu_index
2679 ),
quilesj7e13aeb2019-10-08 13:34:55 +02002680 db_nsr=db_nsr,
2681 db_vnfr=db_vnfr,
2682 nslcmop_id=nslcmop_id,
2683 nsr_id=nsr_id,
2684 nsi_id=nsi_id,
2685 vnfd_id=vnfd_id,
2686 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002687 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002688 member_vnf_index=member_vnf_index,
2689 vdu_index=vdu_index,
2690 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00002691 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02002692 descriptor_config=descriptor_config,
2693 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002694 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002695 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002696 )
bravof922c4172020-11-24 21:21:43 -03002697 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002698 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03002699 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00002700 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002701 vdu_id = None
2702 vdu_index = 0
2703 vdu_name = None
garciadeblas5697b8b2021-03-24 09:17:02 +01002704 kdur = next(
2705 x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name
2706 )
bravof922c4172020-11-24 21:21:43 -03002707 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00002708 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01002709 deploy_params_kdu.update(
2710 parse_yaml_strings(kdur["additionalParams"].copy())
garciadeblas5697b8b2021-03-24 09:17:02 +01002711 )
tierno59d22d22018-09-25 18:10:19 +02002712
calvinosanch9f9c6f22019-11-04 13:37:39 +01002713 self._deploy_n2vc(
2714 logging_text=logging_text,
2715 db_nsr=db_nsr,
2716 db_vnfr=db_vnfr,
2717 nslcmop_id=nslcmop_id,
2718 nsr_id=nsr_id,
2719 nsi_id=nsi_id,
2720 vnfd_id=vnfd_id,
2721 vdu_id=vdu_id,
2722 kdu_name=kdu_name,
2723 member_vnf_index=member_vnf_index,
2724 vdu_index=vdu_index,
2725 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00002726 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002727 descriptor_config=descriptor_config,
2728 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002729 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002730 stage=stage,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002731 )
tierno59d22d22018-09-25 18:10:19 +02002732
tierno1b633412019-02-25 16:48:23 +00002733 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00002734 descriptor_config = nsd.get("ns-configuration")
2735 if descriptor_config and descriptor_config.get("juju"):
2736 vnfd_id = None
2737 db_vnfr = None
2738 member_vnf_index = None
2739 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01002740 kdu_name = None
tiernod8323042019-08-09 11:32:23 +00002741 vdu_index = 0
2742 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00002743
tiernod8323042019-08-09 11:32:23 +00002744 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01002745 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00002746 if db_nsr.get("additionalParamsForNs"):
garciadeblas5697b8b2021-03-24 09:17:02 +01002747 deploy_params.update(
2748 parse_yaml_strings(db_nsr["additionalParamsForNs"].copy())
2749 )
tiernod8323042019-08-09 11:32:23 +00002750 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02002751 self._deploy_n2vc(
2752 logging_text=logging_text,
2753 db_nsr=db_nsr,
2754 db_vnfr=db_vnfr,
2755 nslcmop_id=nslcmop_id,
2756 nsr_id=nsr_id,
2757 nsi_id=nsi_id,
2758 vnfd_id=vnfd_id,
2759 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002760 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02002761 member_vnf_index=member_vnf_index,
2762 vdu_index=vdu_index,
2763 vdu_name=vdu_name,
2764 deploy_params=deploy_params,
2765 descriptor_config=descriptor_config,
2766 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00002767 task_instantiation_info=tasks_dict_info,
garciadeblas5697b8b2021-03-24 09:17:02 +01002768 stage=stage,
quilesj7e13aeb2019-10-08 13:34:55 +02002769 )
tierno1b633412019-02-25 16:48:23 +00002770
tiernoe876f672020-02-13 14:34:48 +00002771 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00002772
garciadeblas5697b8b2021-03-24 09:17:02 +01002773 except (
2774 ROclient.ROClientException,
2775 DbException,
2776 LcmException,
2777 N2VCException,
2778 ) as e:
2779 self.logger.error(
2780 logging_text + "Exit Exception while '{}': {}".format(stage[1], e)
2781 )
tierno59d22d22018-09-25 18:10:19 +02002782 exc = e
2783 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01002784 self.logger.error(
2785 logging_text + "Cancelled Exception while '{}'".format(stage[1])
2786 )
tierno59d22d22018-09-25 18:10:19 +02002787 exc = "Operation was cancelled"
2788 except Exception as e:
2789 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01002790 self.logger.critical(
2791 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
2792 exc_info=True,
2793 )
tierno59d22d22018-09-25 18:10:19 +02002794 finally:
2795 if exc:
tiernoe876f672020-02-13 14:34:48 +00002796 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00002797 try:
tiernoe876f672020-02-13 14:34:48 +00002798 # wait for pending tasks
2799 if tasks_dict_info:
2800 stage[1] = "Waiting for instantiate pending tasks."
2801 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01002802 error_list += await self._wait_for_tasks(
2803 logging_text,
2804 tasks_dict_info,
2805 timeout_ns_deploy,
2806 stage,
2807 nslcmop_id,
2808 nsr_id=nsr_id,
2809 )
tiernoe876f672020-02-13 14:34:48 +00002810 stage[1] = stage[2] = ""
2811 except asyncio.CancelledError:
2812 error_list.append("Cancelled")
2813 # TODO cancel all tasks
2814 except Exception as exc:
2815 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00002816
tiernoe876f672020-02-13 14:34:48 +00002817 # update operation-status
2818 db_nsr_update["operational-status"] = "running"
2819 # let's begin with VCA 'configured' status (later we can change it)
2820 db_nsr_update["config-status"] = "configured"
2821 for task, task_name in tasks_dict_info.items():
2822 if not task.done() or task.cancelled() or task.exception():
2823 if task_name.startswith(self.task_name_deploy_vca):
2824 # A N2VC task is pending
2825 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00002826 else:
tiernoe876f672020-02-13 14:34:48 +00002827 # RO or KDU task is pending
2828 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00002829
tiernoe876f672020-02-13 14:34:48 +00002830 # update status at database
2831 if error_list:
tiernoa2143262020-03-27 16:20:40 +00002832 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00002833 self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01002834 error_description_nslcmop = "{} Detail: {}".format(
2835 stage[0], error_detail
2836 )
2837 error_description_nsr = "Operation: INSTANTIATING.{}, {}".format(
2838 nslcmop_id, stage[0]
2839 )
quilesj3655ae02019-12-12 16:08:35 +00002840
garciadeblas5697b8b2021-03-24 09:17:02 +01002841 db_nsr_update["detailed-status"] = (
2842 error_description_nsr + " Detail: " + error_detail
2843 )
tiernoe876f672020-02-13 14:34:48 +00002844 db_nslcmop_update["detailed-status"] = error_detail
2845 nslcmop_operation_state = "FAILED"
2846 ns_state = "BROKEN"
2847 else:
tiernoa2143262020-03-27 16:20:40 +00002848 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00002849 error_description_nsr = error_description_nslcmop = None
2850 ns_state = "READY"
2851 db_nsr_update["detailed-status"] = "Done"
2852 db_nslcmop_update["detailed-status"] = "Done"
2853 nslcmop_operation_state = "COMPLETED"
quilesj4cda56b2019-12-05 10:02:20 +00002854
tiernoe876f672020-02-13 14:34:48 +00002855 if db_nsr:
2856 self._write_ns_status(
2857 nsr_id=nsr_id,
2858 ns_state=ns_state,
2859 current_operation="IDLE",
2860 current_operation_id=None,
2861 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00002862 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01002863 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00002864 )
tiernoa17d4f42020-04-28 09:59:23 +00002865 self._write_op_status(
2866 op_id=nslcmop_id,
2867 stage="",
2868 error_message=error_description_nslcmop,
2869 operation_state=nslcmop_operation_state,
2870 other_update=db_nslcmop_update,
2871 )
quilesj3655ae02019-12-12 16:08:35 +00002872
tierno59d22d22018-09-25 18:10:19 +02002873 if nslcmop_operation_state:
2874 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01002875 await self.msg.aiowrite(
2876 "ns",
2877 "instantiated",
2878 {
2879 "nsr_id": nsr_id,
2880 "nslcmop_id": nslcmop_id,
2881 "operationState": nslcmop_operation_state,
2882 },
2883 loop=self.loop,
2884 )
tierno59d22d22018-09-25 18:10:19 +02002885 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01002886 self.logger.error(
2887 logging_text + "kafka_write notification Exception {}".format(e)
2888 )
tierno59d22d22018-09-25 18:10:19 +02002889
2890 self.logger.debug(logging_text + "Exit")
2891 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
2892
David Garciab4ebcd02021-10-28 02:00:43 +02002893 def _get_vnfd(self, vnfd_id: str, cached_vnfds: Dict[str, Any]):
2894 if vnfd_id not in cached_vnfds:
2895 cached_vnfds[vnfd_id] = self.db.get_one("vnfds", {"id": vnfd_id})
2896 return cached_vnfds[vnfd_id]
2897
2898 def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
2899 if vnf_profile_id not in cached_vnfrs:
2900 cached_vnfrs[vnf_profile_id] = self.db.get_one(
2901 "vnfrs",
2902 {
2903 "member-vnf-index-ref": vnf_profile_id,
2904 "nsr-id-ref": nsr_id,
2905 },
2906 )
2907 return cached_vnfrs[vnf_profile_id]
2908
2909 def _is_deployed_vca_in_relation(
2910 self, vca: DeployedVCA, relation: Relation
2911 ) -> bool:
2912 found = False
2913 for endpoint in (relation.provider, relation.requirer):
2914 if endpoint["kdu-resource-profile-id"]:
2915 continue
2916 found = (
2917 vca.vnf_profile_id == endpoint.vnf_profile_id
2918 and vca.vdu_profile_id == endpoint.vdu_profile_id
2919 and vca.execution_environment_ref == endpoint.execution_environment_ref
2920 )
2921 if found:
2922 break
2923 return found
2924
2925 def _update_ee_relation_data_with_implicit_data(
2926 self, nsr_id, nsd, ee_relation_data, cached_vnfds, vnf_profile_id: str = None
2927 ):
2928 ee_relation_data = safe_get_ee_relation(
2929 nsr_id, ee_relation_data, vnf_profile_id=vnf_profile_id
2930 )
2931 ee_relation_level = EELevel.get_level(ee_relation_data)
2932 if (ee_relation_level in (EELevel.VNF, EELevel.VDU)) and not ee_relation_data[
2933 "execution-environment-ref"
2934 ]:
2935 vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
2936 vnfd_id = vnf_profile["vnfd-id"]
2937 db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
2938 entity_id = (
2939 vnfd_id
2940 if ee_relation_level == EELevel.VNF
2941 else ee_relation_data["vdu-profile-id"]
2942 )
2943 ee = get_juju_ee_ref(db_vnfd, entity_id)
2944 if not ee:
2945 raise Exception(
2946 f"not execution environments found for ee_relation {ee_relation_data}"
2947 )
2948 ee_relation_data["execution-environment-ref"] = ee["id"]
2949 return ee_relation_data
2950
2951 def _get_ns_relations(
2952 self,
2953 nsr_id: str,
2954 nsd: Dict[str, Any],
2955 vca: DeployedVCA,
2956 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01002957 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02002958 relations = []
2959 db_ns_relations = get_ns_configuration_relation_list(nsd)
2960 for r in db_ns_relations:
David Garcia444bf962021-11-11 16:35:26 +01002961 provider_dict = None
2962 requirer_dict = None
2963 if all(key in r for key in ("provider", "requirer")):
2964 provider_dict = r["provider"]
2965 requirer_dict = r["requirer"]
2966 elif "entities" in r:
2967 provider_id = r["entities"][0]["id"]
2968 provider_dict = {
2969 "nsr-id": nsr_id,
2970 "endpoint": r["entities"][0]["endpoint"],
2971 }
2972 if provider_id != nsd["id"]:
2973 provider_dict["vnf-profile-id"] = provider_id
2974 requirer_id = r["entities"][1]["id"]
2975 requirer_dict = {
2976 "nsr-id": nsr_id,
2977 "endpoint": r["entities"][1]["endpoint"],
2978 }
2979 if requirer_id != nsd["id"]:
2980 requirer_dict["vnf-profile-id"] = requirer_id
2981 else:
aticig15db6142022-01-24 12:51:26 +03002982 raise Exception(
2983 "provider/requirer or entities must be included in the relation."
2984 )
David Garciab4ebcd02021-10-28 02:00:43 +02002985 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01002986 nsr_id, nsd, provider_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02002987 )
2988 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01002989 nsr_id, nsd, requirer_dict, cached_vnfds
David Garciab4ebcd02021-10-28 02:00:43 +02002990 )
2991 provider = EERelation(relation_provider)
2992 requirer = EERelation(relation_requirer)
2993 relation = Relation(r["name"], provider, requirer)
2994 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
2995 if vca_in_relation:
2996 relations.append(relation)
2997 return relations
2998
2999 def _get_vnf_relations(
3000 self,
3001 nsr_id: str,
3002 nsd: Dict[str, Any],
3003 vca: DeployedVCA,
3004 cached_vnfds: Dict[str, Any],
David Garcia444bf962021-11-11 16:35:26 +01003005 ) -> List[Relation]:
David Garciab4ebcd02021-10-28 02:00:43 +02003006 relations = []
3007 vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
3008 vnf_profile_id = vnf_profile["id"]
3009 vnfd_id = vnf_profile["vnfd-id"]
3010 db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
3011 db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
3012 for r in db_vnf_relations:
David Garcia444bf962021-11-11 16:35:26 +01003013 provider_dict = None
3014 requirer_dict = None
3015 if all(key in r for key in ("provider", "requirer")):
3016 provider_dict = r["provider"]
3017 requirer_dict = r["requirer"]
3018 elif "entities" in r:
3019 provider_id = r["entities"][0]["id"]
3020 provider_dict = {
3021 "nsr-id": nsr_id,
3022 "vnf-profile-id": vnf_profile_id,
3023 "endpoint": r["entities"][0]["endpoint"],
3024 }
3025 if provider_id != vnfd_id:
3026 provider_dict["vdu-profile-id"] = provider_id
3027 requirer_id = r["entities"][1]["id"]
3028 requirer_dict = {
3029 "nsr-id": nsr_id,
3030 "vnf-profile-id": vnf_profile_id,
3031 "endpoint": r["entities"][1]["endpoint"],
3032 }
3033 if requirer_id != vnfd_id:
3034 requirer_dict["vdu-profile-id"] = requirer_id
3035 else:
aticig15db6142022-01-24 12:51:26 +03003036 raise Exception(
3037 "provider/requirer or entities must be included in the relation."
3038 )
David Garciab4ebcd02021-10-28 02:00:43 +02003039 relation_provider = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003040 nsr_id, nsd, provider_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003041 )
3042 relation_requirer = self._update_ee_relation_data_with_implicit_data(
David Garcia444bf962021-11-11 16:35:26 +01003043 nsr_id, nsd, requirer_dict, cached_vnfds, vnf_profile_id=vnf_profile_id
David Garciab4ebcd02021-10-28 02:00:43 +02003044 )
3045 provider = EERelation(relation_provider)
3046 requirer = EERelation(relation_requirer)
3047 relation = Relation(r["name"], provider, requirer)
3048 vca_in_relation = self._is_deployed_vca_in_relation(vca, relation)
3049 if vca_in_relation:
3050 relations.append(relation)
3051 return relations
3052
3053 def _get_kdu_resource_data(
3054 self,
3055 ee_relation: EERelation,
3056 db_nsr: Dict[str, Any],
3057 cached_vnfds: Dict[str, Any],
3058 ) -> DeployedK8sResource:
3059 nsd = get_nsd(db_nsr)
3060 vnf_profiles = get_vnf_profiles(nsd)
3061 vnfd_id = find_in_list(
3062 vnf_profiles,
3063 lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
3064 )["vnfd-id"]
3065 db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
3066 kdu_resource_profile = get_kdu_resource_profile(
3067 db_vnfd, ee_relation.kdu_resource_profile_id
3068 )
3069 kdu_name = kdu_resource_profile["kdu-name"]
3070 deployed_kdu, _ = get_deployed_kdu(
3071 db_nsr.get("_admin", ()).get("deployed", ()),
3072 kdu_name,
3073 ee_relation.vnf_profile_id,
3074 )
3075 deployed_kdu.update({"resource-name": kdu_resource_profile["resource-name"]})
3076 return deployed_kdu
3077
3078 def _get_deployed_component(
3079 self,
3080 ee_relation: EERelation,
3081 db_nsr: Dict[str, Any],
3082 cached_vnfds: Dict[str, Any],
3083 ) -> DeployedComponent:
3084 nsr_id = db_nsr["_id"]
3085 deployed_component = None
3086 ee_level = EELevel.get_level(ee_relation)
3087 if ee_level == EELevel.NS:
3088 vca = get_deployed_vca(db_nsr, {"vdu_id": None, "member-vnf-index": None})
3089 if vca:
3090 deployed_component = DeployedVCA(nsr_id, vca)
3091 elif ee_level == EELevel.VNF:
3092 vca = get_deployed_vca(
3093 db_nsr,
3094 {
3095 "vdu_id": None,
3096 "member-vnf-index": ee_relation.vnf_profile_id,
3097 "ee_descriptor_id": ee_relation.execution_environment_ref,
3098 },
3099 )
3100 if vca:
3101 deployed_component = DeployedVCA(nsr_id, vca)
3102 elif ee_level == EELevel.VDU:
3103 vca = get_deployed_vca(
3104 db_nsr,
3105 {
3106 "vdu_id": ee_relation.vdu_profile_id,
3107 "member-vnf-index": ee_relation.vnf_profile_id,
3108 "ee_descriptor_id": ee_relation.execution_environment_ref,
3109 },
3110 )
3111 if vca:
3112 deployed_component = DeployedVCA(nsr_id, vca)
3113 elif ee_level == EELevel.KDU:
3114 kdu_resource_data = self._get_kdu_resource_data(
3115 ee_relation, db_nsr, cached_vnfds
3116 )
3117 if kdu_resource_data:
3118 deployed_component = DeployedK8sResource(kdu_resource_data)
3119 return deployed_component
3120
3121 async def _add_relation(
3122 self,
3123 relation: Relation,
3124 vca_type: str,
3125 db_nsr: Dict[str, Any],
3126 cached_vnfds: Dict[str, Any],
3127 cached_vnfrs: Dict[str, Any],
3128 ) -> bool:
3129 deployed_provider = self._get_deployed_component(
3130 relation.provider, db_nsr, cached_vnfds
3131 )
3132 deployed_requirer = self._get_deployed_component(
3133 relation.requirer, db_nsr, cached_vnfds
3134 )
3135 if (
3136 deployed_provider
3137 and deployed_requirer
3138 and deployed_provider.config_sw_installed
3139 and deployed_requirer.config_sw_installed
3140 ):
3141 provider_db_vnfr = (
3142 self._get_vnfr(
3143 relation.provider.nsr_id,
3144 relation.provider.vnf_profile_id,
3145 cached_vnfrs,
3146 )
3147 if relation.provider.vnf_profile_id
3148 else None
3149 )
3150 requirer_db_vnfr = (
3151 self._get_vnfr(
3152 relation.requirer.nsr_id,
3153 relation.requirer.vnf_profile_id,
3154 cached_vnfrs,
3155 )
3156 if relation.requirer.vnf_profile_id
3157 else None
3158 )
3159 provider_vca_id = self.get_vca_id(provider_db_vnfr, db_nsr)
3160 requirer_vca_id = self.get_vca_id(requirer_db_vnfr, db_nsr)
3161 provider_relation_endpoint = RelationEndpoint(
3162 deployed_provider.ee_id,
3163 provider_vca_id,
3164 relation.provider.endpoint,
3165 )
3166 requirer_relation_endpoint = RelationEndpoint(
3167 deployed_requirer.ee_id,
3168 requirer_vca_id,
3169 relation.requirer.endpoint,
3170 )
3171 await self.vca_map[vca_type].add_relation(
3172 provider=provider_relation_endpoint,
3173 requirer=requirer_relation_endpoint,
3174 )
3175 # remove entry from relations list
3176 return True
3177 return False
3178
David Garciac1fe90a2021-03-31 19:12:02 +02003179 async def _add_vca_relations(
3180 self,
3181 logging_text,
3182 nsr_id,
David Garciab4ebcd02021-10-28 02:00:43 +02003183 vca_type: str,
David Garciac1fe90a2021-03-31 19:12:02 +02003184 vca_index: int,
3185 timeout: int = 3600,
David Garciac1fe90a2021-03-31 19:12:02 +02003186 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00003187
3188 # steps:
3189 # 1. find all relations for this VCA
3190 # 2. wait for other peers related
3191 # 3. add relations
3192
3193 try:
quilesj63f90042020-01-17 09:53:55 +00003194 # STEP 1: find all relations for this VCA
3195
3196 # read nsr record
3197 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciab4ebcd02021-10-28 02:00:43 +02003198 nsd = get_nsd(db_nsr)
quilesj63f90042020-01-17 09:53:55 +00003199
3200 # this VCA data
David Garciab4ebcd02021-10-28 02:00:43 +02003201 deployed_vca_dict = get_deployed_vca_list(db_nsr)[vca_index]
3202 my_vca = DeployedVCA(nsr_id, deployed_vca_dict)
quilesj63f90042020-01-17 09:53:55 +00003203
David Garciab4ebcd02021-10-28 02:00:43 +02003204 cached_vnfds = {}
3205 cached_vnfrs = {}
3206 relations = []
3207 relations.extend(self._get_ns_relations(nsr_id, nsd, my_vca, cached_vnfds))
3208 relations.extend(self._get_vnf_relations(nsr_id, nsd, my_vca, cached_vnfds))
quilesj63f90042020-01-17 09:53:55 +00003209
3210 # if no relations, terminate
David Garciab4ebcd02021-10-28 02:00:43 +02003211 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003212 self.logger.debug(logging_text + " No relations")
quilesj63f90042020-01-17 09:53:55 +00003213 return True
3214
David Garciab4ebcd02021-10-28 02:00:43 +02003215 self.logger.debug(logging_text + " adding relations {}".format(relations))
quilesj63f90042020-01-17 09:53:55 +00003216
3217 # add all relations
3218 start = time()
3219 while True:
3220 # check timeout
3221 now = time()
3222 if now - start >= timeout:
garciadeblas5697b8b2021-03-24 09:17:02 +01003223 self.logger.error(logging_text + " : timeout adding relations")
quilesj63f90042020-01-17 09:53:55 +00003224 return False
3225
David Garciab4ebcd02021-10-28 02:00:43 +02003226 # reload nsr from database (we need to update record: _admin.deployed.VCA)
quilesj63f90042020-01-17 09:53:55 +00003227 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3228
David Garciab4ebcd02021-10-28 02:00:43 +02003229 # for each relation, find the VCA's related
3230 for relation in relations.copy():
3231 added = await self._add_relation(
3232 relation,
3233 vca_type,
3234 db_nsr,
3235 cached_vnfds,
3236 cached_vnfrs,
3237 )
3238 if added:
3239 relations.remove(relation)
quilesj63f90042020-01-17 09:53:55 +00003240
David Garciab4ebcd02021-10-28 02:00:43 +02003241 if not relations:
garciadeblas5697b8b2021-03-24 09:17:02 +01003242 self.logger.debug("Relations added")
quilesj63f90042020-01-17 09:53:55 +00003243 break
David Garciab4ebcd02021-10-28 02:00:43 +02003244 await asyncio.sleep(5.0)
quilesj63f90042020-01-17 09:53:55 +00003245
3246 return True
3247
3248 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003249 self.logger.warn(logging_text + " ERROR adding relations: {}".format(e))
quilesj63f90042020-01-17 09:53:55 +00003250 return False
3251
garciadeblas5697b8b2021-03-24 09:17:02 +01003252 async def _install_kdu(
3253 self,
3254 nsr_id: str,
3255 nsr_db_path: str,
3256 vnfr_data: dict,
3257 kdu_index: int,
3258 kdud: dict,
3259 vnfd: dict,
3260 k8s_instance_info: dict,
3261 k8params: dict = None,
3262 timeout: int = 600,
3263 vca_id: str = None,
3264 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003265
tiernob9018152020-04-16 14:18:24 +00003266 try:
lloretgalleg7c121132020-07-08 07:53:22 +00003267 k8sclustertype = k8s_instance_info["k8scluster-type"]
3268 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003269 db_dict_install = {
3270 "collection": "nsrs",
3271 "filter": {"_id": nsr_id},
3272 "path": nsr_db_path,
3273 }
lloretgalleg7c121132020-07-08 07:53:22 +00003274
romeromonser4554a702021-05-28 12:00:08 +02003275 if k8s_instance_info.get("kdu-deployment-name"):
3276 kdu_instance = k8s_instance_info.get("kdu-deployment-name")
3277 else:
3278 kdu_instance = self.k8scluster_map[
3279 k8sclustertype
3280 ].generate_kdu_instance_name(
3281 db_dict=db_dict_install,
3282 kdu_model=k8s_instance_info["kdu-model"],
3283 kdu_name=k8s_instance_info["kdu-name"],
3284 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003285
3286 # Update the nsrs table with the kdu-instance value
garciadeblas5697b8b2021-03-24 09:17:02 +01003287 self.update_db_2(
Pedro Escaleirada21d262022-04-21 16:31:06 +01003288 item="nsrs",
3289 _id=nsr_id,
3290 _desc={nsr_db_path + ".kdu-instance": kdu_instance},
garciadeblas5697b8b2021-03-24 09:17:02 +01003291 )
Pedro Escaleirada21d262022-04-21 16:31:06 +01003292
3293 # Update the nsrs table with the actual namespace being used, if the k8scluster-type is `juju` or
3294 # `juju-bundle`. This verification is needed because there is not a standard/homogeneous namespace
3295 # between the Helm Charts and Juju Bundles-based KNFs. If we found a way of having an homogeneous
3296 # namespace, this first verification could be removed, and the next step would be done for any kind
3297 # of KNF.
3298 # TODO -> find a way to have an homogeneous namespace between the Helm Charts and Juju Bundles-based
3299 # KNFs (Bug 2027: https://osm.etsi.org/bugzilla/show_bug.cgi?id=2027)
3300 if k8sclustertype in ("juju", "juju-bundle"):
3301 # First, verify if the current namespace is present in the `_admin.projects_read` (if not, it means
3302 # that the user passed a namespace which he wants its KDU to be deployed in)
3303 if (
3304 self.db.count(
3305 table="nsrs",
3306 q_filter={
3307 "_id": nsr_id,
3308 "_admin.projects_write": k8s_instance_info["namespace"],
3309 "_admin.projects_read": k8s_instance_info["namespace"],
3310 },
3311 )
3312 > 0
3313 ):
3314 self.logger.debug(
3315 f"Updating namespace/model for Juju Bundle from {k8s_instance_info['namespace']} to {kdu_instance}"
3316 )
3317 self.update_db_2(
3318 item="nsrs",
3319 _id=nsr_id,
3320 _desc={f"{nsr_db_path}.namespace": kdu_instance},
3321 )
3322 k8s_instance_info["namespace"] = kdu_instance
3323
David Garciad64e2742021-02-25 20:19:18 +01003324 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00003325 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3326 kdu_model=k8s_instance_info["kdu-model"],
3327 atomic=True,
3328 params=k8params,
3329 db_dict=db_dict_install,
3330 timeout=timeout,
3331 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01003332 namespace=k8s_instance_info["namespace"],
3333 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02003334 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01003335 )
lloretgalleg7c121132020-07-08 07:53:22 +00003336
3337 # Obtain services to obtain management service ip
3338 services = await self.k8scluster_map[k8sclustertype].get_services(
3339 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3340 kdu_instance=kdu_instance,
garciadeblas5697b8b2021-03-24 09:17:02 +01003341 namespace=k8s_instance_info["namespace"],
3342 )
lloretgalleg7c121132020-07-08 07:53:22 +00003343
3344 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00003345 vnfr_update_dict = {}
bravof6ec62b72021-02-25 17:20:35 -03003346 kdu_config = get_configuration(vnfd, kdud["name"])
3347 if kdu_config:
3348 target_ee_list = kdu_config.get("execution-environment-list", [])
3349 else:
3350 target_ee_list = []
3351
lloretgalleg7c121132020-07-08 07:53:22 +00003352 if services:
tierno7ecbc342020-09-21 14:05:39 +00003353 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
garciadeblas5697b8b2021-03-24 09:17:02 +01003354 mgmt_services = [
3355 service
3356 for service in kdud.get("service", [])
3357 if service.get("mgmt-service")
3358 ]
lloretgalleg7c121132020-07-08 07:53:22 +00003359 for mgmt_service in mgmt_services:
3360 for service in services:
3361 if service["name"].startswith(mgmt_service["name"]):
3362 # Mgmt service found, Obtain service ip
3363 ip = service.get("external_ip", service.get("cluster_ip"))
3364 if isinstance(ip, list) and len(ip) == 1:
3365 ip = ip[0]
3366
garciadeblas5697b8b2021-03-24 09:17:02 +01003367 vnfr_update_dict[
3368 "kdur.{}.ip-address".format(kdu_index)
3369 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003370
3371 # Check if must update also mgmt ip at the vnf
garciadeblas5697b8b2021-03-24 09:17:02 +01003372 service_external_cp = mgmt_service.get(
3373 "external-connection-point-ref"
3374 )
lloretgalleg7c121132020-07-08 07:53:22 +00003375 if service_external_cp:
garciadeblas5697b8b2021-03-24 09:17:02 +01003376 if (
3377 deep_get(vnfd, ("mgmt-interface", "cp"))
3378 == service_external_cp
3379 ):
lloretgalleg7c121132020-07-08 07:53:22 +00003380 vnfr_update_dict["ip-address"] = ip
3381
bravof6ec62b72021-02-25 17:20:35 -03003382 if find_in_list(
3383 target_ee_list,
garciadeblas5697b8b2021-03-24 09:17:02 +01003384 lambda ee: ee.get(
3385 "external-connection-point-ref", ""
3386 )
3387 == service_external_cp,
bravof6ec62b72021-02-25 17:20:35 -03003388 ):
garciadeblas5697b8b2021-03-24 09:17:02 +01003389 vnfr_update_dict[
3390 "kdur.{}.ip-address".format(kdu_index)
3391 ] = ip
lloretgalleg7c121132020-07-08 07:53:22 +00003392 break
3393 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003394 self.logger.warn(
3395 "Mgmt service name: {} not found".format(
3396 mgmt_service["name"]
3397 )
3398 )
lloretgalleg7c121132020-07-08 07:53:22 +00003399
tierno7ecbc342020-09-21 14:05:39 +00003400 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
3401 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00003402
bravof9a256db2021-02-22 18:02:07 -03003403 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
garciadeblas5697b8b2021-03-24 09:17:02 +01003404 if (
3405 kdu_config
3406 and kdu_config.get("initial-config-primitive")
3407 and get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None
3408 ):
3409 initial_config_primitive_list = kdu_config.get(
3410 "initial-config-primitive"
3411 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003412 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
3413
3414 for initial_config_primitive in initial_config_primitive_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003415 primitive_params_ = self._map_primitive_params(
3416 initial_config_primitive, {}, {}
3417 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003418
3419 await asyncio.wait_for(
3420 self.k8scluster_map[k8sclustertype].exec_primitive(
3421 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
3422 kdu_instance=kdu_instance,
3423 primitive_name=initial_config_primitive["name"],
garciadeblas5697b8b2021-03-24 09:17:02 +01003424 params=primitive_params_,
3425 db_dict=db_dict_install,
David Garciac1fe90a2021-03-31 19:12:02 +02003426 vca_id=vca_id,
3427 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01003428 timeout=timeout,
David Garciac1fe90a2021-03-31 19:12:02 +02003429 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02003430
tiernob9018152020-04-16 14:18:24 +00003431 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00003432 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00003433 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003434 self.update_db_2(
3435 "nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}
3436 )
3437 self.update_db_2(
3438 "vnfrs",
3439 vnfr_data.get("_id"),
3440 {"kdur.{}.status".format(kdu_index): "ERROR"},
3441 )
tiernob9018152020-04-16 14:18:24 +00003442 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00003443 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00003444 pass
lloretgalleg7c121132020-07-08 07:53:22 +00003445 # reraise original error
3446 raise
3447
3448 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00003449
garciadeblas5697b8b2021-03-24 09:17:02 +01003450 async def deploy_kdus(
3451 self,
3452 logging_text,
3453 nsr_id,
3454 nslcmop_id,
3455 db_vnfrs,
3456 db_vnfds,
3457 task_instantiation_info,
3458 ):
calvinosanch9f9c6f22019-11-04 13:37:39 +01003459 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00003460
garciadeblas5697b8b2021-03-24 09:17:02 +01003461 k8scluster_id_2_uuic = {
3462 "helm-chart-v3": {},
3463 "helm-chart": {},
3464 "juju-bundle": {},
3465 }
tierno626e0152019-11-29 14:16:16 +00003466
tierno16f4a4e2020-07-20 09:05:51 +00003467 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00003468 nonlocal k8scluster_id_2_uuic
3469 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
3470 return k8scluster_id_2_uuic[cluster_type][cluster_id]
3471
tierno16f4a4e2020-07-20 09:05:51 +00003472 # check if K8scluster is creating and wait look if previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01003473 task_name, task_dependency = self.lcm_tasks.lookfor_related(
3474 "k8scluster", cluster_id
3475 )
tierno16f4a4e2020-07-20 09:05:51 +00003476 if task_dependency:
garciadeblas5697b8b2021-03-24 09:17:02 +01003477 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(
3478 task_name, cluster_id
3479 )
tierno16f4a4e2020-07-20 09:05:51 +00003480 self.logger.debug(logging_text + text)
3481 await asyncio.wait(task_dependency, timeout=3600)
3482
garciadeblas5697b8b2021-03-24 09:17:02 +01003483 db_k8scluster = self.db.get_one(
3484 "k8sclusters", {"_id": cluster_id}, fail_on_empty=False
3485 )
tierno626e0152019-11-29 14:16:16 +00003486 if not db_k8scluster:
3487 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00003488
tierno626e0152019-11-29 14:16:16 +00003489 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
3490 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003491 if cluster_type == "helm-chart-v3":
3492 try:
3493 # backward compatibility for existing clusters that have not been initialized for helm v3
garciadeblas5697b8b2021-03-24 09:17:02 +01003494 k8s_credentials = yaml.safe_dump(
3495 db_k8scluster.get("credentials")
3496 )
3497 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(
3498 k8s_credentials, reuse_cluster_uuid=cluster_id
3499 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003500 db_k8scluster_update = {}
3501 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
3502 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
garciadeblas5697b8b2021-03-24 09:17:02 +01003503 db_k8scluster_update[
3504 "_admin.helm-chart-v3.created"
3505 ] = uninstall_sw
3506 db_k8scluster_update[
3507 "_admin.helm-chart-v3.operationalState"
3508 ] = "ENABLED"
3509 self.update_db_2(
3510 "k8sclusters", cluster_id, db_k8scluster_update
3511 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003512 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01003513 self.logger.error(
3514 logging_text
3515 + "error initializing helm-v3 cluster: {}".format(str(e))
3516 )
3517 raise LcmException(
3518 "K8s cluster '{}' has not been initialized for '{}'".format(
3519 cluster_id, cluster_type
3520 )
3521 )
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003522 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003523 raise LcmException(
3524 "K8s cluster '{}' has not been initialized for '{}'".format(
3525 cluster_id, cluster_type
3526 )
3527 )
tierno626e0152019-11-29 14:16:16 +00003528 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
3529 return k8s_id
3530
3531 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00003532 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01003533 try:
tierno626e0152019-11-29 14:16:16 +00003534 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003535 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003536
tierno626e0152019-11-29 14:16:16 +00003537 index = 0
tiernoe876f672020-02-13 14:34:48 +00003538 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003539 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00003540
tierno626e0152019-11-29 14:16:16 +00003541 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02003542 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00003543 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
3544 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03003545 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
garciadeblas5697b8b2021-03-24 09:17:02 +01003546 vnfd_id = vnfr_data.get("vnfd-id")
3547 vnfd_with_id = find_in_list(
3548 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3549 )
3550 kdud = next(
3551 kdud
3552 for kdud in vnfd_with_id["kdu"]
3553 if kdud["name"] == kdur["kdu-name"]
3554 )
tiernode1584f2020-04-07 09:07:33 +00003555 namespace = kdur.get("k8s-namespace")
romeromonser4554a702021-05-28 12:00:08 +02003556 kdu_deployment_name = kdur.get("kdu-deployment-name")
tierno626e0152019-11-29 14:16:16 +00003557 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003558 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003559 # Default version: helm3, if helm-version is v2 assign v2
3560 k8sclustertype = "helm-chart-v3"
3561 self.logger.debug("kdur: {}".format(kdur))
garciadeblas5697b8b2021-03-24 09:17:02 +01003562 if (
3563 kdur.get("helm-version")
3564 and kdur.get("helm-version") == "v2"
3565 ):
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003566 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00003567 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00003568 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00003569 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00003570 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003571 raise LcmException(
3572 "kdu type for kdu='{}.{}' is neither helm-chart nor "
3573 "juju-bundle. Maybe an old NBI version is running".format(
3574 vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]
3575 )
3576 )
quilesjacde94f2020-01-23 10:07:08 +00003577 # check if kdumodel is a file and exists
3578 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01003579 vnfd_with_id = find_in_list(
3580 db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id
3581 )
3582 storage = deep_get(vnfd_with_id, ("_admin", "storage"))
bravof486707f2021-11-08 17:18:50 -03003583 if storage: # may be not present if vnfd has not artifacts
tierno51183952020-04-03 15:48:18 +00003584 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
bravof486707f2021-11-08 17:18:50 -03003585 if storage["pkg-dir"]:
3586 filename = "{}/{}/{}s/{}".format(
3587 storage["folder"],
3588 storage["pkg-dir"],
3589 k8sclustertype,
3590 kdumodel,
3591 )
3592 else:
3593 filename = "{}/Scripts/{}s/{}".format(
3594 storage["folder"],
3595 k8sclustertype,
3596 kdumodel,
3597 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003598 if self.fs.file_exists(
3599 filename, mode="file"
3600 ) or self.fs.file_exists(filename, mode="dir"):
tierno51183952020-04-03 15:48:18 +00003601 kdumodel = self.fs.path + filename
3602 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003603 raise
garciadeblas5697b8b2021-03-24 09:17:02 +01003604 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00003605 pass
lloretgallegedc5f332020-02-20 11:50:50 +01003606
tiernoe876f672020-02-13 14:34:48 +00003607 k8s_cluster_id = kdur["k8s-cluster"]["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01003608 step = "Synchronize repos for k8s cluster '{}'".format(
3609 k8s_cluster_id
3610 )
tierno16f4a4e2020-07-20 09:05:51 +00003611 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01003612
lloretgalleg7c121132020-07-08 07:53:22 +00003613 # Synchronize repos
garciadeblas5697b8b2021-03-24 09:17:02 +01003614 if (
3615 k8sclustertype == "helm-chart"
3616 and cluster_uuid not in updated_cluster_list
3617 ) or (
3618 k8sclustertype == "helm-chart-v3"
3619 and cluster_uuid not in updated_v3_cluster_list
3620 ):
tiernoe876f672020-02-13 14:34:48 +00003621 del_repo_list, added_repo_dict = await asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003622 self.k8scluster_map[k8sclustertype].synchronize_repos(
3623 cluster_uuid=cluster_uuid
3624 )
3625 )
tiernoe876f672020-02-13 14:34:48 +00003626 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003627 if k8sclustertype == "helm-chart":
garciadeblas5697b8b2021-03-24 09:17:02 +01003628 unset = {
3629 "_admin.helm_charts_added." + item: None
3630 for item in del_repo_list
3631 }
3632 updated = {
3633 "_admin.helm_charts_added." + item: name
3634 for item, name in added_repo_dict.items()
3635 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003636 updated_cluster_list.append(cluster_uuid)
3637 elif k8sclustertype == "helm-chart-v3":
garciadeblas5697b8b2021-03-24 09:17:02 +01003638 unset = {
3639 "_admin.helm_charts_v3_added." + item: None
3640 for item in del_repo_list
3641 }
3642 updated = {
3643 "_admin.helm_charts_v3_added." + item: name
3644 for item, name in added_repo_dict.items()
3645 }
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003646 updated_v3_cluster_list.append(cluster_uuid)
garciadeblas5697b8b2021-03-24 09:17:02 +01003647 self.logger.debug(
3648 logging_text + "repos synchronized on k8s cluster "
3649 "'{}' to_delete: {}, to_add: {}".format(
3650 k8s_cluster_id, del_repo_list, added_repo_dict
3651 )
3652 )
3653 self.db.set_one(
3654 "k8sclusters",
3655 {"_id": k8s_cluster_id},
3656 updated,
3657 unset=unset,
3658 )
lloretgallegedc5f332020-02-20 11:50:50 +01003659
lloretgalleg7c121132020-07-08 07:53:22 +00003660 # Instantiate kdu
garciadeblas5697b8b2021-03-24 09:17:02 +01003661 step = "Instantiating KDU {}.{} in k8s cluster {}".format(
3662 vnfr_data["member-vnf-index-ref"],
3663 kdur["kdu-name"],
3664 k8s_cluster_id,
3665 )
3666 k8s_instance_info = {
3667 "kdu-instance": None,
3668 "k8scluster-uuid": cluster_uuid,
3669 "k8scluster-type": k8sclustertype,
3670 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
3671 "kdu-name": kdur["kdu-name"],
3672 "kdu-model": kdumodel,
3673 "namespace": namespace,
romeromonser4554a702021-05-28 12:00:08 +02003674 "kdu-deployment-name": kdu_deployment_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003675 }
tiernob9018152020-04-16 14:18:24 +00003676 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00003677 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00003678 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01003679 vnfd_with_id = find_in_list(
3680 db_vnfds, lambda vnf: vnf["_id"] == vnfd_id
3681 )
tiernoa2143262020-03-27 16:20:40 +00003682 task = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01003683 self._install_kdu(
3684 nsr_id,
3685 db_path,
3686 vnfr_data,
3687 kdu_index,
3688 kdud,
3689 vnfd_with_id,
3690 k8s_instance_info,
3691 k8params=desc_params,
Alexis Romeroab16ae82022-05-17 18:18:02 +02003692 timeout=1800,
garciadeblas5697b8b2021-03-24 09:17:02 +01003693 vca_id=vca_id,
3694 )
3695 )
3696 self.lcm_tasks.register(
3697 "ns",
3698 nsr_id,
3699 nslcmop_id,
3700 "instantiate_KDU-{}".format(index),
3701 task,
3702 )
3703 task_instantiation_info[task] = "Deploying KDU {}".format(
3704 kdur["kdu-name"]
3705 )
tiernoe876f672020-02-13 14:34:48 +00003706
tierno626e0152019-11-29 14:16:16 +00003707 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00003708
tiernoe876f672020-02-13 14:34:48 +00003709 except (LcmException, asyncio.CancelledError):
3710 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01003711 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003712 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
3713 if isinstance(e, (N2VCException, DbException)):
3714 self.logger.error(logging_text + msg)
3715 else:
3716 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00003717 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003718 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01003719 if db_nsr_update:
3720 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00003721
garciadeblas5697b8b2021-03-24 09:17:02 +01003722 def _deploy_n2vc(
3723 self,
3724 logging_text,
3725 db_nsr,
3726 db_vnfr,
3727 nslcmop_id,
3728 nsr_id,
3729 nsi_id,
3730 vnfd_id,
3731 vdu_id,
3732 kdu_name,
3733 member_vnf_index,
3734 vdu_index,
3735 vdu_name,
3736 deploy_params,
3737 descriptor_config,
3738 base_folder,
3739 task_instantiation_info,
3740 stage,
3741 ):
quilesj7e13aeb2019-10-08 13:34:55 +02003742 # launch instantiate_N2VC in a asyncio task and register task object
3743 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
3744 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02003745 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00003746
garciadeblas5697b8b2021-03-24 09:17:02 +01003747 self.logger.debug(
3748 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
3749 )
aticig9bc63ac2022-07-27 09:32:06 +03003750
3751 charm_name = ""
3752 get_charm_name = False
bravof9a256db2021-02-22 18:02:07 -03003753 if "execution-environment-list" in descriptor_config:
3754 ee_list = descriptor_config.get("execution-environment-list", [])
David Garcia9ad54a42021-05-28 12:08:18 +02003755 elif "juju" in descriptor_config:
3756 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03003757 if "execution-environment-list" not in descriptor_config:
3758 # charm name is only required for ns charms
3759 get_charm_name = True
tierno588547c2020-07-01 15:30:20 +00003760 else: # other types as script are not supported
3761 ee_list = []
3762
3763 for ee_item in ee_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01003764 self.logger.debug(
3765 logging_text
3766 + "_deploy_n2vc ee_item juju={}, helm={}".format(
3767 ee_item.get("juju"), ee_item.get("helm-chart")
3768 )
3769 )
tiernoa278b842020-07-08 15:33:55 +00003770 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00003771 if ee_item.get("juju"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003772 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03003773 if get_charm_name:
3774 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas5697b8b2021-03-24 09:17:02 +01003775 vca_type = (
3776 "lxc_proxy_charm"
3777 if ee_item["juju"].get("charm") is not None
3778 else "native_charm"
3779 )
3780 if ee_item["juju"].get("cloud") == "k8s":
tierno588547c2020-07-01 15:30:20 +00003781 vca_type = "k8s_proxy_charm"
garciadeblas5697b8b2021-03-24 09:17:02 +01003782 elif ee_item["juju"].get("proxy") is False:
tierno588547c2020-07-01 15:30:20 +00003783 vca_type = "native_charm"
3784 elif ee_item.get("helm-chart"):
garciadeblas5697b8b2021-03-24 09:17:02 +01003785 vca_name = ee_item["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003786 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
3787 vca_type = "helm"
3788 else:
3789 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00003790 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01003791 self.logger.debug(
3792 logging_text + "skipping non juju neither charm configuration"
3793 )
quilesj7e13aeb2019-10-08 13:34:55 +02003794 continue
quilesj3655ae02019-12-12 16:08:35 +00003795
tierno588547c2020-07-01 15:30:20 +00003796 vca_index = -1
garciadeblas5697b8b2021-03-24 09:17:02 +01003797 for vca_index, vca_deployed in enumerate(
3798 db_nsr["_admin"]["deployed"]["VCA"]
3799 ):
tierno588547c2020-07-01 15:30:20 +00003800 if not vca_deployed:
3801 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01003802 if (
3803 vca_deployed.get("member-vnf-index") == member_vnf_index
3804 and vca_deployed.get("vdu_id") == vdu_id
3805 and vca_deployed.get("kdu_name") == kdu_name
3806 and vca_deployed.get("vdu_count_index", 0) == vdu_index
3807 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
3808 ):
tierno588547c2020-07-01 15:30:20 +00003809 break
3810 else:
3811 # not found, create one.
garciadeblas5697b8b2021-03-24 09:17:02 +01003812 target = (
3813 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
3814 )
tiernoa278b842020-07-08 15:33:55 +00003815 if vdu_id:
3816 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
3817 elif kdu_name:
3818 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00003819 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00003820 "target_element": target,
3821 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00003822 "member-vnf-index": member_vnf_index,
3823 "vdu_id": vdu_id,
3824 "kdu_name": kdu_name,
3825 "vdu_count_index": vdu_index,
3826 "operational-status": "init", # TODO revise
3827 "detailed-status": "", # TODO revise
garciadeblas5697b8b2021-03-24 09:17:02 +01003828 "step": "initial-deploy", # TODO revise
tierno588547c2020-07-01 15:30:20 +00003829 "vnfd_id": vnfd_id,
3830 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00003831 "type": vca_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01003832 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03003833 "charm_name": charm_name,
tierno588547c2020-07-01 15:30:20 +00003834 }
3835 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00003836
tierno588547c2020-07-01 15:30:20 +00003837 # create VCA and configurationStatus in db
3838 db_dict = {
3839 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
garciadeblas5697b8b2021-03-24 09:17:02 +01003840 "configurationStatus.{}".format(vca_index): dict(),
tierno588547c2020-07-01 15:30:20 +00003841 }
3842 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02003843
tierno588547c2020-07-01 15:30:20 +00003844 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
3845
bravof922c4172020-11-24 21:21:43 -03003846 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
3847 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
3848 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
3849
tierno588547c2020-07-01 15:30:20 +00003850 # Launch task
3851 task_n2vc = asyncio.ensure_future(
3852 self.instantiate_N2VC(
3853 logging_text=logging_text,
3854 vca_index=vca_index,
3855 nsi_id=nsi_id,
3856 db_nsr=db_nsr,
3857 db_vnfr=db_vnfr,
3858 vdu_id=vdu_id,
3859 kdu_name=kdu_name,
3860 vdu_index=vdu_index,
3861 deploy_params=deploy_params,
3862 config_descriptor=descriptor_config,
3863 base_folder=base_folder,
3864 nslcmop_id=nslcmop_id,
3865 stage=stage,
3866 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00003867 vca_name=vca_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01003868 ee_config_descriptor=ee_item,
tierno588547c2020-07-01 15:30:20 +00003869 )
quilesj7e13aeb2019-10-08 13:34:55 +02003870 )
garciadeblas5697b8b2021-03-24 09:17:02 +01003871 self.lcm_tasks.register(
3872 "ns",
3873 nsr_id,
3874 nslcmop_id,
3875 "instantiate_N2VC-{}".format(vca_index),
3876 task_n2vc,
3877 )
3878 task_instantiation_info[
3879 task_n2vc
3880 ] = self.task_name_deploy_vca + " {}.{}".format(
3881 member_vnf_index or "", vdu_id or ""
3882 )
tiernobaa51102018-12-14 13:16:18 +00003883
tiernoc9556972019-07-05 15:25:25 +00003884 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02003885 def _create_nslcmop(nsr_id, operation, params):
3886 """
3887 Creates a ns-lcm-opp content to be stored at database.
3888 :param nsr_id: internal id of the instance
3889 :param operation: instantiate, terminate, scale, action, ...
3890 :param params: user parameters for the operation
3891 :return: dictionary following SOL005 format
3892 """
3893 # Raise exception if invalid arguments
3894 if not (nsr_id and operation and params):
3895 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01003896 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided"
3897 )
kuuse0ca67472019-05-13 15:59:27 +02003898 now = time()
3899 _id = str(uuid4())
3900 nslcmop = {
3901 "id": _id,
3902 "_id": _id,
3903 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
3904 "operationState": "PROCESSING",
3905 "statusEnteredTime": now,
3906 "nsInstanceId": nsr_id,
3907 "lcmOperationType": operation,
3908 "startTime": now,
3909 "isAutomaticInvocation": False,
3910 "operationParams": params,
3911 "isCancelPending": False,
3912 "links": {
3913 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
3914 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01003915 },
kuuse0ca67472019-05-13 15:59:27 +02003916 }
3917 return nslcmop
3918
calvinosanch9f9c6f22019-11-04 13:37:39 +01003919 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00003920 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01003921 for key, value in params.items():
3922 if str(value).startswith("!!yaml "):
3923 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01003924 return params
3925
kuuse8b998e42019-07-30 15:22:16 +02003926 def _get_terminate_primitive_params(self, seq, vnf_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01003927 primitive = seq.get("name")
kuuse8b998e42019-07-30 15:22:16 +02003928 primitive_params = {}
3929 params = {
3930 "member_vnf_index": vnf_index,
3931 "primitive": primitive,
3932 "primitive_params": primitive_params,
3933 }
3934 desc_params = {}
3935 return self._map_primitive_params(seq, params, desc_params)
3936
kuuseac3a8882019-10-03 10:48:06 +02003937 # sub-operations
3938
tierno51183952020-04-03 15:48:18 +00003939 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
garciadeblas5697b8b2021-03-24 09:17:02 +01003940 op = deep_get(db_nslcmop, ("_admin", "operations"), [])[op_index]
3941 if op.get("operationState") == "COMPLETED":
kuuseac3a8882019-10-03 10:48:06 +02003942 # b. Skip sub-operation
3943 # _ns_execute_primitive() or RO.create_action() will NOT be executed
3944 return self.SUBOPERATION_STATUS_SKIP
3945 else:
tierno7c4e24c2020-05-13 08:41:35 +00003946 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003947 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00003948 # Update operationState = 'PROCESSING' to indicate a retry.
garciadeblas5697b8b2021-03-24 09:17:02 +01003949 operationState = "PROCESSING"
3950 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02003951 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01003952 db_nslcmop, op_index, operationState, detailed_status
3953 )
kuuseac3a8882019-10-03 10:48:06 +02003954 # Return the sub-operation index
3955 # _ns_execute_primitive() or RO.create_action() will be called from scale()
3956 # with arguments extracted from the sub-operation
3957 return op_index
3958
3959 # Find a sub-operation where all keys in a matching dictionary must match
3960 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
3961 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00003962 if db_nslcmop and match:
garciadeblas5697b8b2021-03-24 09:17:02 +01003963 op_list = db_nslcmop.get("_admin", {}).get("operations", [])
kuuseac3a8882019-10-03 10:48:06 +02003964 for i, op in enumerate(op_list):
3965 if all(op.get(k) == match[k] for k in match):
3966 return i
3967 return self.SUBOPERATION_STATUS_NOT_FOUND
3968
3969 # Update status for a sub-operation given its index
garciadeblas5697b8b2021-03-24 09:17:02 +01003970 def _update_suboperation_status(
3971 self, db_nslcmop, op_index, operationState, detailed_status
3972 ):
kuuseac3a8882019-10-03 10:48:06 +02003973 # Update DB for HA tasks
garciadeblas5697b8b2021-03-24 09:17:02 +01003974 q_filter = {"_id": db_nslcmop["_id"]}
3975 update_dict = {
3976 "_admin.operations.{}.operationState".format(op_index): operationState,
3977 "_admin.operations.{}.detailed-status".format(op_index): detailed_status,
3978 }
3979 self.db.set_one(
3980 "nslcmops", q_filter=q_filter, update_dict=update_dict, fail_on_empty=False
3981 )
kuuseac3a8882019-10-03 10:48:06 +02003982
3983 # Add sub-operation, return the index of the added sub-operation
3984 # Optionally, set operationState, detailed-status, and operationType
3985 # Status and type are currently set for 'scale' sub-operations:
3986 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
3987 # 'detailed-status' : status message
3988 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
3989 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
garciadeblas5697b8b2021-03-24 09:17:02 +01003990 def _add_suboperation(
3991 self,
3992 db_nslcmop,
3993 vnf_index,
3994 vdu_id,
3995 vdu_count_index,
3996 vdu_name,
3997 primitive,
3998 mapped_primitive_params,
3999 operationState=None,
4000 detailed_status=None,
4001 operationType=None,
4002 RO_nsr_id=None,
4003 RO_scaling_info=None,
4004 ):
tiernoe876f672020-02-13 14:34:48 +00004005 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02004006 return self.SUBOPERATION_STATUS_NOT_FOUND
4007 # Get the "_admin.operations" list, if it exists
garciadeblas5697b8b2021-03-24 09:17:02 +01004008 db_nslcmop_admin = db_nslcmop.get("_admin", {})
4009 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004010 # Create or append to the "_admin.operations" list
garciadeblas5697b8b2021-03-24 09:17:02 +01004011 new_op = {
4012 "member_vnf_index": vnf_index,
4013 "vdu_id": vdu_id,
4014 "vdu_count_index": vdu_count_index,
4015 "primitive": primitive,
4016 "primitive_params": mapped_primitive_params,
4017 }
kuuseac3a8882019-10-03 10:48:06 +02004018 if operationState:
garciadeblas5697b8b2021-03-24 09:17:02 +01004019 new_op["operationState"] = operationState
kuuseac3a8882019-10-03 10:48:06 +02004020 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01004021 new_op["detailed-status"] = detailed_status
kuuseac3a8882019-10-03 10:48:06 +02004022 if operationType:
garciadeblas5697b8b2021-03-24 09:17:02 +01004023 new_op["lcmOperationType"] = operationType
kuuseac3a8882019-10-03 10:48:06 +02004024 if RO_nsr_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004025 new_op["RO_nsr_id"] = RO_nsr_id
kuuseac3a8882019-10-03 10:48:06 +02004026 if RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004027 new_op["RO_scaling_info"] = RO_scaling_info
kuuseac3a8882019-10-03 10:48:06 +02004028 if not op_list:
4029 # No existing operations, create key 'operations' with current operation as first list element
garciadeblas5697b8b2021-03-24 09:17:02 +01004030 db_nslcmop_admin.update({"operations": [new_op]})
4031 op_list = db_nslcmop_admin.get("operations")
kuuseac3a8882019-10-03 10:48:06 +02004032 else:
4033 # Existing operations, append operation to list
4034 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02004035
garciadeblas5697b8b2021-03-24 09:17:02 +01004036 db_nslcmop_update = {"_admin.operations": op_list}
4037 self.update_db_2("nslcmops", db_nslcmop["_id"], db_nslcmop_update)
kuuseac3a8882019-10-03 10:48:06 +02004038 op_index = len(op_list) - 1
4039 return op_index
4040
4041 # Helper methods for scale() sub-operations
4042
4043 # pre-scale/post-scale:
4044 # Check for 3 different cases:
4045 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
4046 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00004047 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
garciadeblas5697b8b2021-03-24 09:17:02 +01004048 def _check_or_add_scale_suboperation(
4049 self,
4050 db_nslcmop,
4051 vnf_index,
4052 vnf_config_primitive,
4053 primitive_params,
4054 operationType,
4055 RO_nsr_id=None,
4056 RO_scaling_info=None,
4057 ):
kuuseac3a8882019-10-03 10:48:06 +02004058 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00004059 if RO_nsr_id and RO_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004060 operationType = "SCALE-RO"
kuuseac3a8882019-10-03 10:48:06 +02004061 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004062 "member_vnf_index": vnf_index,
4063 "RO_nsr_id": RO_nsr_id,
4064 "RO_scaling_info": RO_scaling_info,
kuuseac3a8882019-10-03 10:48:06 +02004065 }
4066 else:
4067 match = {
garciadeblas5697b8b2021-03-24 09:17:02 +01004068 "member_vnf_index": vnf_index,
4069 "primitive": vnf_config_primitive,
4070 "primitive_params": primitive_params,
4071 "lcmOperationType": operationType,
kuuseac3a8882019-10-03 10:48:06 +02004072 }
4073 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00004074 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02004075 # a. New sub-operation
4076 # The sub-operation does not exist, add it.
4077 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
4078 # The following parameters are set to None for all kind of scaling:
4079 vdu_id = None
4080 vdu_count_index = None
4081 vdu_name = None
tierno51183952020-04-03 15:48:18 +00004082 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02004083 vnf_config_primitive = None
4084 primitive_params = None
4085 else:
4086 RO_nsr_id = None
4087 RO_scaling_info = None
4088 # Initial status for sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004089 operationState = "PROCESSING"
4090 detailed_status = "In progress"
kuuseac3a8882019-10-03 10:48:06 +02004091 # Add sub-operation for pre/post-scaling (zero or more operations)
garciadeblas5697b8b2021-03-24 09:17:02 +01004092 self._add_suboperation(
4093 db_nslcmop,
4094 vnf_index,
4095 vdu_id,
4096 vdu_count_index,
4097 vdu_name,
4098 vnf_config_primitive,
4099 primitive_params,
4100 operationState,
4101 detailed_status,
4102 operationType,
4103 RO_nsr_id,
4104 RO_scaling_info,
4105 )
kuuseac3a8882019-10-03 10:48:06 +02004106 return self.SUBOPERATION_STATUS_NEW
4107 else:
4108 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
4109 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00004110 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02004111
preethika.pdf7d8e02019-12-10 13:10:48 +00004112 # Function to return execution_environment id
4113
4114 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00004115 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00004116 for vca in vca_deployed_list:
4117 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
4118 return vca["ee_id"]
4119
David Garciac1fe90a2021-03-31 19:12:02 +02004120 async def destroy_N2VC(
4121 self,
4122 logging_text,
4123 db_nslcmop,
4124 vca_deployed,
4125 config_descriptor,
4126 vca_index,
4127 destroy_ee=True,
4128 exec_primitives=True,
4129 scaling_in=False,
4130 vca_id: str = None,
4131 ):
tiernoe876f672020-02-13 14:34:48 +00004132 """
4133 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
4134 :param logging_text:
4135 :param db_nslcmop:
4136 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
4137 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
4138 :param vca_index: index in the database _admin.deployed.VCA
4139 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00004140 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
4141 not executed properly
aktas13251562021-02-12 22:19:10 +03004142 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00004143 :return: None or exception
4144 """
tiernoe876f672020-02-13 14:34:48 +00004145
tierno588547c2020-07-01 15:30:20 +00004146 self.logger.debug(
garciadeblas5697b8b2021-03-24 09:17:02 +01004147 logging_text
4148 + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
tierno588547c2020-07-01 15:30:20 +00004149 vca_index, vca_deployed, config_descriptor, destroy_ee
4150 )
4151 )
4152
4153 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
4154
4155 # execute terminate_primitives
4156 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03004157 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01004158 config_descriptor.get("terminate-config-primitive"),
4159 vca_deployed.get("ee_descriptor_id"),
4160 )
tierno588547c2020-07-01 15:30:20 +00004161 vdu_id = vca_deployed.get("vdu_id")
4162 vdu_count_index = vca_deployed.get("vdu_count_index")
4163 vdu_name = vca_deployed.get("vdu_name")
4164 vnf_index = vca_deployed.get("member-vnf-index")
4165 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00004166 for seq in terminate_primitives:
4167 # For each sequence in list, get primitive and call _ns_execute_primitive()
4168 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01004169 vnf_index, seq.get("name")
4170 )
tierno588547c2020-07-01 15:30:20 +00004171 self.logger.debug(logging_text + step)
4172 # Create the primitive for each sequence, i.e. "primitive": "touch"
garciadeblas5697b8b2021-03-24 09:17:02 +01004173 primitive = seq.get("name")
4174 mapped_primitive_params = self._get_terminate_primitive_params(
4175 seq, vnf_index
4176 )
tierno588547c2020-07-01 15:30:20 +00004177
4178 # Add sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01004179 self._add_suboperation(
4180 db_nslcmop,
4181 vnf_index,
4182 vdu_id,
4183 vdu_count_index,
4184 vdu_name,
4185 primitive,
4186 mapped_primitive_params,
4187 )
tierno588547c2020-07-01 15:30:20 +00004188 # Sub-operations: Call _ns_execute_primitive() instead of action()
4189 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004190 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01004191 vca_deployed["ee_id"],
4192 primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004193 mapped_primitive_params,
4194 vca_type=vca_type,
4195 vca_id=vca_id,
4196 )
tierno588547c2020-07-01 15:30:20 +00004197 except LcmException:
4198 # this happens when VCA is not deployed. In this case it is not needed to terminate
4199 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004200 result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
tierno588547c2020-07-01 15:30:20 +00004201 if result not in result_ok:
garciadeblas5697b8b2021-03-24 09:17:02 +01004202 raise LcmException(
4203 "terminate_primitive {} for vnf_member_index={} fails with "
4204 "error {}".format(seq.get("name"), vnf_index, result_detail)
4205 )
tierno588547c2020-07-01 15:30:20 +00004206 # set that this VCA do not need terminated
garciadeblas5697b8b2021-03-24 09:17:02 +01004207 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
4208 vca_index
4209 )
4210 self.update_db_2(
4211 "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
4212 )
tiernoe876f672020-02-13 14:34:48 +00004213
bravof73bac502021-05-11 07:38:47 -04004214 # Delete Prometheus Jobs if any
4215 # This uses NSR_ID, so it will destroy any jobs under this index
4216 self.db.del_list("prometheus_jobs", {"nsr_id": db_nslcmop["nsInstanceId"]})
tiernob996d942020-07-03 14:52:28 +00004217
tiernoe876f672020-02-13 14:34:48 +00004218 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02004219 await self.vca_map[vca_type].delete_execution_environment(
4220 vca_deployed["ee_id"],
4221 scaling_in=scaling_in,
aktas98488ed2021-07-29 17:42:49 +03004222 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004223 vca_id=vca_id,
4224 )
kuuse0ca67472019-05-13 15:59:27 +02004225
David Garciac1fe90a2021-03-31 19:12:02 +02004226 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
garciadeblas5697b8b2021-03-24 09:17:02 +01004227 self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
tierno51183952020-04-03 15:48:18 +00004228 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00004229 try:
David Garciac1fe90a2021-03-31 19:12:02 +02004230 await self.n2vc.delete_namespace(
4231 namespace=namespace,
4232 total_timeout=self.timeout_charm_delete,
4233 vca_id=vca_id,
4234 )
tiernof59ad6c2020-04-08 12:50:52 +00004235 except N2VCNotFound: # already deleted. Skip
4236 pass
garciadeblas5697b8b2021-03-24 09:17:02 +01004237 self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
quilesj3655ae02019-12-12 16:08:35 +00004238
garciadeblas5697b8b2021-03-24 09:17:02 +01004239 async def _terminate_RO(
4240 self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4241 ):
tiernoe876f672020-02-13 14:34:48 +00004242 """
4243 Terminates a deployment from RO
4244 :param logging_text:
4245 :param nsr_deployed: db_nsr._admin.deployed
4246 :param nsr_id:
4247 :param nslcmop_id:
4248 :param stage: list of string with the content to write on db_nslcmop.detailed-status.
4249 this method will update only the index 2, but it will write on database the concatenated content of the list
4250 :return:
4251 """
4252 db_nsr_update = {}
4253 failed_detail = []
4254 ro_nsr_id = ro_delete_action = None
4255 if nsr_deployed and nsr_deployed.get("RO"):
4256 ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
4257 ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
4258 try:
4259 if ro_nsr_id:
4260 stage[2] = "Deleting ns from VIM."
4261 db_nsr_update["detailed-status"] = " ".join(stage)
4262 self._write_op_status(nslcmop_id, stage)
4263 self.logger.debug(logging_text + stage[2])
4264 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4265 self._write_op_status(nslcmop_id, stage)
4266 desc = await self.RO.delete("ns", ro_nsr_id)
4267 ro_delete_action = desc["action_id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004268 db_nsr_update[
4269 "_admin.deployed.RO.nsr_delete_action_id"
4270 ] = ro_delete_action
tiernoe876f672020-02-13 14:34:48 +00004271 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
4272 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4273 if ro_delete_action:
4274 # wait until NS is deleted from VIM
4275 stage[2] = "Waiting ns deleted from VIM."
4276 detailed_status_old = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004277 self.logger.debug(
4278 logging_text
4279 + stage[2]
4280 + " RO_id={} ro_delete_action={}".format(
4281 ro_nsr_id, ro_delete_action
4282 )
4283 )
tiernoe876f672020-02-13 14:34:48 +00004284 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4285 self._write_op_status(nslcmop_id, stage)
kuused124bfe2019-06-18 12:09:24 +02004286
tiernoe876f672020-02-13 14:34:48 +00004287 delete_timeout = 20 * 60 # 20 minutes
4288 while delete_timeout > 0:
4289 desc = await self.RO.show(
4290 "ns",
4291 item_id_name=ro_nsr_id,
4292 extra_item="action",
garciadeblas5697b8b2021-03-24 09:17:02 +01004293 extra_item_id=ro_delete_action,
4294 )
tiernoe876f672020-02-13 14:34:48 +00004295
4296 # deploymentStatus
4297 self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
4298
4299 ns_status, ns_status_info = self.RO.check_action_status(desc)
4300 if ns_status == "ERROR":
4301 raise ROclient.ROClientException(ns_status_info)
4302 elif ns_status == "BUILD":
4303 stage[2] = "Deleting from VIM {}".format(ns_status_info)
4304 elif ns_status == "ACTIVE":
4305 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
4306 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4307 break
4308 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004309 assert (
4310 False
4311 ), "ROclient.check_action_status returns unknown {}".format(
4312 ns_status
4313 )
tiernoe876f672020-02-13 14:34:48 +00004314 if stage[2] != detailed_status_old:
4315 detailed_status_old = stage[2]
4316 db_nsr_update["detailed-status"] = " ".join(stage)
4317 self._write_op_status(nslcmop_id, stage)
4318 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4319 await asyncio.sleep(5, loop=self.loop)
4320 delete_timeout -= 5
4321 else: # delete_timeout <= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01004322 raise ROclient.ROClientException(
4323 "Timeout waiting ns deleted from VIM"
4324 )
tiernoe876f672020-02-13 14:34:48 +00004325
4326 except Exception as e:
4327 self.update_db_2("nsrs", nsr_id, db_nsr_update)
garciadeblas5697b8b2021-03-24 09:17:02 +01004328 if (
4329 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4330 ): # not found
tiernoe876f672020-02-13 14:34:48 +00004331 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
4332 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
4333 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004334 self.logger.debug(
4335 logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id)
4336 )
4337 elif (
4338 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4339 ): # conflict
tiernoa2143262020-03-27 16:20:40 +00004340 failed_detail.append("delete conflict: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01004341 self.logger.debug(
4342 logging_text
4343 + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e)
4344 )
tiernoe876f672020-02-13 14:34:48 +00004345 else:
tiernoa2143262020-03-27 16:20:40 +00004346 failed_detail.append("delete error: {}".format(e))
garciadeblas5697b8b2021-03-24 09:17:02 +01004347 self.logger.error(
4348 logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e)
4349 )
tiernoe876f672020-02-13 14:34:48 +00004350
4351 # Delete nsd
4352 if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
4353 ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
4354 try:
4355 stage[2] = "Deleting nsd from RO."
4356 db_nsr_update["detailed-status"] = " ".join(stage)
4357 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4358 self._write_op_status(nslcmop_id, stage)
4359 await self.RO.delete("nsd", ro_nsd_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01004360 self.logger.debug(
4361 logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id)
4362 )
tiernoe876f672020-02-13 14:34:48 +00004363 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
4364 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004365 if (
4366 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4367 ): # not found
tiernoe876f672020-02-13 14:34:48 +00004368 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004369 self.logger.debug(
4370 logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id)
4371 )
4372 elif (
4373 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4374 ): # conflict
4375 failed_detail.append(
4376 "ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e)
4377 )
tiernoe876f672020-02-13 14:34:48 +00004378 self.logger.debug(logging_text + failed_detail[-1])
4379 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004380 failed_detail.append(
4381 "ro_nsd_id={} delete error: {}".format(ro_nsd_id, e)
4382 )
tiernoe876f672020-02-13 14:34:48 +00004383 self.logger.error(logging_text + failed_detail[-1])
4384
4385 if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
4386 for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
4387 if not vnf_deployed or not vnf_deployed["id"]:
4388 continue
4389 try:
4390 ro_vnfd_id = vnf_deployed["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004391 stage[
4392 2
4393 ] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
4394 vnf_deployed["member-vnf-index"], ro_vnfd_id
4395 )
tiernoe876f672020-02-13 14:34:48 +00004396 db_nsr_update["detailed-status"] = " ".join(stage)
4397 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4398 self._write_op_status(nslcmop_id, stage)
4399 await self.RO.delete("vnfd", ro_vnfd_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01004400 self.logger.debug(
4401 logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id)
4402 )
tiernoe876f672020-02-13 14:34:48 +00004403 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
4404 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004405 if (
4406 isinstance(e, ROclient.ROClientException) and e.http_code == 404
4407 ): # not found
4408 db_nsr_update[
4409 "_admin.deployed.RO.vnfd.{}.id".format(index)
4410 ] = None
4411 self.logger.debug(
4412 logging_text
4413 + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id)
4414 )
4415 elif (
4416 isinstance(e, ROclient.ROClientException) and e.http_code == 409
4417 ): # conflict
4418 failed_detail.append(
4419 "ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e)
4420 )
tiernoe876f672020-02-13 14:34:48 +00004421 self.logger.debug(logging_text + failed_detail[-1])
4422 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004423 failed_detail.append(
4424 "ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e)
4425 )
tiernoe876f672020-02-13 14:34:48 +00004426 self.logger.error(logging_text + failed_detail[-1])
4427
tiernoa2143262020-03-27 16:20:40 +00004428 if failed_detail:
4429 stage[2] = "Error deleting from VIM"
4430 else:
4431 stage[2] = "Deleted from VIM"
tiernoe876f672020-02-13 14:34:48 +00004432 db_nsr_update["detailed-status"] = " ".join(stage)
4433 self.update_db_2("nsrs", nsr_id, db_nsr_update)
4434 self._write_op_status(nslcmop_id, stage)
4435
4436 if failed_detail:
tiernoa2143262020-03-27 16:20:40 +00004437 raise LcmException("; ".join(failed_detail))
tiernoe876f672020-02-13 14:34:48 +00004438
4439 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02004440 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01004441 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004442 if not task_is_locked_by_me:
4443 return
4444
tierno59d22d22018-09-25 18:10:19 +02004445 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
4446 self.logger.debug(logging_text + "Enter")
tiernoe876f672020-02-13 14:34:48 +00004447 timeout_ns_terminate = self.timeout_ns_terminate
tierno59d22d22018-09-25 18:10:19 +02004448 db_nsr = None
4449 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00004450 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02004451 exc = None
garciadeblas5697b8b2021-03-24 09:17:02 +01004452 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02004453 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00004454 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00004455 tasks_dict_info = {}
4456 db_nsr_update = {}
garciadeblas5697b8b2021-03-24 09:17:02 +01004457 stage = [
4458 "Stage 1/3: Preparing task.",
4459 "Waiting for previous operations to terminate.",
4460 "",
4461 ]
tiernoe876f672020-02-13 14:34:48 +00004462 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02004463 try:
kuused124bfe2019-06-18 12:09:24 +02004464 # wait for any previous tasks in process
garciadeblas5697b8b2021-03-24 09:17:02 +01004465 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02004466
tiernoe876f672020-02-13 14:34:48 +00004467 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
4468 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
4469 operation_params = db_nslcmop.get("operationParams") or {}
4470 if operation_params.get("timeout_ns_terminate"):
4471 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
4472 stage[1] = "Getting nsr={} from db.".format(nsr_id)
4473 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
4474
4475 db_nsr_update["operational-status"] = "terminating"
4476 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00004477 self._write_ns_status(
4478 nsr_id=nsr_id,
4479 ns_state="TERMINATING",
4480 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00004481 current_operation_id=nslcmop_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01004482 other_update=db_nsr_update,
quilesj4cda56b2019-12-05 10:02:20 +00004483 )
garciadeblas5697b8b2021-03-24 09:17:02 +01004484 self._write_op_status(op_id=nslcmop_id, queuePosition=0, stage=stage)
tiernoe876f672020-02-13 14:34:48 +00004485 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02004486 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
4487 return
tierno59d22d22018-09-25 18:10:19 +02004488
tiernoe876f672020-02-13 14:34:48 +00004489 stage[1] = "Getting vnf descriptors from db."
4490 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
garciadeblas5697b8b2021-03-24 09:17:02 +01004491 db_vnfrs_dict = {
4492 db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list
4493 }
tiernoe876f672020-02-13 14:34:48 +00004494 db_vnfds_from_id = {}
4495 db_vnfds_from_member_index = {}
4496 # Loop over VNFRs
4497 for vnfr in db_vnfrs_list:
4498 vnfd_id = vnfr["vnfd-id"]
4499 if vnfd_id not in db_vnfds_from_id:
4500 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
4501 db_vnfds_from_id[vnfd_id] = vnfd
garciadeblas5697b8b2021-03-24 09:17:02 +01004502 db_vnfds_from_member_index[
4503 vnfr["member-vnf-index-ref"]
4504 ] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01004505
tiernoe876f672020-02-13 14:34:48 +00004506 # Destroy individual execution environments when there are terminating primitives.
4507 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00004508 # TODO - check before calling _destroy_N2VC
4509 # if not operation_params.get("skip_terminate_primitives"):#
4510 # or not vca.get("needed_terminate"):
4511 stage[0] = "Stage 2/3 execute terminating primitives."
4512 self.logger.debug(logging_text + stage[0])
4513 stage[1] = "Looking execution environment that needs terminate."
4514 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03004515
tierno588547c2020-07-01 15:30:20 +00004516 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00004517 config_descriptor = None
David Garcia9ad54a42021-05-28 12:08:18 +02004518 vca_member_vnf_index = vca.get("member-vnf-index")
4519 vca_id = self.get_vca_id(
4520 db_vnfrs_dict.get(vca_member_vnf_index)
4521 if vca_member_vnf_index
4522 else None,
4523 db_nsr,
4524 )
tierno588547c2020-07-01 15:30:20 +00004525 if not vca or not vca.get("ee_id"):
4526 continue
4527 if not vca.get("member-vnf-index"):
4528 # ns
4529 config_descriptor = db_nsr.get("ns-configuration")
4530 elif vca.get("vdu_id"):
4531 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004532 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00004533 elif vca.get("kdu_name"):
4534 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03004535 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00004536 else:
bravofe5a31bc2021-02-17 19:09:12 -03004537 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03004538 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00004539 vca_type = vca.get("type")
garciadeblas5697b8b2021-03-24 09:17:02 +01004540 exec_terminate_primitives = not operation_params.get(
4541 "skip_terminate_primitives"
4542 ) and vca.get("needed_terminate")
tiernoaebd7da2020-08-07 06:36:38 +00004543 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
4544 # pending native charms
garciadeblas5697b8b2021-03-24 09:17:02 +01004545 destroy_ee = (
4546 True if vca_type in ("helm", "helm-v3", "native_charm") else False
4547 )
tierno86e33612020-09-16 14:13:06 +00004548 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
4549 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00004550 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02004551 self.destroy_N2VC(
4552 logging_text,
4553 db_nslcmop,
4554 vca,
4555 config_descriptor,
4556 vca_index,
4557 destroy_ee,
4558 exec_terminate_primitives,
4559 vca_id=vca_id,
4560 )
4561 )
tierno588547c2020-07-01 15:30:20 +00004562 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02004563
tierno588547c2020-07-01 15:30:20 +00004564 # wait for pending tasks of terminate primitives
4565 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01004566 self.logger.debug(
4567 logging_text
4568 + "Waiting for tasks {}".format(list(tasks_dict_info.keys()))
4569 )
4570 error_list = await self._wait_for_tasks(
4571 logging_text,
4572 tasks_dict_info,
4573 min(self.timeout_charm_delete, timeout_ns_terminate),
4574 stage,
4575 nslcmop_id,
4576 )
tierno86e33612020-09-16 14:13:06 +00004577 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00004578 if error_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01004579 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00004580
tiernoe876f672020-02-13 14:34:48 +00004581 # remove All execution environments at once
4582 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00004583
tierno49676be2020-04-07 16:34:35 +00004584 if nsr_deployed.get("VCA"):
4585 stage[1] = "Deleting all execution environments."
4586 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02004587 vca_id = self.get_vca_id({}, db_nsr)
4588 task_delete_ee = asyncio.ensure_future(
4589 asyncio.wait_for(
4590 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
garciadeblas5697b8b2021-03-24 09:17:02 +01004591 timeout=self.timeout_charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02004592 )
4593 )
tierno49676be2020-04-07 16:34:35 +00004594 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
4595 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02004596
tiernoe876f672020-02-13 14:34:48 +00004597 # Delete from k8scluster
4598 stage[1] = "Deleting KDUs."
4599 self.logger.debug(logging_text + stage[1])
4600 # print(nsr_deployed)
4601 for kdu in get_iterable(nsr_deployed, "K8s"):
4602 if not kdu or not kdu.get("kdu-instance"):
4603 continue
4604 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00004605 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02004606 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
4607 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00004608 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00004609 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
4610 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02004611 kdu_instance=kdu_instance,
4612 vca_id=vca_id,
Pedro Escaleirae1ea2672022-04-22 00:46:14 +01004613 namespace=kdu.get("namespace"),
David Garciac1fe90a2021-03-31 19:12:02 +02004614 )
4615 )
tiernoe876f672020-02-13 14:34:48 +00004616 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004617 self.logger.error(
4618 logging_text
4619 + "Unknown k8s deployment type {}".format(
4620 kdu.get("k8scluster-type")
4621 )
4622 )
tiernoe876f672020-02-13 14:34:48 +00004623 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004624 tasks_dict_info[
4625 task_delete_kdu_instance
4626 ] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02004627
4628 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00004629 stage[1] = "Deleting ns from VIM."
tierno69f0d382020-05-07 13:08:09 +00004630 if self.ng_ro:
4631 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004632 self._terminate_ng_ro(
4633 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4634 )
4635 )
tierno69f0d382020-05-07 13:08:09 +00004636 else:
4637 task_delete_ro = asyncio.ensure_future(
garciadeblas5697b8b2021-03-24 09:17:02 +01004638 self._terminate_RO(
4639 logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
4640 )
4641 )
tiernoe876f672020-02-13 14:34:48 +00004642 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02004643
tiernoe876f672020-02-13 14:34:48 +00004644 # rest of staff will be done at finally
4645
garciadeblas5697b8b2021-03-24 09:17:02 +01004646 except (
4647 ROclient.ROClientException,
4648 DbException,
4649 LcmException,
4650 N2VCException,
4651 ) as e:
tiernoe876f672020-02-13 14:34:48 +00004652 self.logger.error(logging_text + "Exit Exception {}".format(e))
4653 exc = e
4654 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01004655 self.logger.error(
4656 logging_text + "Cancelled Exception while '{}'".format(stage[1])
4657 )
tiernoe876f672020-02-13 14:34:48 +00004658 exc = "Operation was cancelled"
4659 except Exception as e:
4660 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01004661 self.logger.critical(
4662 logging_text + "Exit Exception while '{}': {}".format(stage[1], e),
4663 exc_info=True,
4664 )
tiernoe876f672020-02-13 14:34:48 +00004665 finally:
4666 if exc:
4667 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02004668 try:
tiernoe876f672020-02-13 14:34:48 +00004669 # wait for pending tasks
4670 if tasks_dict_info:
4671 stage[1] = "Waiting for terminate pending tasks."
4672 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01004673 error_list += await self._wait_for_tasks(
4674 logging_text,
4675 tasks_dict_info,
4676 timeout_ns_terminate,
4677 stage,
4678 nslcmop_id,
4679 )
tiernoe876f672020-02-13 14:34:48 +00004680 stage[1] = stage[2] = ""
4681 except asyncio.CancelledError:
4682 error_list.append("Cancelled")
4683 # TODO cancell all tasks
4684 except Exception as exc:
4685 error_list.append(str(exc))
4686 # update status at database
4687 if error_list:
4688 error_detail = "; ".join(error_list)
4689 # self.logger.error(logging_text + error_detail)
garciadeblas5697b8b2021-03-24 09:17:02 +01004690 error_description_nslcmop = "{} Detail: {}".format(
4691 stage[0], error_detail
4692 )
4693 error_description_nsr = "Operation: TERMINATING.{}, {}.".format(
4694 nslcmop_id, stage[0]
4695 )
tierno59d22d22018-09-25 18:10:19 +02004696
tierno59d22d22018-09-25 18:10:19 +02004697 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01004698 db_nsr_update["detailed-status"] = (
4699 error_description_nsr + " Detail: " + error_detail
4700 )
tiernoe876f672020-02-13 14:34:48 +00004701 db_nslcmop_update["detailed-status"] = error_detail
4702 nslcmop_operation_state = "FAILED"
4703 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02004704 else:
tiernoa2143262020-03-27 16:20:40 +00004705 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00004706 error_description_nsr = error_description_nslcmop = None
4707 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02004708 db_nsr_update["operational-status"] = "terminated"
4709 db_nsr_update["detailed-status"] = "Done"
4710 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
4711 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00004712 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02004713
tiernoe876f672020-02-13 14:34:48 +00004714 if db_nsr:
4715 self._write_ns_status(
4716 nsr_id=nsr_id,
4717 ns_state=ns_state,
4718 current_operation="IDLE",
4719 current_operation_id=None,
4720 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00004721 error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01004722 other_update=db_nsr_update,
tiernoe876f672020-02-13 14:34:48 +00004723 )
tiernoa17d4f42020-04-28 09:59:23 +00004724 self._write_op_status(
4725 op_id=nslcmop_id,
4726 stage="",
4727 error_message=error_description_nslcmop,
4728 operation_state=nslcmop_operation_state,
4729 other_update=db_nslcmop_update,
4730 )
lloretgalleg6d488782020-07-22 10:13:46 +00004731 if ns_state == "NOT_INSTANTIATED":
4732 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004733 self.db.set_list(
4734 "vnfrs",
4735 {"nsr-id-ref": nsr_id},
4736 {"_admin.nsState": "NOT_INSTANTIATED"},
4737 )
lloretgalleg6d488782020-07-22 10:13:46 +00004738 except DbException as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004739 self.logger.warn(
4740 logging_text
4741 + "Error writing VNFR status for nsr-id-ref: {} -> {}".format(
4742 nsr_id, e
4743 )
4744 )
tiernoa17d4f42020-04-28 09:59:23 +00004745 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00004746 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02004747 if nslcmop_operation_state:
4748 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01004749 await self.msg.aiowrite(
4750 "ns",
4751 "terminated",
4752 {
4753 "nsr_id": nsr_id,
4754 "nslcmop_id": nslcmop_id,
4755 "operationState": nslcmop_operation_state,
4756 "autoremove": autoremove,
4757 },
4758 loop=self.loop,
4759 )
tierno59d22d22018-09-25 18:10:19 +02004760 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01004761 self.logger.error(
4762 logging_text + "kafka_write notification Exception {}".format(e)
4763 )
quilesj7e13aeb2019-10-08 13:34:55 +02004764
tierno59d22d22018-09-25 18:10:19 +02004765 self.logger.debug(logging_text + "Exit")
4766 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
4767
garciadeblas5697b8b2021-03-24 09:17:02 +01004768 async def _wait_for_tasks(
4769 self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None
4770 ):
tiernoe876f672020-02-13 14:34:48 +00004771 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00004772 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00004773 error_list = []
4774 pending_tasks = list(created_tasks_info.keys())
4775 num_tasks = len(pending_tasks)
4776 num_done = 0
4777 stage[1] = "{}/{}.".format(num_done, num_tasks)
4778 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00004779 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004780 new_error = None
tiernoe876f672020-02-13 14:34:48 +00004781 _timeout = timeout + time_start - time()
garciadeblas5697b8b2021-03-24 09:17:02 +01004782 done, pending_tasks = await asyncio.wait(
4783 pending_tasks, timeout=_timeout, return_when=asyncio.FIRST_COMPLETED
4784 )
tiernoe876f672020-02-13 14:34:48 +00004785 num_done += len(done)
garciadeblas5697b8b2021-03-24 09:17:02 +01004786 if not done: # Timeout
tiernoe876f672020-02-13 14:34:48 +00004787 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00004788 new_error = created_tasks_info[task] + ": Timeout"
4789 error_detail_list.append(new_error)
4790 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00004791 break
4792 for task in done:
4793 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00004794 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00004795 else:
4796 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00004797 if exc:
4798 if isinstance(exc, asyncio.TimeoutError):
4799 exc = "Timeout"
4800 new_error = created_tasks_info[task] + ": {}".format(exc)
4801 error_list.append(created_tasks_info[task])
4802 error_detail_list.append(new_error)
garciadeblas5697b8b2021-03-24 09:17:02 +01004803 if isinstance(
4804 exc,
4805 (
4806 str,
4807 DbException,
4808 N2VCException,
4809 ROclient.ROClientException,
4810 LcmException,
4811 K8sException,
4812 NgRoException,
4813 ),
4814 ):
tierno067e04a2020-03-31 12:53:13 +00004815 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00004816 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004817 exc_traceback = "".join(
4818 traceback.format_exception(None, exc, exc.__traceback__)
4819 )
4820 self.logger.error(
4821 logging_text
4822 + created_tasks_info[task]
4823 + " "
4824 + exc_traceback
4825 )
tierno067e04a2020-03-31 12:53:13 +00004826 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004827 self.logger.debug(
4828 logging_text + created_tasks_info[task] + ": Done"
4829 )
tiernoe876f672020-02-13 14:34:48 +00004830 stage[1] = "{}/{}.".format(num_done, num_tasks)
4831 if new_error:
tiernoa2143262020-03-27 16:20:40 +00004832 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00004833 if nsr_id: # update also nsr
garciadeblas5697b8b2021-03-24 09:17:02 +01004834 self.update_db_2(
4835 "nsrs",
4836 nsr_id,
4837 {
4838 "errorDescription": "Error at: " + ", ".join(error_list),
4839 "errorDetail": ". ".join(error_detail_list),
4840 },
4841 )
tiernoe876f672020-02-13 14:34:48 +00004842 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00004843 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00004844
tiernoda1ff8c2020-10-22 14:12:46 +00004845 @staticmethod
4846 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00004847 """
4848 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
4849 The default-value is used. If it is between < > it look for a value at instantiation_params
4850 :param primitive_desc: portion of VNFD/NSD that describes primitive
4851 :param params: Params provided by user
4852 :param instantiation_params: Instantiation params provided by user
4853 :return: a dictionary with the calculated params
4854 """
4855 calculated_params = {}
4856 for parameter in primitive_desc.get("parameter", ()):
4857 param_name = parameter["name"]
4858 if param_name in params:
4859 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00004860 elif "default-value" in parameter or "value" in parameter:
4861 if "value" in parameter:
4862 calculated_params[param_name] = parameter["value"]
4863 else:
4864 calculated_params[param_name] = parameter["default-value"]
garciadeblas5697b8b2021-03-24 09:17:02 +01004865 if (
4866 isinstance(calculated_params[param_name], str)
4867 and calculated_params[param_name].startswith("<")
4868 and calculated_params[param_name].endswith(">")
4869 ):
tierno98ad6ea2019-05-30 17:16:28 +00004870 if calculated_params[param_name][1:-1] in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004871 calculated_params[param_name] = instantiation_params[
4872 calculated_params[param_name][1:-1]
4873 ]
tiernoda964822019-01-14 15:53:47 +00004874 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004875 raise LcmException(
4876 "Parameter {} needed to execute primitive {} not provided".format(
4877 calculated_params[param_name], primitive_desc["name"]
4878 )
4879 )
tiernoda964822019-01-14 15:53:47 +00004880 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01004881 raise LcmException(
4882 "Parameter {} needed to execute primitive {} not provided".format(
4883 param_name, primitive_desc["name"]
4884 )
4885 )
tierno59d22d22018-09-25 18:10:19 +02004886
tiernoda964822019-01-14 15:53:47 +00004887 if isinstance(calculated_params[param_name], (dict, list, tuple)):
garciadeblas5697b8b2021-03-24 09:17:02 +01004888 calculated_params[param_name] = yaml.safe_dump(
4889 calculated_params[param_name], default_flow_style=True, width=256
4890 )
4891 elif isinstance(calculated_params[param_name], str) and calculated_params[
4892 param_name
4893 ].startswith("!!yaml "):
tiernoda964822019-01-14 15:53:47 +00004894 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00004895 if parameter.get("data-type") == "INTEGER":
4896 try:
4897 calculated_params[param_name] = int(calculated_params[param_name])
4898 except ValueError: # error converting string to int
4899 raise LcmException(
garciadeblas5697b8b2021-03-24 09:17:02 +01004900 "Parameter {} of primitive {} must be integer".format(
4901 param_name, primitive_desc["name"]
4902 )
4903 )
tiernofa40e692020-10-14 14:59:36 +00004904 elif parameter.get("data-type") == "BOOLEAN":
garciadeblas5697b8b2021-03-24 09:17:02 +01004905 calculated_params[param_name] = not (
4906 (str(calculated_params[param_name])).lower() == "false"
4907 )
tiernoc3f2a822019-11-05 13:45:04 +00004908
4909 # add always ns_config_info if primitive name is config
4910 if primitive_desc["name"] == "config":
4911 if "ns_config_info" in instantiation_params:
garciadeblas5697b8b2021-03-24 09:17:02 +01004912 calculated_params["ns_config_info"] = instantiation_params[
4913 "ns_config_info"
4914 ]
tiernoda964822019-01-14 15:53:47 +00004915 return calculated_params
4916
garciadeblas5697b8b2021-03-24 09:17:02 +01004917 def _look_for_deployed_vca(
4918 self,
4919 deployed_vca,
4920 member_vnf_index,
4921 vdu_id,
4922 vdu_count_index,
4923 kdu_name=None,
4924 ee_descriptor_id=None,
4925 ):
tiernoe876f672020-02-13 14:34:48 +00004926 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
4927 for vca in deployed_vca:
4928 if not vca:
4929 continue
4930 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
4931 continue
garciadeblas5697b8b2021-03-24 09:17:02 +01004932 if (
4933 vdu_count_index is not None
4934 and vdu_count_index != vca["vdu_count_index"]
4935 ):
tiernoe876f672020-02-13 14:34:48 +00004936 continue
4937 if kdu_name and kdu_name != vca["kdu_name"]:
4938 continue
tiernoa278b842020-07-08 15:33:55 +00004939 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
4940 continue
tiernoe876f672020-02-13 14:34:48 +00004941 break
4942 else:
4943 # vca_deployed not found
garciadeblas5697b8b2021-03-24 09:17:02 +01004944 raise LcmException(
4945 "charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
4946 " is not deployed".format(
4947 member_vnf_index,
4948 vdu_id,
4949 vdu_count_index,
4950 kdu_name,
4951 ee_descriptor_id,
4952 )
4953 )
tiernoe876f672020-02-13 14:34:48 +00004954 # get ee_id
4955 ee_id = vca.get("ee_id")
garciadeblas5697b8b2021-03-24 09:17:02 +01004956 vca_type = vca.get(
4957 "type", "lxc_proxy_charm"
4958 ) # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00004959 if not ee_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01004960 raise LcmException(
4961 "charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
4962 "execution environment".format(
4963 member_vnf_index, vdu_id, kdu_name, vdu_count_index
4964 )
4965 )
tierno588547c2020-07-01 15:30:20 +00004966 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00004967
David Garciac1fe90a2021-03-31 19:12:02 +02004968 async def _ns_execute_primitive(
4969 self,
4970 ee_id,
4971 primitive,
4972 primitive_params,
4973 retries=0,
4974 retries_interval=30,
4975 timeout=None,
4976 vca_type=None,
4977 db_dict=None,
4978 vca_id: str = None,
4979 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00004980 try:
tierno98ad6ea2019-05-30 17:16:28 +00004981 if primitive == "config":
4982 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00004983
tierno588547c2020-07-01 15:30:20 +00004984 vca_type = vca_type or "lxc_proxy_charm"
4985
quilesj7e13aeb2019-10-08 13:34:55 +02004986 while retries >= 0:
4987 try:
tierno067e04a2020-03-31 12:53:13 +00004988 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00004989 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00004990 ee_id=ee_id,
4991 primitive_name=primitive,
4992 params_dict=primitive_params,
4993 progress_timeout=self.timeout_progress_primitive,
tierno588547c2020-07-01 15:30:20 +00004994 total_timeout=self.timeout_primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02004995 db_dict=db_dict,
4996 vca_id=vca_id,
aktas98488ed2021-07-29 17:42:49 +03004997 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02004998 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01004999 timeout=timeout or self.timeout_primitive,
5000 )
quilesj7e13aeb2019-10-08 13:34:55 +02005001 # execution was OK
5002 break
tierno067e04a2020-03-31 12:53:13 +00005003 except asyncio.CancelledError:
5004 raise
Mark Beierl0240ddd2022-08-19 15:01:06 -04005005 except Exception as e:
quilesj7e13aeb2019-10-08 13:34:55 +02005006 retries -= 1
5007 if retries >= 0:
garciadeblas5697b8b2021-03-24 09:17:02 +01005008 self.logger.debug(
5009 "Error executing action {} on {} -> {}".format(
5010 primitive, ee_id, e
5011 )
5012 )
quilesj7e13aeb2019-10-08 13:34:55 +02005013 # wait and retry
5014 await asyncio.sleep(retries_interval, loop=self.loop)
tierno73d8bd02019-11-18 17:33:27 +00005015 else:
Mark Beierl0240ddd2022-08-19 15:01:06 -04005016 if isinstance(e, asyncio.TimeoutError):
preethika.p28b0bf82022-09-23 07:36:28 +00005017 e = N2VCException(
5018 message="Timed out waiting for action to complete"
5019 )
5020 return "FAILED", getattr(e, "message", repr(e))
quilesj7e13aeb2019-10-08 13:34:55 +02005021
garciadeblas5697b8b2021-03-24 09:17:02 +01005022 return "COMPLETED", output
quilesj7e13aeb2019-10-08 13:34:55 +02005023
tierno067e04a2020-03-31 12:53:13 +00005024 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00005025 raise
quilesj7e13aeb2019-10-08 13:34:55 +02005026 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005027 return "FAIL", "Error executing action {}: {}".format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02005028
ksaikiranr3fde2c72021-03-15 10:39:06 +05305029 async def vca_status_refresh(self, nsr_id, nslcmop_id):
5030 """
5031 Updating the vca_status with latest juju information in nsrs record
5032 :param: nsr_id: Id of the nsr
5033 :param: nslcmop_id: Id of the nslcmop
5034 :return: None
5035 """
5036
5037 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
5038 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02005039 vca_id = self.get_vca_id({}, db_nsr)
garciadeblas5697b8b2021-03-24 09:17:02 +01005040 if db_nsr["_admin"]["deployed"]["K8s"]:
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005041 for _, k8s in enumerate(db_nsr["_admin"]["deployed"]["K8s"]):
5042 cluster_uuid, kdu_instance, cluster_type = (
5043 k8s["k8scluster-uuid"],
5044 k8s["kdu-instance"],
5045 k8s["k8scluster-type"],
5046 )
garciadeblas5697b8b2021-03-24 09:17:02 +01005047 await self._on_update_k8s_db(
Pedro Escaleira75b620d2022-04-01 01:49:22 +01005048 cluster_uuid=cluster_uuid,
5049 kdu_instance=kdu_instance,
5050 filter={"_id": nsr_id},
5051 vca_id=vca_id,
5052 cluster_type=cluster_type,
garciadeblas5697b8b2021-03-24 09:17:02 +01005053 )
ksaikiranr656b6dd2021-02-19 10:25:18 +05305054 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005055 for vca_index, _ in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
ksaikiranr656b6dd2021-02-19 10:25:18 +05305056 table, filter = "nsrs", {"_id": nsr_id}
5057 path = "_admin.deployed.VCA.{}.".format(vca_index)
5058 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05305059
5060 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
5061 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
5062
tierno59d22d22018-09-25 18:10:19 +02005063 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02005064 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01005065 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005066 if not task_is_locked_by_me:
5067 return
5068
tierno59d22d22018-09-25 18:10:19 +02005069 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
5070 self.logger.debug(logging_text + "Enter")
5071 # get all needed from database
5072 db_nsr = None
5073 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00005074 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02005075 db_nslcmop_update = {}
5076 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00005077 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02005078 exc = None
5079 try:
kuused124bfe2019-06-18 12:09:24 +02005080 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00005081 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01005082 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02005083
quilesj4cda56b2019-12-05 10:02:20 +00005084 self._write_ns_status(
5085 nsr_id=nsr_id,
5086 ns_state=None,
5087 current_operation="RUNNING ACTION",
garciadeblas5697b8b2021-03-24 09:17:02 +01005088 current_operation_id=nslcmop_id,
quilesj4cda56b2019-12-05 10:02:20 +00005089 )
5090
tierno59d22d22018-09-25 18:10:19 +02005091 step = "Getting information from database"
5092 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5093 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
Guillermo Calvino57c68152022-01-26 17:40:31 +01005094 if db_nslcmop["operationParams"].get("primitive_params"):
5095 db_nslcmop["operationParams"]["primitive_params"] = json.loads(
5096 db_nslcmop["operationParams"]["primitive_params"]
5097 )
tiernoda964822019-01-14 15:53:47 +00005098
tiernoe4f7e6c2018-11-27 14:55:30 +00005099 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00005100 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02005101 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01005102 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00005103 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00005104 primitive = db_nslcmop["operationParams"]["primitive"]
5105 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
garciadeblas5697b8b2021-03-24 09:17:02 +01005106 timeout_ns_action = db_nslcmop["operationParams"].get(
5107 "timeout_ns_action", self.timeout_primitive
5108 )
tierno59d22d22018-09-25 18:10:19 +02005109
tierno1b633412019-02-25 16:48:23 +00005110 if vnf_index:
5111 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01005112 db_vnfr = self.db.get_one(
5113 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
5114 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005115 if db_vnfr.get("kdur"):
5116 kdur_list = []
5117 for kdur in db_vnfr["kdur"]:
5118 if kdur.get("additionalParams"):
Pedro Escaleirab9a7c4d2022-03-31 00:08:05 +01005119 kdur["additionalParams"] = json.loads(
5120 kdur["additionalParams"]
5121 )
Guillermo Calvino48aee4c2022-02-01 18:59:50 +01005122 kdur_list.append(kdur)
5123 db_vnfr["kdur"] = kdur_list
tierno1b633412019-02-25 16:48:23 +00005124 step = "Getting vnfd from database"
5125 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
bravofa96dd9c2021-10-13 17:37:36 -03005126
5127 # Sync filesystem before running a primitive
5128 self.fs.sync(db_vnfr["vnfd-id"])
tierno1b633412019-02-25 16:48:23 +00005129 else:
tierno067e04a2020-03-31 12:53:13 +00005130 step = "Getting nsd from database"
5131 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00005132
David Garciac1fe90a2021-03-31 19:12:02 +02005133 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00005134 # for backward compatibility
5135 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
5136 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
5137 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
5138 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5139
tiernoda964822019-01-14 15:53:47 +00005140 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00005141 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00005142 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03005143 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01005144 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03005145 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00005146 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03005147 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00005148 else:
tiernoa278b842020-07-08 15:33:55 +00005149 descriptor_configuration = db_nsd.get("ns-configuration")
5150
garciadeblas5697b8b2021-03-24 09:17:02 +01005151 if descriptor_configuration and descriptor_configuration.get(
5152 "config-primitive"
5153 ):
tiernoa278b842020-07-08 15:33:55 +00005154 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00005155 if config_primitive["name"] == primitive:
5156 config_primitive_desc = config_primitive
5157 break
tiernoda964822019-01-14 15:53:47 +00005158
garciadeblas6bed6b32020-07-20 11:05:42 +00005159 if not config_primitive_desc:
5160 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005161 raise LcmException(
5162 "Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".format(
5163 primitive
5164 )
5165 )
garciadeblas6bed6b32020-07-20 11:05:42 +00005166 primitive_name = primitive
5167 ee_descriptor_id = None
5168 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005169 primitive_name = config_primitive_desc.get(
5170 "execution-environment-primitive", primitive
5171 )
5172 ee_descriptor_id = config_primitive_desc.get(
5173 "execution-environment-ref"
5174 )
tierno1b633412019-02-25 16:48:23 +00005175
tierno1b633412019-02-25 16:48:23 +00005176 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00005177 if vdu_id:
garciadeblas5697b8b2021-03-24 09:17:02 +01005178 vdur = next(
5179 (x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None
5180 )
bravof922c4172020-11-24 21:21:43 -03005181 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005182 elif kdu_name:
garciadeblas5697b8b2021-03-24 09:17:02 +01005183 kdur = next(
5184 (x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None
5185 )
bravof922c4172020-11-24 21:21:43 -03005186 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00005187 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005188 desc_params = parse_yaml_strings(
5189 db_vnfr.get("additionalParamsForVnf")
5190 )
tierno1b633412019-02-25 16:48:23 +00005191 else:
bravof922c4172020-11-24 21:21:43 -03005192 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03005193 if kdu_name and get_configuration(db_vnfd, kdu_name):
5194 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01005195 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01005196 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005197 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01005198 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01005199 actions.add(primitive["name"])
David Garciaae230232022-05-10 14:07:12 +02005200 kdu = find_in_list(
5201 nsr_deployed["K8s"],
5202 lambda kdu: kdu_name == kdu["kdu-name"]
5203 and kdu["member-vnf-index"] == vnf_index,
5204 )
5205 kdu_action = (
5206 True
5207 if primitive_name in actions
5208 and kdu["k8scluster-type"] not in ("helm-chart", "helm-chart-v3")
5209 else False
5210 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005211
tiernoda964822019-01-14 15:53:47 +00005212 # TODO check if ns is in a proper status
garciadeblas5697b8b2021-03-24 09:17:02 +01005213 if kdu_name and (
5214 primitive_name in ("upgrade", "rollback", "status") or kdu_action
5215 ):
tierno067e04a2020-03-31 12:53:13 +00005216 # kdur and desc_params already set from before
5217 if primitive_params:
5218 desc_params.update(primitive_params)
5219 # TODO Check if we will need something at vnf level
5220 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
garciadeblas5697b8b2021-03-24 09:17:02 +01005221 if (
5222 kdu_name == kdu["kdu-name"]
5223 and kdu["member-vnf-index"] == vnf_index
5224 ):
tierno067e04a2020-03-31 12:53:13 +00005225 break
5226 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005227 raise LcmException(
5228 "KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index)
5229 )
quilesj7e13aeb2019-10-08 13:34:55 +02005230
tierno067e04a2020-03-31 12:53:13 +00005231 if kdu.get("k8scluster-type") not in self.k8scluster_map:
garciadeblas5697b8b2021-03-24 09:17:02 +01005232 msg = "unknown k8scluster-type '{}'".format(
5233 kdu.get("k8scluster-type")
5234 )
tierno067e04a2020-03-31 12:53:13 +00005235 raise LcmException(msg)
5236
garciadeblas5697b8b2021-03-24 09:17:02 +01005237 db_dict = {
5238 "collection": "nsrs",
5239 "filter": {"_id": nsr_id},
5240 "path": "_admin.deployed.K8s.{}".format(index),
5241 }
5242 self.logger.debug(
5243 logging_text
5244 + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)
5245 )
tiernoa278b842020-07-08 15:33:55 +00005246 step = "Executing kdu {}".format(primitive_name)
5247 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00005248 if desc_params.get("kdu_model"):
5249 kdu_model = desc_params.get("kdu_model")
5250 del desc_params["kdu_model"]
5251 else:
5252 kdu_model = kdu.get("kdu-model")
5253 parts = kdu_model.split(sep=":")
5254 if len(parts) == 2:
5255 kdu_model = parts[0]
5256
5257 detailed_status = await asyncio.wait_for(
5258 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
5259 cluster_uuid=kdu.get("k8scluster-uuid"),
5260 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005261 atomic=True,
5262 kdu_model=kdu_model,
5263 params=desc_params,
5264 db_dict=db_dict,
5265 timeout=timeout_ns_action,
5266 ),
5267 timeout=timeout_ns_action + 10,
5268 )
5269 self.logger.debug(
5270 logging_text + " Upgrade of kdu {} done".format(detailed_status)
5271 )
tiernoa278b842020-07-08 15:33:55 +00005272 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00005273 detailed_status = await asyncio.wait_for(
5274 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
5275 cluster_uuid=kdu.get("k8scluster-uuid"),
5276 kdu_instance=kdu.get("kdu-instance"),
garciadeblas5697b8b2021-03-24 09:17:02 +01005277 db_dict=db_dict,
5278 ),
5279 timeout=timeout_ns_action,
5280 )
tiernoa278b842020-07-08 15:33:55 +00005281 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00005282 detailed_status = await asyncio.wait_for(
5283 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
5284 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02005285 kdu_instance=kdu.get("kdu-instance"),
5286 vca_id=vca_id,
5287 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005288 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005289 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005290 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005291 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(
5292 kdu["kdu-name"], nsr_id
5293 )
5294 params = self._map_primitive_params(
5295 config_primitive_desc, primitive_params, desc_params
5296 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02005297
5298 detailed_status = await asyncio.wait_for(
5299 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
5300 cluster_uuid=kdu.get("k8scluster-uuid"),
5301 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00005302 primitive_name=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005303 params=params,
5304 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02005305 timeout=timeout_ns_action,
5306 vca_id=vca_id,
5307 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01005308 timeout=timeout_ns_action,
David Garciac1fe90a2021-03-31 19:12:02 +02005309 )
tierno067e04a2020-03-31 12:53:13 +00005310
5311 if detailed_status:
garciadeblas5697b8b2021-03-24 09:17:02 +01005312 nslcmop_operation_state = "COMPLETED"
tierno067e04a2020-03-31 12:53:13 +00005313 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005314 detailed_status = ""
5315 nslcmop_operation_state = "FAILED"
tierno067e04a2020-03-31 12:53:13 +00005316 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01005317 ee_id, vca_type = self._look_for_deployed_vca(
5318 nsr_deployed["VCA"],
5319 member_vnf_index=vnf_index,
5320 vdu_id=vdu_id,
5321 vdu_count_index=vdu_count_index,
5322 ee_descriptor_id=ee_descriptor_id,
5323 )
5324 for vca_index, vca_deployed in enumerate(
5325 db_nsr["_admin"]["deployed"]["VCA"]
5326 ):
ksaikiranrb1c9f372021-03-15 11:07:29 +05305327 if vca_deployed.get("member-vnf-index") == vnf_index:
garciadeblas5697b8b2021-03-24 09:17:02 +01005328 db_dict = {
5329 "collection": "nsrs",
5330 "filter": {"_id": nsr_id},
5331 "path": "_admin.deployed.VCA.{}.".format(vca_index),
5332 }
ksaikiranrb1c9f372021-03-15 11:07:29 +05305333 break
garciadeblas5697b8b2021-03-24 09:17:02 +01005334 (
5335 nslcmop_operation_state,
5336 detailed_status,
5337 ) = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00005338 ee_id,
tiernoa278b842020-07-08 15:33:55 +00005339 primitive=primitive_name,
garciadeblas5697b8b2021-03-24 09:17:02 +01005340 primitive_params=self._map_primitive_params(
5341 config_primitive_desc, primitive_params, desc_params
5342 ),
tierno588547c2020-07-01 15:30:20 +00005343 timeout=timeout_ns_action,
5344 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02005345 db_dict=db_dict,
5346 vca_id=vca_id,
5347 )
tierno067e04a2020-03-31 12:53:13 +00005348
5349 db_nslcmop_update["detailed-status"] = detailed_status
garciadeblas5697b8b2021-03-24 09:17:02 +01005350 error_description_nslcmop = (
5351 detailed_status if nslcmop_operation_state == "FAILED" else ""
5352 )
5353 self.logger.debug(
5354 logging_text
Mark Beierl0240ddd2022-08-19 15:01:06 -04005355 + "Done with result {} {}".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01005356 nslcmop_operation_state, detailed_status
5357 )
5358 )
tierno59d22d22018-09-25 18:10:19 +02005359 return # database update is called inside finally
5360
tiernof59ad6c2020-04-08 12:50:52 +00005361 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02005362 self.logger.error(logging_text + "Exit Exception {}".format(e))
5363 exc = e
5364 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01005365 self.logger.error(
5366 logging_text + "Cancelled Exception while '{}'".format(step)
5367 )
tierno59d22d22018-09-25 18:10:19 +02005368 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00005369 except asyncio.TimeoutError:
5370 self.logger.error(logging_text + "Timeout while '{}'".format(step))
5371 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02005372 except Exception as e:
5373 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01005374 self.logger.critical(
5375 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
5376 exc_info=True,
5377 )
tierno59d22d22018-09-25 18:10:19 +02005378 finally:
tierno067e04a2020-03-31 12:53:13 +00005379 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01005380 db_nslcmop_update[
5381 "detailed-status"
5382 ] = (
5383 detailed_status
5384 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00005385 nslcmop_operation_state = "FAILED"
5386 if db_nsr:
5387 self._write_ns_status(
5388 nsr_id=nsr_id,
garciadeblas5697b8b2021-03-24 09:17:02 +01005389 ns_state=db_nsr[
5390 "nsState"
5391 ], # TODO check if degraded. For the moment use previous status
tierno067e04a2020-03-31 12:53:13 +00005392 current_operation="IDLE",
5393 current_operation_id=None,
5394 # error_description=error_description_nsr,
5395 # error_detail=error_detail,
garciadeblas5697b8b2021-03-24 09:17:02 +01005396 other_update=db_nsr_update,
tierno067e04a2020-03-31 12:53:13 +00005397 )
5398
garciadeblas5697b8b2021-03-24 09:17:02 +01005399 self._write_op_status(
5400 op_id=nslcmop_id,
5401 stage="",
5402 error_message=error_description_nslcmop,
5403 operation_state=nslcmop_operation_state,
5404 other_update=db_nslcmop_update,
5405 )
tierno067e04a2020-03-31 12:53:13 +00005406
tierno59d22d22018-09-25 18:10:19 +02005407 if nslcmop_operation_state:
5408 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01005409 await self.msg.aiowrite(
5410 "ns",
5411 "actioned",
5412 {
5413 "nsr_id": nsr_id,
5414 "nslcmop_id": nslcmop_id,
5415 "operationState": nslcmop_operation_state,
5416 },
5417 loop=self.loop,
5418 )
tierno59d22d22018-09-25 18:10:19 +02005419 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01005420 self.logger.error(
5421 logging_text + "kafka_write notification Exception {}".format(e)
5422 )
tierno59d22d22018-09-25 18:10:19 +02005423 self.logger.debug(logging_text + "Exit")
5424 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00005425 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02005426
elumalaica7ece02022-04-12 12:47:32 +05305427 async def terminate_vdus(
5428 self, db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text
5429 ):
5430 """This method terminates VDUs
5431
5432 Args:
5433 db_vnfr: VNF instance record
5434 member_vnf_index: VNF index to identify the VDUs to be removed
5435 db_nsr: NS instance record
5436 update_db_nslcmops: Nslcmop update record
5437 """
5438 vca_scaling_info = []
5439 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5440 scaling_info["scaling_direction"] = "IN"
5441 scaling_info["vdu-delete"] = {}
5442 scaling_info["kdu-delete"] = {}
5443 db_vdur = db_vnfr.get("vdur")
5444 vdur_list = copy(db_vdur)
5445 count_index = 0
5446 for index, vdu in enumerate(vdur_list):
5447 vca_scaling_info.append(
5448 {
5449 "osm_vdu_id": vdu["vdu-id-ref"],
5450 "member-vnf-index": member_vnf_index,
5451 "type": "delete",
5452 "vdu_index": count_index,
preethika.p28b0bf82022-09-23 07:36:28 +00005453 }
5454 )
elumalaica7ece02022-04-12 12:47:32 +05305455 scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
5456 scaling_info["vdu"].append(
5457 {
5458 "name": vdu.get("name") or vdu.get("vdu-name"),
5459 "vdu_id": vdu["vdu-id-ref"],
5460 "interface": [],
preethika.p28b0bf82022-09-23 07:36:28 +00005461 }
5462 )
elumalaica7ece02022-04-12 12:47:32 +05305463 for interface in vdu["interfaces"]:
5464 scaling_info["vdu"][index]["interface"].append(
5465 {
5466 "name": interface["name"],
5467 "ip_address": interface["ip-address"],
5468 "mac_address": interface.get("mac-address"),
preethika.p28b0bf82022-09-23 07:36:28 +00005469 }
5470 )
elumalaica7ece02022-04-12 12:47:32 +05305471 self.logger.info("NS update scaling info{}".format(scaling_info))
5472 stage[2] = "Terminating VDUs"
5473 if scaling_info.get("vdu-delete"):
5474 # scale_process = "RO"
5475 if self.ro_config.get("ng"):
5476 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005477 logging_text,
5478 db_nsr,
5479 update_db_nslcmops,
5480 db_vnfr,
5481 scaling_info,
5482 stage,
elumalaica7ece02022-04-12 12:47:32 +05305483 )
5484
preethika.p28b0bf82022-09-23 07:36:28 +00005485 async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
elumalaica7ece02022-04-12 12:47:32 +05305486 """This method is to Remove VNF instances from NS.
5487
5488 Args:
5489 nsr_id: NS instance id
5490 nslcmop_id: nslcmop id of update
5491 vnf_instance_id: id of the VNF instance to be removed
5492
5493 Returns:
5494 result: (str, str) COMPLETED/FAILED, details
5495 """
5496 try:
5497 db_nsr_update = {}
5498 logging_text = "Task ns={} update ".format(nsr_id)
5499 check_vnfr_count = len(self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}))
5500 self.logger.info("check_vnfr_count {}".format(check_vnfr_count))
5501 if check_vnfr_count > 1:
5502 stage = ["", "", ""]
5503 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00005504 self.logger.debug(
5505 step + " after having waited for previous tasks to be completed"
5506 )
elumalaica7ece02022-04-12 12:47:32 +05305507 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5508 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5509 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5510 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5511 """ db_vnfr = self.db.get_one(
5512 "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
5513
5514 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
preethika.p28b0bf82022-09-23 07:36:28 +00005515 await self.terminate_vdus(
5516 db_vnfr,
5517 member_vnf_index,
5518 db_nsr,
5519 update_db_nslcmops,
5520 stage,
5521 logging_text,
5522 )
elumalaica7ece02022-04-12 12:47:32 +05305523
5524 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
5525 constituent_vnfr.remove(db_vnfr.get("_id"))
preethika.p28b0bf82022-09-23 07:36:28 +00005526 db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
5527 "constituent-vnfr-ref"
5528 )
elumalaica7ece02022-04-12 12:47:32 +05305529 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5530 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
5531 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5532 return "COMPLETED", "Done"
5533 else:
5534 step = "Terminate VNF Failed with"
preethika.p28b0bf82022-09-23 07:36:28 +00005535 raise LcmException(
5536 "{} Cannot terminate the last VNF in this NS.".format(
5537 vnf_instance_id
5538 )
5539 )
elumalaica7ece02022-04-12 12:47:32 +05305540 except (LcmException, asyncio.CancelledError):
5541 raise
5542 except Exception as e:
5543 self.logger.debug("Error removing VNF {}".format(e))
5544 return "FAILED", "Error removing VNF {}".format(e)
5545
elumalaib9e357c2022-04-27 09:58:38 +05305546 async def _ns_redeploy_vnf(
preethika.p28b0bf82022-09-23 07:36:28 +00005547 self,
5548 nsr_id,
5549 nslcmop_id,
5550 db_vnfd,
5551 db_vnfr,
5552 db_nsr,
elumalaib9e357c2022-04-27 09:58:38 +05305553 ):
5554 """This method updates and redeploys VNF instances
5555
5556 Args:
5557 nsr_id: NS instance id
5558 nslcmop_id: nslcmop id
5559 db_vnfd: VNF descriptor
5560 db_vnfr: VNF instance record
5561 db_nsr: NS instance record
5562
5563 Returns:
5564 result: (str, str) COMPLETED/FAILED, details
5565 """
5566 try:
5567 count_index = 0
5568 stage = ["", "", ""]
5569 logging_text = "Task ns={} update ".format(nsr_id)
5570 latest_vnfd_revision = db_vnfd["_admin"].get("revision")
5571 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5572
5573 # Terminate old VNF resources
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 )
elumalaib9e357c2022-04-27 09:58:38 +05305583
5584 # old_vnfd_id = db_vnfr["vnfd-id"]
5585 # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
5586 new_db_vnfd = db_vnfd
5587 # new_vnfd_ref = new_db_vnfd["id"]
5588 # new_vnfd_id = vnfd_id
5589
5590 # Create VDUR
5591 new_vnfr_cp = []
5592 for cp in new_db_vnfd.get("ext-cpd", ()):
5593 vnf_cp = {
5594 "name": cp.get("id"),
5595 "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
5596 "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
5597 "id": cp.get("id"),
5598 }
5599 new_vnfr_cp.append(vnf_cp)
5600 new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
5601 # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
5602 # 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 +00005603 new_vnfr_update = {
5604 "revision": latest_vnfd_revision,
5605 "connection-point": new_vnfr_cp,
5606 "vdur": new_vdur,
5607 "ip-address": "",
5608 }
elumalaib9e357c2022-04-27 09:58:38 +05305609 self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
5610 updated_db_vnfr = self.db.get_one(
preethika.p28b0bf82022-09-23 07:36:28 +00005611 "vnfrs",
5612 {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
elumalaib9e357c2022-04-27 09:58:38 +05305613 )
5614
5615 # Instantiate new VNF resources
5616 # update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
5617 vca_scaling_info = []
5618 scaling_info = {"scaling_group_name": "vdu_autoscale", "vdu": [], "kdu": []}
5619 scaling_info["scaling_direction"] = "OUT"
5620 scaling_info["vdu-create"] = {}
5621 scaling_info["kdu-create"] = {}
5622 vdud_instantiate_list = db_vnfd["vdu"]
5623 for index, vdud in enumerate(vdud_instantiate_list):
preethika.p28b0bf82022-09-23 07:36:28 +00005624 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
elumalaib9e357c2022-04-27 09:58:38 +05305625 if cloud_init_text:
5626 additional_params = (
5627 self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
5628 or {}
5629 )
5630 cloud_init_list = []
5631 if cloud_init_text:
5632 # TODO Information of its own ip is not available because db_vnfr is not updated.
5633 additional_params["OSM"] = get_osm_params(
5634 updated_db_vnfr, vdud["id"], 1
5635 )
5636 cloud_init_list.append(
5637 self._parse_cloud_init(
5638 cloud_init_text,
5639 additional_params,
5640 db_vnfd["id"],
5641 vdud["id"],
5642 )
5643 )
5644 vca_scaling_info.append(
5645 {
5646 "osm_vdu_id": vdud["id"],
5647 "member-vnf-index": member_vnf_index,
5648 "type": "create",
5649 "vdu_index": count_index,
5650 }
5651 )
5652 scaling_info["vdu-create"][vdud["id"]] = count_index
5653 if self.ro_config.get("ng"):
5654 self.logger.debug(
preethika.p28b0bf82022-09-23 07:36:28 +00005655 "New Resources to be deployed: {}".format(scaling_info)
5656 )
elumalaib9e357c2022-04-27 09:58:38 +05305657 await self._scale_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00005658 logging_text,
5659 db_nsr,
5660 update_db_nslcmops,
5661 updated_db_vnfr,
5662 scaling_info,
5663 stage,
elumalaib9e357c2022-04-27 09:58:38 +05305664 )
5665 return "COMPLETED", "Done"
5666 except (LcmException, asyncio.CancelledError):
5667 raise
5668 except Exception as e:
5669 self.logger.debug("Error updating VNF {}".format(e))
5670 return "FAILED", "Error updating VNF {}".format(e)
5671
aticigdffa6212022-04-12 15:27:53 +03005672 async def _ns_charm_upgrade(
5673 self,
5674 ee_id,
5675 charm_id,
5676 charm_type,
5677 path,
5678 timeout: float = None,
5679 ) -> (str, str):
5680 """This method upgrade charms in VNF instances
5681
5682 Args:
5683 ee_id: Execution environment id
5684 path: Local path to the charm
5685 charm_id: charm-id
5686 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
5687 timeout: (Float) Timeout for the ns update operation
5688
5689 Returns:
5690 result: (str, str) COMPLETED/FAILED, details
5691 """
5692 try:
5693 charm_type = charm_type or "lxc_proxy_charm"
5694 output = await self.vca_map[charm_type].upgrade_charm(
5695 ee_id=ee_id,
5696 path=path,
5697 charm_id=charm_id,
5698 charm_type=charm_type,
5699 timeout=timeout or self.timeout_ns_update,
5700 )
5701
5702 if output:
5703 return "COMPLETED", output
5704
5705 except (LcmException, asyncio.CancelledError):
5706 raise
5707
5708 except Exception as e:
5709
5710 self.logger.debug("Error upgrading charm {}".format(path))
5711
5712 return "FAILED", "Error upgrading charm {}: {}".format(path, e)
5713
5714 async def update(self, nsr_id, nslcmop_id):
5715 """Update NS according to different update types
5716
5717 This method performs upgrade of VNF instances then updates the revision
5718 number in VNF record
5719
5720 Args:
5721 nsr_id: Network service will be updated
5722 nslcmop_id: ns lcm operation id
5723
5724 Returns:
5725 It may raise DbException, LcmException, N2VCException, K8sException
5726
5727 """
5728 # Try to lock HA task here
5729 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
5730 if not task_is_locked_by_me:
5731 return
5732
5733 logging_text = "Task ns={} update={} ".format(nsr_id, nslcmop_id)
5734 self.logger.debug(logging_text + "Enter")
5735
5736 # Set the required variables to be filled up later
5737 db_nsr = None
5738 db_nslcmop_update = {}
5739 vnfr_update = {}
5740 nslcmop_operation_state = None
5741 db_nsr_update = {}
5742 error_description_nslcmop = ""
5743 exc = None
elumalaica7ece02022-04-12 12:47:32 +05305744 change_type = "updated"
aticigdffa6212022-04-12 15:27:53 +03005745 detailed_status = ""
5746
5747 try:
5748 # wait for any previous tasks in process
5749 step = "Waiting for previous operations to terminate"
5750 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
5751 self._write_ns_status(
5752 nsr_id=nsr_id,
5753 ns_state=None,
5754 current_operation="UPDATING",
5755 current_operation_id=nslcmop_id,
5756 )
5757
5758 step = "Getting nslcmop from database"
5759 db_nslcmop = self.db.get_one(
5760 "nslcmops", {"_id": nslcmop_id}, fail_on_empty=False
5761 )
5762 update_type = db_nslcmop["operationParams"]["updateType"]
5763
5764 step = "Getting nsr from database"
5765 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
5766 old_operational_status = db_nsr["operational-status"]
5767 db_nsr_update["operational-status"] = "updating"
5768 self.update_db_2("nsrs", nsr_id, db_nsr_update)
5769 nsr_deployed = db_nsr["_admin"].get("deployed")
5770
5771 if update_type == "CHANGE_VNFPKG":
5772
5773 # Get the input parameters given through update request
5774 vnf_instance_id = db_nslcmop["operationParams"][
5775 "changeVnfPackageData"
5776 ].get("vnfInstanceId")
5777
5778 vnfd_id = db_nslcmop["operationParams"]["changeVnfPackageData"].get(
5779 "vnfdId"
5780 )
5781 timeout_seconds = db_nslcmop["operationParams"].get("timeout_ns_update")
5782
5783 step = "Getting vnfr from database"
5784 db_vnfr = self.db.get_one(
5785 "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
5786 )
5787
5788 step = "Getting vnfds from database"
5789 # Latest VNFD
5790 latest_vnfd = self.db.get_one(
5791 "vnfds", {"_id": vnfd_id}, fail_on_empty=False
5792 )
5793 latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
5794
5795 # Current VNFD
5796 current_vnf_revision = db_vnfr.get("revision", 1)
5797 current_vnfd = self.db.get_one(
5798 "vnfds_revisions",
5799 {"_id": vnfd_id + ":" + str(current_vnf_revision)},
5800 fail_on_empty=False,
5801 )
5802 # Charm artifact paths will be filled up later
5803 (
5804 current_charm_artifact_path,
5805 target_charm_artifact_path,
5806 charm_artifact_paths,
5807 ) = ([], [], [])
5808
5809 step = "Checking if revision has changed in VNFD"
5810 if current_vnf_revision != latest_vnfd_revision:
5811
elumalaib9e357c2022-04-27 09:58:38 +05305812 change_type = "policy_updated"
5813
aticigdffa6212022-04-12 15:27:53 +03005814 # There is new revision of VNFD, update operation is required
5815 current_vnfd_path = vnfd_id + ":" + str(current_vnf_revision)
aticigd7083542022-05-30 20:45:55 +03005816 latest_vnfd_path = vnfd_id + ":" + str(latest_vnfd_revision)
aticigdffa6212022-04-12 15:27:53 +03005817
5818 step = "Removing the VNFD packages if they exist in the local path"
5819 shutil.rmtree(self.fs.path + current_vnfd_path, ignore_errors=True)
5820 shutil.rmtree(self.fs.path + latest_vnfd_path, ignore_errors=True)
5821
5822 step = "Get the VNFD packages from FSMongo"
5823 self.fs.sync(from_path=latest_vnfd_path)
5824 self.fs.sync(from_path=current_vnfd_path)
5825
5826 step = (
5827 "Get the charm-type, charm-id, ee-id if there is deployed VCA"
5828 )
5829 base_folder = latest_vnfd["_admin"]["storage"]
5830
5831 for charm_index, charm_deployed in enumerate(
5832 get_iterable(nsr_deployed, "VCA")
5833 ):
5834 vnf_index = db_vnfr.get("member-vnf-index-ref")
5835
5836 # Getting charm-id and charm-type
5837 if charm_deployed.get("member-vnf-index") == vnf_index:
5838 charm_id = self.get_vca_id(db_vnfr, db_nsr)
5839 charm_type = charm_deployed.get("type")
5840
5841 # Getting ee-id
5842 ee_id = charm_deployed.get("ee_id")
5843
5844 step = "Getting descriptor config"
5845 descriptor_config = get_configuration(
5846 current_vnfd, current_vnfd["id"]
5847 )
5848
5849 if "execution-environment-list" in descriptor_config:
5850 ee_list = descriptor_config.get(
5851 "execution-environment-list", []
5852 )
5853 else:
5854 ee_list = []
5855
5856 # There could be several charm used in the same VNF
5857 for ee_item in ee_list:
5858 if ee_item.get("juju"):
5859
5860 step = "Getting charm name"
5861 charm_name = ee_item["juju"].get("charm")
5862
5863 step = "Setting Charm artifact paths"
5864 current_charm_artifact_path.append(
5865 get_charm_artifact_path(
5866 base_folder,
5867 charm_name,
5868 charm_type,
5869 current_vnf_revision,
5870 )
5871 )
5872 target_charm_artifact_path.append(
5873 get_charm_artifact_path(
5874 base_folder,
5875 charm_name,
5876 charm_type,
aticigd7083542022-05-30 20:45:55 +03005877 latest_vnfd_revision,
aticigdffa6212022-04-12 15:27:53 +03005878 )
5879 )
5880
5881 charm_artifact_paths = zip(
5882 current_charm_artifact_path, target_charm_artifact_path
5883 )
5884
5885 step = "Checking if software version has changed in VNFD"
5886 if find_software_version(current_vnfd) != find_software_version(
5887 latest_vnfd
5888 ):
5889
5890 step = "Checking if existing VNF has charm"
5891 for current_charm_path, target_charm_path in list(
5892 charm_artifact_paths
5893 ):
5894 if current_charm_path:
5895 raise LcmException(
5896 "Software version change is not supported as VNF instance {} has charm.".format(
5897 vnf_instance_id
5898 )
5899 )
5900
5901 # There is no change in the charm package, then redeploy the VNF
5902 # based on new descriptor
5903 step = "Redeploying VNF"
elumalaib9e357c2022-04-27 09:58:38 +05305904 member_vnf_index = db_vnfr["member-vnf-index-ref"]
preethika.p28b0bf82022-09-23 07:36:28 +00005905 (result, detailed_status) = await self._ns_redeploy_vnf(
5906 nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
elumalaib9e357c2022-04-27 09:58:38 +05305907 )
5908 if result == "FAILED":
5909 nslcmop_operation_state = result
5910 error_description_nslcmop = detailed_status
5911 db_nslcmop_update["detailed-status"] = detailed_status
5912 self.logger.debug(
5913 logging_text
5914 + " step {} Done with result {} {}".format(
5915 step, nslcmop_operation_state, detailed_status
5916 )
5917 )
aticigdffa6212022-04-12 15:27:53 +03005918
5919 else:
5920 step = "Checking if any charm package has changed or not"
5921 for current_charm_path, target_charm_path in list(
5922 charm_artifact_paths
5923 ):
5924 if (
5925 current_charm_path
5926 and target_charm_path
5927 and self.check_charm_hash_changed(
5928 current_charm_path, target_charm_path
5929 )
5930 ):
5931
5932 step = "Checking whether VNF uses juju bundle"
5933 if check_juju_bundle_existence(current_vnfd):
5934
5935 raise LcmException(
5936 "Charm upgrade is not supported for the instance which"
5937 " uses juju-bundle: {}".format(
5938 check_juju_bundle_existence(current_vnfd)
5939 )
5940 )
5941
5942 step = "Upgrading Charm"
5943 (
5944 result,
5945 detailed_status,
5946 ) = await self._ns_charm_upgrade(
5947 ee_id=ee_id,
5948 charm_id=charm_id,
5949 charm_type=charm_type,
5950 path=self.fs.path + target_charm_path,
5951 timeout=timeout_seconds,
5952 )
5953
5954 if result == "FAILED":
5955 nslcmop_operation_state = result
5956 error_description_nslcmop = detailed_status
5957
5958 db_nslcmop_update["detailed-status"] = detailed_status
5959 self.logger.debug(
5960 logging_text
5961 + " step {} Done with result {} {}".format(
5962 step, nslcmop_operation_state, detailed_status
5963 )
5964 )
5965
5966 step = "Updating policies"
elumalaib9e357c2022-04-27 09:58:38 +05305967 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5968 result = "COMPLETED"
5969 detailed_status = "Done"
5970 db_nslcmop_update["detailed-status"] = "Done"
aticigdffa6212022-04-12 15:27:53 +03005971
5972 # If nslcmop_operation_state is None, so any operation is not failed.
5973 if not nslcmop_operation_state:
5974 nslcmop_operation_state = "COMPLETED"
5975
5976 # If update CHANGE_VNFPKG nslcmop_operation is successful
5977 # vnf revision need to be updated
5978 vnfr_update["revision"] = latest_vnfd_revision
5979 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
5980
5981 self.logger.debug(
5982 logging_text
5983 + " task Done with result {} {}".format(
5984 nslcmop_operation_state, detailed_status
5985 )
5986 )
5987 elif update_type == "REMOVE_VNF":
5988 # This part is included in https://osm.etsi.org/gerrit/11876
elumalaica7ece02022-04-12 12:47:32 +05305989 vnf_instance_id = db_nslcmop["operationParams"]["removeVnfInstanceId"]
5990 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
5991 member_vnf_index = db_vnfr["member-vnf-index-ref"]
5992 step = "Removing VNF"
preethika.p28b0bf82022-09-23 07:36:28 +00005993 (result, detailed_status) = await self.remove_vnf(
5994 nsr_id, nslcmop_id, vnf_instance_id
5995 )
elumalaica7ece02022-04-12 12:47:32 +05305996 if result == "FAILED":
5997 nslcmop_operation_state = result
5998 error_description_nslcmop = detailed_status
5999 db_nslcmop_update["detailed-status"] = detailed_status
6000 change_type = "vnf_terminated"
6001 if not nslcmop_operation_state:
6002 nslcmop_operation_state = "COMPLETED"
6003 self.logger.debug(
6004 logging_text
6005 + " task Done with result {} {}".format(
6006 nslcmop_operation_state, detailed_status
6007 )
6008 )
aticigdffa6212022-04-12 15:27:53 +03006009
k4.rahulb827de92022-05-02 16:35:02 +00006010 elif update_type == "OPERATE_VNF":
preethika.p28b0bf82022-09-23 07:36:28 +00006011 vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
6012 "vnfInstanceId"
6013 ]
6014 operation_type = db_nslcmop["operationParams"]["operateVnfData"][
6015 "changeStateTo"
6016 ]
6017 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
6018 "additionalParam"
6019 ]
k4.rahulb827de92022-05-02 16:35:02 +00006020 (result, detailed_status) = await self.rebuild_start_stop(
6021 nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
preethika.p28b0bf82022-09-23 07:36:28 +00006022 )
k4.rahulb827de92022-05-02 16:35:02 +00006023 if result == "FAILED":
6024 nslcmop_operation_state = result
6025 error_description_nslcmop = detailed_status
6026 db_nslcmop_update["detailed-status"] = detailed_status
6027 if not nslcmop_operation_state:
6028 nslcmop_operation_state = "COMPLETED"
6029 self.logger.debug(
6030 logging_text
6031 + " task Done with result {} {}".format(
6032 nslcmop_operation_state, detailed_status
6033 )
6034 )
6035
aticigdffa6212022-04-12 15:27:53 +03006036 # If nslcmop_operation_state is None, so any operation is not failed.
6037 # All operations are executed in overall.
6038 if not nslcmop_operation_state:
6039 nslcmop_operation_state = "COMPLETED"
6040 db_nsr_update["operational-status"] = old_operational_status
6041
6042 except (DbException, LcmException, N2VCException, K8sException) as e:
6043 self.logger.error(logging_text + "Exit Exception {}".format(e))
6044 exc = e
6045 except asyncio.CancelledError:
6046 self.logger.error(
6047 logging_text + "Cancelled Exception while '{}'".format(step)
6048 )
6049 exc = "Operation was cancelled"
6050 except asyncio.TimeoutError:
6051 self.logger.error(logging_text + "Timeout while '{}'".format(step))
6052 exc = "Timeout"
6053 except Exception as e:
6054 exc = traceback.format_exc()
6055 self.logger.critical(
6056 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
6057 exc_info=True,
6058 )
6059 finally:
6060 if exc:
6061 db_nslcmop_update[
6062 "detailed-status"
6063 ] = (
6064 detailed_status
6065 ) = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
6066 nslcmop_operation_state = "FAILED"
6067 db_nsr_update["operational-status"] = old_operational_status
6068 if db_nsr:
6069 self._write_ns_status(
6070 nsr_id=nsr_id,
6071 ns_state=db_nsr["nsState"],
6072 current_operation="IDLE",
6073 current_operation_id=None,
6074 other_update=db_nsr_update,
6075 )
6076
6077 self._write_op_status(
6078 op_id=nslcmop_id,
6079 stage="",
6080 error_message=error_description_nslcmop,
6081 operation_state=nslcmop_operation_state,
6082 other_update=db_nslcmop_update,
6083 )
6084
6085 if nslcmop_operation_state:
6086 try:
elumalaica7ece02022-04-12 12:47:32 +05306087 msg = {
elumalaib9e357c2022-04-27 09:58:38 +05306088 "nsr_id": nsr_id,
6089 "nslcmop_id": nslcmop_id,
6090 "operationState": nslcmop_operation_state,
6091 }
6092 if change_type in ("vnf_terminated", "policy_updated"):
elumalaica7ece02022-04-12 12:47:32 +05306093 msg.update({"vnf_member_index": member_vnf_index})
6094 await self.msg.aiowrite("ns", change_type, msg, loop=self.loop)
aticigdffa6212022-04-12 15:27:53 +03006095 except Exception as e:
6096 self.logger.error(
6097 logging_text + "kafka_write notification Exception {}".format(e)
6098 )
6099 self.logger.debug(logging_text + "Exit")
6100 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_update")
6101 return nslcmop_operation_state, detailed_status
6102
tierno59d22d22018-09-25 18:10:19 +02006103 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02006104 # Try to lock HA task here
garciadeblas5697b8b2021-03-24 09:17:02 +01006105 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
kuused124bfe2019-06-18 12:09:24 +02006106 if not task_is_locked_by_me:
6107 return
6108
tierno59d22d22018-09-25 18:10:19 +02006109 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
garciadeblas5697b8b2021-03-24 09:17:02 +01006110 stage = ["", "", ""]
aktas13251562021-02-12 22:19:10 +03006111 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00006112 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02006113 self.logger.debug(logging_text + "Enter")
6114 # get all needed from database
6115 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02006116 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00006117 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02006118 exc = None
tierno9ab95942018-10-10 16:44:22 +02006119 # in case of error, indicates what part of scale was failed to put nsr at error status
6120 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02006121 old_operational_status = ""
6122 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03006123 nsi_id = None
tierno59d22d22018-09-25 18:10:19 +02006124 try:
kuused124bfe2019-06-18 12:09:24 +02006125 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00006126 step = "Waiting for previous operations to terminate"
garciadeblas5697b8b2021-03-24 09:17:02 +01006127 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
6128 self._write_ns_status(
6129 nsr_id=nsr_id,
6130 ns_state=None,
6131 current_operation="SCALING",
6132 current_operation_id=nslcmop_id,
6133 )
quilesj4cda56b2019-12-05 10:02:20 +00006134
ikalyvas02d9e7b2019-05-27 18:16:01 +03006135 step = "Getting nslcmop from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006136 self.logger.debug(
6137 step + " after having waited for previous tasks to be completed"
6138 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006139 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03006140
ikalyvas02d9e7b2019-05-27 18:16:01 +03006141 step = "Getting nsr from database"
6142 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006143 old_operational_status = db_nsr["operational-status"]
6144 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03006145
tierno59d22d22018-09-25 18:10:19 +02006146 step = "Parsing scaling parameters"
6147 db_nsr_update["operational-status"] = "scaling"
6148 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00006149 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01006150
garciadeblas5697b8b2021-03-24 09:17:02 +01006151 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
6152 "scaleByStepData"
6153 ]["member-vnf-index"]
6154 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"][
6155 "scaleByStepData"
6156 ]["scaling-group-descriptor"]
tierno59d22d22018-09-25 18:10:19 +02006157 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00006158 # for backward compatibility
6159 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
6160 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
6161 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
6162 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6163
tierno59d22d22018-09-25 18:10:19 +02006164 step = "Getting vnfr from database"
garciadeblas5697b8b2021-03-24 09:17:02 +01006165 db_vnfr = self.db.get_one(
6166 "vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id}
6167 )
bravof922c4172020-11-24 21:21:43 -03006168
David Garciac1fe90a2021-03-31 19:12:02 +02006169 vca_id = self.get_vca_id(db_vnfr, db_nsr)
6170
tierno59d22d22018-09-25 18:10:19 +02006171 step = "Getting vnfd from database"
6172 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03006173
aktas13251562021-02-12 22:19:10 +03006174 base_folder = db_vnfd["_admin"]["storage"]
6175
tierno59d22d22018-09-25 18:10:19 +02006176 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03006177 scaling_descriptor = find_in_list(
garciadeblas5697b8b2021-03-24 09:17:02 +01006178 get_scaling_aspect(db_vnfd),
6179 lambda scale_desc: scale_desc["name"] == scaling_group,
bravof832f8992020-12-07 12:57:31 -03006180 )
6181 if not scaling_descriptor:
garciadeblas5697b8b2021-03-24 09:17:02 +01006182 raise LcmException(
6183 "input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
6184 "at vnfd:scaling-group-descriptor".format(scaling_group)
6185 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006186
tierno15b1cf12019-08-29 13:21:40 +00006187 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03006188 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02006189 nb_scale_op = 0
6190 if not db_nsr["_admin"].get("scaling-group"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006191 self.update_db_2(
6192 "nsrs",
6193 nsr_id,
6194 {
6195 "_admin.scaling-group": [
6196 {"name": scaling_group, "nb-scale-op": 0}
6197 ]
6198 },
6199 )
tierno59d22d22018-09-25 18:10:19 +02006200 admin_scale_index = 0
6201 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006202 for admin_scale_index, admin_scale_info in enumerate(
6203 db_nsr["_admin"]["scaling-group"]
6204 ):
tierno59d22d22018-09-25 18:10:19 +02006205 if admin_scale_info["name"] == scaling_group:
6206 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
6207 break
tierno9ab95942018-10-10 16:44:22 +02006208 else: # not found, set index one plus last element and add new entry with the name
6209 admin_scale_index += 1
garciadeblas5697b8b2021-03-24 09:17:02 +01006210 db_nsr_update[
6211 "_admin.scaling-group.{}.name".format(admin_scale_index)
6212 ] = scaling_group
aktas5f75f102021-03-15 11:26:10 +03006213
6214 vca_scaling_info = []
6215 scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
tierno59d22d22018-09-25 18:10:19 +02006216 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03006217 if "aspect-delta-details" not in scaling_descriptor:
6218 raise LcmException(
6219 "Aspect delta details not fount in scaling descriptor {}".format(
6220 scaling_descriptor["name"]
6221 )
6222 )
tierno59d22d22018-09-25 18:10:19 +02006223 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03006224 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02006225
aktas5f75f102021-03-15 11:26:10 +03006226 scaling_info["scaling_direction"] = "OUT"
6227 scaling_info["vdu-create"] = {}
6228 scaling_info["kdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03006229 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006230 for vdu_delta in delta.get("vdu-delta", {}):
bravof832f8992020-12-07 12:57:31 -03006231 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006232 # vdu_index also provides the number of instance of the targeted vdu
6233 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
garciadeblas5697b8b2021-03-24 09:17:02 +01006234 cloud_init_text = self._get_vdu_cloud_init_content(
6235 vdud, db_vnfd
6236 )
tierno72ef84f2020-10-06 08:22:07 +00006237 if cloud_init_text:
garciadeblas5697b8b2021-03-24 09:17:02 +01006238 additional_params = (
6239 self._get_vdu_additional_params(db_vnfr, vdud["id"])
6240 or {}
6241 )
bravof832f8992020-12-07 12:57:31 -03006242 cloud_init_list = []
6243
6244 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6245 max_instance_count = 10
6246 if vdu_profile and "max-number-of-instances" in vdu_profile:
garciadeblas5697b8b2021-03-24 09:17:02 +01006247 max_instance_count = vdu_profile.get(
6248 "max-number-of-instances", 10
6249 )
6250
6251 default_instance_num = get_number_of_instances(
6252 db_vnfd, vdud["id"]
6253 )
aktas5f75f102021-03-15 11:26:10 +03006254 instances_number = vdu_delta.get("number-of-instances", 1)
6255 nb_scale_op += instances_number
bravof832f8992020-12-07 12:57:31 -03006256
aktas5f75f102021-03-15 11:26:10 +03006257 new_instance_count = nb_scale_op + default_instance_num
6258 # Control if new count is over max and vdu count is less than max.
6259 # Then assign new instance count
6260 if new_instance_count > max_instance_count > vdu_count:
6261 instances_number = new_instance_count - max_instance_count
6262 else:
6263 instances_number = instances_number
bravof832f8992020-12-07 12:57:31 -03006264
aktas5f75f102021-03-15 11:26:10 +03006265 if new_instance_count > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03006266 raise LcmException(
6267 "reached the limit of {} (max-instance-count) "
6268 "scaling-out operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006269 "scaling-group-descriptor '{}'".format(
6270 nb_scale_op, scaling_group
6271 )
bravof922c4172020-11-24 21:21:43 -03006272 )
bravof832f8992020-12-07 12:57:31 -03006273 for x in range(vdu_delta.get("number-of-instances", 1)):
6274 if cloud_init_text:
6275 # TODO Information of its own ip is not available because db_vnfr is not updated.
6276 additional_params["OSM"] = get_osm_params(
garciadeblas5697b8b2021-03-24 09:17:02 +01006277 db_vnfr, vdu_delta["id"], vdu_index + x
bravof922c4172020-11-24 21:21:43 -03006278 )
bravof832f8992020-12-07 12:57:31 -03006279 cloud_init_list.append(
6280 self._parse_cloud_init(
6281 cloud_init_text,
6282 additional_params,
6283 db_vnfd["id"],
garciadeblas5697b8b2021-03-24 09:17:02 +01006284 vdud["id"],
bravof832f8992020-12-07 12:57:31 -03006285 )
6286 )
aktas5f75f102021-03-15 11:26:10 +03006287 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006288 {
6289 "osm_vdu_id": vdu_delta["id"],
6290 "member-vnf-index": vnf_index,
6291 "type": "create",
garciadeblas5697b8b2021-03-24 09:17:02 +01006292 "vdu_index": vdu_index + x,
aktas13251562021-02-12 22:19:10 +03006293 }
6294 )
aktas5f75f102021-03-15 11:26:10 +03006295 scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
6296 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006297 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006298 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006299 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006300
6301 # Might have different kdus in the same delta
6302 # Should have list for each kdu
6303 if not scaling_info["kdu-create"].get(kdu_name, None):
6304 scaling_info["kdu-create"][kdu_name] = []
6305
6306 kdur = get_kdur(db_vnfr, kdu_name)
6307 if kdur.get("helm-chart"):
6308 k8s_cluster_type = "helm-chart-v3"
6309 self.logger.debug("kdur: {}".format(kdur))
6310 if (
6311 kdur.get("helm-version")
6312 and kdur.get("helm-version") == "v2"
6313 ):
6314 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006315 elif kdur.get("juju-bundle"):
6316 k8s_cluster_type = "juju-bundle"
6317 else:
6318 raise LcmException(
6319 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6320 "juju-bundle. Maybe an old NBI version is running".format(
6321 db_vnfr["member-vnf-index-ref"], kdu_name
6322 )
6323 )
6324
6325 max_instance_count = 10
6326 if kdu_profile and "max-number-of-instances" in kdu_profile:
6327 max_instance_count = kdu_profile.get(
6328 "max-number-of-instances", 10
6329 )
6330
6331 nb_scale_op += kdu_delta.get("number-of-instances", 1)
6332 deployed_kdu, _ = get_deployed_kdu(
6333 nsr_deployed, kdu_name, vnf_index
bravof832f8992020-12-07 12:57:31 -03006334 )
aktas5f75f102021-03-15 11:26:10 +03006335 if deployed_kdu is None:
6336 raise LcmException(
6337 "KDU '{}' for vnf '{}' not deployed".format(
6338 kdu_name, vnf_index
6339 )
6340 )
6341 kdu_instance = deployed_kdu.get("kdu-instance")
6342 instance_num = await self.k8scluster_map[
6343 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006344 ].get_scale_count(
6345 resource_name,
6346 kdu_instance,
6347 vca_id=vca_id,
6348 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6349 kdu_model=deployed_kdu.get("kdu-model"),
6350 )
aktas5f75f102021-03-15 11:26:10 +03006351 kdu_replica_count = instance_num + kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006352 "number-of-instances", 1
6353 )
ikalyvas02d9e7b2019-05-27 18:16:01 +03006354
aktas5f75f102021-03-15 11:26:10 +03006355 # Control if new count is over max and instance_num is less than max.
6356 # Then assign max instance number to kdu replica count
6357 if kdu_replica_count > max_instance_count > instance_num:
6358 kdu_replica_count = max_instance_count
6359 if kdu_replica_count > max_instance_count:
6360 raise LcmException(
6361 "reached the limit of {} (max-instance-count) "
6362 "scaling-out operations for the "
6363 "scaling-group-descriptor '{}'".format(
6364 instance_num, scaling_group
6365 )
6366 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006367
aktas5f75f102021-03-15 11:26:10 +03006368 for x in range(kdu_delta.get("number-of-instances", 1)):
6369 vca_scaling_info.append(
6370 {
6371 "osm_kdu_id": kdu_name,
6372 "member-vnf-index": vnf_index,
6373 "type": "create",
6374 "kdu_index": instance_num + x - 1,
6375 }
6376 )
6377 scaling_info["kdu-create"][kdu_name].append(
6378 {
6379 "member-vnf-index": vnf_index,
6380 "type": "create",
6381 "k8s-cluster-type": k8s_cluster_type,
6382 "resource-name": resource_name,
6383 "scale": kdu_replica_count,
6384 }
6385 )
6386 elif scaling_type == "SCALE_IN":
bravof832f8992020-12-07 12:57:31 -03006387 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
aktas5f75f102021-03-15 11:26:10 +03006388
6389 scaling_info["scaling_direction"] = "IN"
6390 scaling_info["vdu-delete"] = {}
6391 scaling_info["kdu-delete"] = {}
6392
bravof832f8992020-12-07 12:57:31 -03006393 for delta in deltas:
aktas5f75f102021-03-15 11:26:10 +03006394 for vdu_delta in delta.get("vdu-delta", {}):
6395 vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03006396 min_instance_count = 0
6397 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
6398 if vdu_profile and "min-number-of-instances" in vdu_profile:
6399 min_instance_count = vdu_profile["min-number-of-instances"]
6400
garciadeblas5697b8b2021-03-24 09:17:02 +01006401 default_instance_num = get_number_of_instances(
6402 db_vnfd, vdu_delta["id"]
6403 )
aktas5f75f102021-03-15 11:26:10 +03006404 instance_num = vdu_delta.get("number-of-instances", 1)
6405 nb_scale_op -= instance_num
bravof832f8992020-12-07 12:57:31 -03006406
aktas5f75f102021-03-15 11:26:10 +03006407 new_instance_count = nb_scale_op + default_instance_num
6408
6409 if new_instance_count < min_instance_count < vdu_count:
6410 instances_number = min_instance_count - new_instance_count
6411 else:
6412 instances_number = instance_num
6413
6414 if new_instance_count < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03006415 raise LcmException(
6416 "reached the limit of {} (min-instance-count) scaling-in operations for the "
garciadeblas5697b8b2021-03-24 09:17:02 +01006417 "scaling-group-descriptor '{}'".format(
6418 nb_scale_op, scaling_group
6419 )
bravof832f8992020-12-07 12:57:31 -03006420 )
aktas13251562021-02-12 22:19:10 +03006421 for x in range(vdu_delta.get("number-of-instances", 1)):
aktas5f75f102021-03-15 11:26:10 +03006422 vca_scaling_info.append(
aktas13251562021-02-12 22:19:10 +03006423 {
6424 "osm_vdu_id": vdu_delta["id"],
6425 "member-vnf-index": vnf_index,
6426 "type": "delete",
garciadeblas5697b8b2021-03-24 09:17:02 +01006427 "vdu_index": vdu_index - 1 - x,
aktas13251562021-02-12 22:19:10 +03006428 }
6429 )
aktas5f75f102021-03-15 11:26:10 +03006430 scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
6431 for kdu_delta in delta.get("kdu-resource-delta", {}):
David Garciab4ebcd02021-10-28 02:00:43 +02006432 kdu_profile = get_kdu_resource_profile(db_vnfd, kdu_delta["id"])
aktas5f75f102021-03-15 11:26:10 +03006433 kdu_name = kdu_profile["kdu-name"]
aktasc41fe832021-11-29 18:41:42 +03006434 resource_name = kdu_profile.get("resource-name", "")
aktas5f75f102021-03-15 11:26:10 +03006435
6436 if not scaling_info["kdu-delete"].get(kdu_name, None):
6437 scaling_info["kdu-delete"][kdu_name] = []
6438
6439 kdur = get_kdur(db_vnfr, kdu_name)
6440 if kdur.get("helm-chart"):
6441 k8s_cluster_type = "helm-chart-v3"
6442 self.logger.debug("kdur: {}".format(kdur))
6443 if (
6444 kdur.get("helm-version")
6445 and kdur.get("helm-version") == "v2"
6446 ):
6447 k8s_cluster_type = "helm-chart"
aktas5f75f102021-03-15 11:26:10 +03006448 elif kdur.get("juju-bundle"):
6449 k8s_cluster_type = "juju-bundle"
6450 else:
6451 raise LcmException(
6452 "kdu type for kdu='{}.{}' is neither helm-chart nor "
6453 "juju-bundle. Maybe an old NBI version is running".format(
6454 db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
6455 )
6456 )
6457
6458 min_instance_count = 0
6459 if kdu_profile and "min-number-of-instances" in kdu_profile:
6460 min_instance_count = kdu_profile["min-number-of-instances"]
6461
6462 nb_scale_op -= kdu_delta.get("number-of-instances", 1)
6463 deployed_kdu, _ = get_deployed_kdu(
6464 nsr_deployed, kdu_name, vnf_index
6465 )
6466 if deployed_kdu is None:
6467 raise LcmException(
6468 "KDU '{}' for vnf '{}' not deployed".format(
6469 kdu_name, vnf_index
6470 )
6471 )
6472 kdu_instance = deployed_kdu.get("kdu-instance")
6473 instance_num = await self.k8scluster_map[
6474 k8s_cluster_type
aktasc41fe832021-11-29 18:41:42 +03006475 ].get_scale_count(
6476 resource_name,
6477 kdu_instance,
6478 vca_id=vca_id,
6479 cluster_uuid=deployed_kdu.get("k8scluster-uuid"),
6480 kdu_model=deployed_kdu.get("kdu-model"),
6481 )
aktas5f75f102021-03-15 11:26:10 +03006482 kdu_replica_count = instance_num - kdu_delta.get(
garciadeblas5697b8b2021-03-24 09:17:02 +01006483 "number-of-instances", 1
6484 )
tierno59d22d22018-09-25 18:10:19 +02006485
aktas5f75f102021-03-15 11:26:10 +03006486 if kdu_replica_count < min_instance_count < instance_num:
6487 kdu_replica_count = min_instance_count
6488 if kdu_replica_count < min_instance_count:
6489 raise LcmException(
6490 "reached the limit of {} (min-instance-count) scaling-in operations for the "
6491 "scaling-group-descriptor '{}'".format(
6492 instance_num, scaling_group
6493 )
6494 )
6495
6496 for x in range(kdu_delta.get("number-of-instances", 1)):
6497 vca_scaling_info.append(
6498 {
6499 "osm_kdu_id": kdu_name,
6500 "member-vnf-index": vnf_index,
6501 "type": "delete",
6502 "kdu_index": instance_num - x - 1,
6503 }
6504 )
6505 scaling_info["kdu-delete"][kdu_name].append(
6506 {
6507 "member-vnf-index": vnf_index,
6508 "type": "delete",
6509 "k8s-cluster-type": k8s_cluster_type,
6510 "resource-name": resource_name,
6511 "scale": kdu_replica_count,
6512 }
6513 )
6514
tierno59d22d22018-09-25 18:10:19 +02006515 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
aktas5f75f102021-03-15 11:26:10 +03006516 vdu_delete = copy(scaling_info.get("vdu-delete"))
6517 if scaling_info["scaling_direction"] == "IN":
tierno59d22d22018-09-25 18:10:19 +02006518 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02006519 if vdu_delete.get(vdur["vdu-id-ref"]):
6520 vdu_delete[vdur["vdu-id-ref"]] -= 1
aktas5f75f102021-03-15 11:26:10 +03006521 scaling_info["vdu"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006522 {
6523 "name": vdur.get("name") or vdur.get("vdu-name"),
6524 "vdu_id": vdur["vdu-id-ref"],
6525 "interface": [],
6526 }
6527 )
tierno59d22d22018-09-25 18:10:19 +02006528 for interface in vdur["interfaces"]:
aktas5f75f102021-03-15 11:26:10 +03006529 scaling_info["vdu"][-1]["interface"].append(
garciadeblas5697b8b2021-03-24 09:17:02 +01006530 {
6531 "name": interface["name"],
6532 "ip_address": interface["ip-address"],
6533 "mac_address": interface.get("mac-address"),
6534 }
6535 )
tierno2357f4e2020-10-19 16:38:59 +00006536 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02006537
kuuseac3a8882019-10-03 10:48:06 +02006538 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006539 step = "Executing pre-scale vnf-config-primitive"
6540 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006541 for scaling_config_action in scaling_descriptor[
6542 "scaling-config-action"
6543 ]:
6544 if (
6545 scaling_config_action.get("trigger") == "pre-scale-in"
6546 and scaling_type == "SCALE_IN"
6547 ) or (
6548 scaling_config_action.get("trigger") == "pre-scale-out"
6549 and scaling_type == "SCALE_OUT"
6550 ):
6551 vnf_config_primitive = scaling_config_action[
6552 "vnf-config-primitive-name-ref"
6553 ]
6554 step = db_nslcmop_update[
6555 "detailed-status"
6556 ] = "executing pre-scale scaling-config-action '{}'".format(
6557 vnf_config_primitive
6558 )
tiernoda964822019-01-14 15:53:47 +00006559
tierno59d22d22018-09-25 18:10:19 +02006560 # look for primitive
garciadeblas5697b8b2021-03-24 09:17:02 +01006561 for config_primitive in (
6562 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6563 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006564 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006565 break
6566 else:
6567 raise LcmException(
6568 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00006569 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
garciadeblas5697b8b2021-03-24 09:17:02 +01006570 "primitive".format(scaling_group, vnf_config_primitive)
6571 )
tiernoda964822019-01-14 15:53:47 +00006572
aktas5f75f102021-03-15 11:26:10 +03006573 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006574 if db_vnfr.get("additionalParamsForVnf"):
6575 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02006576
tierno9ab95942018-10-10 16:44:22 +02006577 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006578 db_nsr_update["config-status"] = "configuring pre-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006579 primitive_params = self._map_primitive_params(
6580 config_primitive, {}, vnfr_params
6581 )
kuuseac3a8882019-10-03 10:48:06 +02006582
tierno7c4e24c2020-05-13 08:41:35 +00006583 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006584 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006585 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006586 vnf_index,
6587 vnf_config_primitive,
6588 primitive_params,
6589 "PRE-SCALE",
6590 )
tierno7c4e24c2020-05-13 08:41:35 +00006591 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006592 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006593 result = "COMPLETED"
6594 result_detail = "Done"
6595 self.logger.debug(
6596 logging_text
6597 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6598 vnf_config_primitive, result, result_detail
6599 )
6600 )
kuuseac3a8882019-10-03 10:48:06 +02006601 else:
tierno7c4e24c2020-05-13 08:41:35 +00006602 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006603 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006604 op_index = (
6605 len(db_nslcmop.get("_admin", {}).get("operations"))
6606 - 1
6607 )
6608 self.logger.debug(
6609 logging_text
6610 + "vnf_config_primitive={} New sub-operation".format(
6611 vnf_config_primitive
6612 )
6613 )
kuuseac3a8882019-10-03 10:48:06 +02006614 else:
tierno7c4e24c2020-05-13 08:41:35 +00006615 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006616 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6617 op_index
6618 ]
6619 vnf_index = op.get("member_vnf_index")
6620 vnf_config_primitive = op.get("primitive")
6621 primitive_params = op.get("primitive_params")
6622 self.logger.debug(
6623 logging_text
6624 + "vnf_config_primitive={} Sub-operation retry".format(
6625 vnf_config_primitive
6626 )
6627 )
tierno588547c2020-07-01 15:30:20 +00006628 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006629 ee_descriptor_id = config_primitive.get(
6630 "execution-environment-ref"
6631 )
6632 primitive_name = config_primitive.get(
6633 "execution-environment-primitive", vnf_config_primitive
6634 )
6635 ee_id, vca_type = self._look_for_deployed_vca(
6636 nsr_deployed["VCA"],
6637 member_vnf_index=vnf_index,
6638 vdu_id=None,
6639 vdu_count_index=None,
6640 ee_descriptor_id=ee_descriptor_id,
6641 )
kuuseac3a8882019-10-03 10:48:06 +02006642 result, result_detail = await self._ns_execute_primitive(
garciadeblas5697b8b2021-03-24 09:17:02 +01006643 ee_id,
6644 primitive_name,
David Garciac1fe90a2021-03-31 19:12:02 +02006645 primitive_params,
6646 vca_type=vca_type,
6647 vca_id=vca_id,
6648 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006649 self.logger.debug(
6650 logging_text
6651 + "vnf_config_primitive={} Done with result {} {}".format(
6652 vnf_config_primitive, result, result_detail
6653 )
6654 )
kuuseac3a8882019-10-03 10:48:06 +02006655 # Update operationState = COMPLETED | FAILED
6656 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01006657 db_nslcmop, op_index, result, result_detail
6658 )
kuuseac3a8882019-10-03 10:48:06 +02006659
tierno59d22d22018-09-25 18:10:19 +02006660 if result == "FAILED":
6661 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02006662 db_nsr_update["config-status"] = old_config_status
6663 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02006664 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02006665
garciadeblas5697b8b2021-03-24 09:17:02 +01006666 db_nsr_update[
6667 "_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)
6668 ] = nb_scale_op
6669 db_nsr_update[
6670 "_admin.scaling-group.{}.time".format(admin_scale_index)
6671 ] = time()
tierno2357f4e2020-10-19 16:38:59 +00006672
aktas13251562021-02-12 22:19:10 +03006673 # SCALE-IN VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006674 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006675 step = db_nslcmop_update[
6676 "detailed-status"
6677 ] = "Deleting the execution environments"
aktas13251562021-02-12 22:19:10 +03006678 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006679 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006680 if vca_info["type"] == "delete" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006681 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01006682 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03006683 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01006684 )
aktas5f75f102021-03-15 11:26:10 +03006685 if vca_info.get("osm_vdu_id"):
6686 vdu_id = vca_info["osm_vdu_id"]
6687 vdu_index = int(vca_info["vdu_index"])
6688 stage[
6689 1
6690 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
6691 member_vnf_index, vdu_id, vdu_index
6692 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006693 stage[2] = step = "Scaling in VCA"
6694 self._write_op_status(op_id=nslcmop_id, stage=stage)
aktas13251562021-02-12 22:19:10 +03006695 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
6696 config_update = db_nsr["configurationStatus"]
6697 for vca_index, vca in enumerate(vca_update):
garciadeblas5697b8b2021-03-24 09:17:02 +01006698 if (
6699 (vca or vca.get("ee_id"))
6700 and vca["member-vnf-index"] == member_vnf_index
6701 and vca["vdu_count_index"] == vdu_index
6702 ):
aktas13251562021-02-12 22:19:10 +03006703 if vca.get("vdu_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006704 config_descriptor = get_configuration(
6705 db_vnfd, vca.get("vdu_id")
6706 )
aktas13251562021-02-12 22:19:10 +03006707 elif vca.get("kdu_name"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006708 config_descriptor = get_configuration(
6709 db_vnfd, vca.get("kdu_name")
6710 )
aktas13251562021-02-12 22:19:10 +03006711 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01006712 config_descriptor = get_configuration(
6713 db_vnfd, db_vnfd["id"]
6714 )
6715 operation_params = (
6716 db_nslcmop.get("operationParams") or {}
6717 )
6718 exec_terminate_primitives = not operation_params.get(
6719 "skip_terminate_primitives"
6720 ) and vca.get("needed_terminate")
David Garciac1fe90a2021-03-31 19:12:02 +02006721 task = asyncio.ensure_future(
6722 asyncio.wait_for(
6723 self.destroy_N2VC(
6724 logging_text,
6725 db_nslcmop,
6726 vca,
6727 config_descriptor,
6728 vca_index,
6729 destroy_ee=True,
6730 exec_primitives=exec_terminate_primitives,
6731 scaling_in=True,
6732 vca_id=vca_id,
6733 ),
garciadeblas5697b8b2021-03-24 09:17:02 +01006734 timeout=self.timeout_charm_delete,
David Garciac1fe90a2021-03-31 19:12:02 +02006735 )
6736 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006737 tasks_dict_info[task] = "Terminating VCA {}".format(
6738 vca.get("ee_id")
6739 )
aktas13251562021-02-12 22:19:10 +03006740 del vca_update[vca_index]
6741 del config_update[vca_index]
6742 # wait for pending tasks of terminate primitives
6743 if tasks_dict_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006744 self.logger.debug(
6745 logging_text
6746 + "Waiting for tasks {}".format(
6747 list(tasks_dict_info.keys())
6748 )
6749 )
6750 error_list = await self._wait_for_tasks(
6751 logging_text,
6752 tasks_dict_info,
6753 min(
6754 self.timeout_charm_delete, self.timeout_ns_terminate
6755 ),
6756 stage,
6757 nslcmop_id,
6758 )
aktas13251562021-02-12 22:19:10 +03006759 tasks_dict_info.clear()
6760 if error_list:
6761 raise LcmException("; ".join(error_list))
6762
6763 db_vca_and_config_update = {
6764 "_admin.deployed.VCA": vca_update,
garciadeblas5697b8b2021-03-24 09:17:02 +01006765 "configurationStatus": config_update,
aktas13251562021-02-12 22:19:10 +03006766 }
garciadeblas5697b8b2021-03-24 09:17:02 +01006767 self.update_db_2(
6768 "nsrs", db_nsr["_id"], db_vca_and_config_update
6769 )
aktas13251562021-02-12 22:19:10 +03006770 scale_process = None
6771 # SCALE-IN VCA - END
6772
kuuseac3a8882019-10-03 10:48:06 +02006773 # SCALE RO - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006774 if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
tierno9ab95942018-10-10 16:44:22 +02006775 scale_process = "RO"
tierno2357f4e2020-10-19 16:38:59 +00006776 if self.ro_config.get("ng"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006777 await self._scale_ng_ro(
aktas5f75f102021-03-15 11:26:10 +03006778 logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
garciadeblas5697b8b2021-03-24 09:17:02 +01006779 )
aktas5f75f102021-03-15 11:26:10 +03006780 scaling_info.pop("vdu-create", None)
6781 scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02006782
tierno9ab95942018-10-10 16:44:22 +02006783 scale_process = None
aktas13251562021-02-12 22:19:10 +03006784 # SCALE RO - END
6785
aktas5f75f102021-03-15 11:26:10 +03006786 # SCALE KDU - BEGIN
6787 if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
6788 scale_process = "KDU"
6789 await self._scale_kdu(
6790 logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
6791 )
6792 scaling_info.pop("kdu-create", None)
6793 scaling_info.pop("kdu-delete", None)
6794
6795 scale_process = None
6796 # SCALE KDU - END
6797
6798 if db_nsr_update:
6799 self.update_db_2("nsrs", nsr_id, db_nsr_update)
6800
aktas13251562021-02-12 22:19:10 +03006801 # SCALE-UP VCA - BEGIN
aktas5f75f102021-03-15 11:26:10 +03006802 if vca_scaling_info:
garciadeblas5697b8b2021-03-24 09:17:02 +01006803 step = db_nslcmop_update[
6804 "detailed-status"
6805 ] = "Creating new execution environments"
aktas13251562021-02-12 22:19:10 +03006806 scale_process = "VCA"
aktas5f75f102021-03-15 11:26:10 +03006807 for vca_info in vca_scaling_info:
Guillermo Calvinoa0c6baf2022-02-02 19:04:50 +01006808 if vca_info["type"] == "create" and not vca_info.get("osm_kdu_id"):
aktas5f75f102021-03-15 11:26:10 +03006809 member_vnf_index = str(vca_info["member-vnf-index"])
garciadeblas5697b8b2021-03-24 09:17:02 +01006810 self.logger.debug(
aktas5f75f102021-03-15 11:26:10 +03006811 logging_text + "vdu info: {}".format(vca_info)
garciadeblas5697b8b2021-03-24 09:17:02 +01006812 )
aktas13251562021-02-12 22:19:10 +03006813 vnfd_id = db_vnfr["vnfd-ref"]
aktas5f75f102021-03-15 11:26:10 +03006814 if vca_info.get("osm_vdu_id"):
6815 vdu_index = int(vca_info["vdu_index"])
6816 deploy_params = {"OSM": get_osm_params(db_vnfr)}
6817 if db_vnfr.get("additionalParamsForVnf"):
6818 deploy_params.update(
6819 parse_yaml_strings(
6820 db_vnfr["additionalParamsForVnf"].copy()
6821 )
garciadeblas5697b8b2021-03-24 09:17:02 +01006822 )
aktas5f75f102021-03-15 11:26:10 +03006823 descriptor_config = get_configuration(
6824 db_vnfd, db_vnfd["id"]
garciadeblas5697b8b2021-03-24 09:17:02 +01006825 )
aktas5f75f102021-03-15 11:26:10 +03006826 if descriptor_config:
6827 vdu_id = None
6828 vdu_name = None
6829 kdu_name = None
6830 self._deploy_n2vc(
6831 logging_text=logging_text
6832 + "member_vnf_index={} ".format(member_vnf_index),
6833 db_nsr=db_nsr,
6834 db_vnfr=db_vnfr,
6835 nslcmop_id=nslcmop_id,
6836 nsr_id=nsr_id,
6837 nsi_id=nsi_id,
6838 vnfd_id=vnfd_id,
6839 vdu_id=vdu_id,
6840 kdu_name=kdu_name,
6841 member_vnf_index=member_vnf_index,
6842 vdu_index=vdu_index,
6843 vdu_name=vdu_name,
6844 deploy_params=deploy_params,
6845 descriptor_config=descriptor_config,
6846 base_folder=base_folder,
6847 task_instantiation_info=tasks_dict_info,
6848 stage=stage,
6849 )
6850 vdu_id = vca_info["osm_vdu_id"]
6851 vdur = find_in_list(
6852 db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
aktas13251562021-02-12 22:19:10 +03006853 )
aktas5f75f102021-03-15 11:26:10 +03006854 descriptor_config = get_configuration(db_vnfd, vdu_id)
6855 if vdur.get("additionalParams"):
6856 deploy_params_vdu = parse_yaml_strings(
6857 vdur["additionalParams"]
6858 )
6859 else:
6860 deploy_params_vdu = deploy_params
6861 deploy_params_vdu["OSM"] = get_osm_params(
6862 db_vnfr, vdu_id, vdu_count_index=vdu_index
garciadeblas5697b8b2021-03-24 09:17:02 +01006863 )
aktas5f75f102021-03-15 11:26:10 +03006864 if descriptor_config:
6865 vdu_name = None
6866 kdu_name = None
6867 stage[
6868 1
6869 ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
garciadeblas5697b8b2021-03-24 09:17:02 +01006870 member_vnf_index, vdu_id, vdu_index
aktas5f75f102021-03-15 11:26:10 +03006871 )
6872 stage[2] = step = "Scaling out VCA"
6873 self._write_op_status(op_id=nslcmop_id, stage=stage)
6874 self._deploy_n2vc(
6875 logging_text=logging_text
6876 + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
6877 member_vnf_index, vdu_id, vdu_index
6878 ),
6879 db_nsr=db_nsr,
6880 db_vnfr=db_vnfr,
6881 nslcmop_id=nslcmop_id,
6882 nsr_id=nsr_id,
6883 nsi_id=nsi_id,
6884 vnfd_id=vnfd_id,
6885 vdu_id=vdu_id,
6886 kdu_name=kdu_name,
6887 member_vnf_index=member_vnf_index,
6888 vdu_index=vdu_index,
6889 vdu_name=vdu_name,
6890 deploy_params=deploy_params_vdu,
6891 descriptor_config=descriptor_config,
6892 base_folder=base_folder,
6893 task_instantiation_info=tasks_dict_info,
6894 stage=stage,
6895 )
aktas13251562021-02-12 22:19:10 +03006896 # SCALE-UP VCA - END
6897 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02006898
kuuseac3a8882019-10-03 10:48:06 +02006899 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02006900 # execute primitive service POST-SCALING
6901 step = "Executing post-scale vnf-config-primitive"
6902 if scaling_descriptor.get("scaling-config-action"):
garciadeblas5697b8b2021-03-24 09:17:02 +01006903 for scaling_config_action in scaling_descriptor[
6904 "scaling-config-action"
6905 ]:
6906 if (
6907 scaling_config_action.get("trigger") == "post-scale-in"
6908 and scaling_type == "SCALE_IN"
6909 ) or (
6910 scaling_config_action.get("trigger") == "post-scale-out"
6911 and scaling_type == "SCALE_OUT"
6912 ):
6913 vnf_config_primitive = scaling_config_action[
6914 "vnf-config-primitive-name-ref"
6915 ]
6916 step = db_nslcmop_update[
6917 "detailed-status"
6918 ] = "executing post-scale scaling-config-action '{}'".format(
6919 vnf_config_primitive
6920 )
tiernoda964822019-01-14 15:53:47 +00006921
aktas5f75f102021-03-15 11:26:10 +03006922 vnfr_params = {"VDU_SCALE_INFO": scaling_info}
tiernoda964822019-01-14 15:53:47 +00006923 if db_vnfr.get("additionalParamsForVnf"):
6924 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
6925
tierno59d22d22018-09-25 18:10:19 +02006926 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03006927 for config_primitive in (
6928 get_configuration(db_vnfd, db_vnfd["id"]) or {}
6929 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02006930 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02006931 break
6932 else:
tiernoa278b842020-07-08 15:33:55 +00006933 raise LcmException(
6934 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
6935 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
garciadeblas5697b8b2021-03-24 09:17:02 +01006936 "config-primitive".format(
6937 scaling_group, vnf_config_primitive
6938 )
6939 )
tierno9ab95942018-10-10 16:44:22 +02006940 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02006941 db_nsr_update["config-status"] = "configuring post-scaling"
garciadeblas5697b8b2021-03-24 09:17:02 +01006942 primitive_params = self._map_primitive_params(
6943 config_primitive, {}, vnfr_params
6944 )
tiernod6de1992018-10-11 13:05:52 +02006945
tierno7c4e24c2020-05-13 08:41:35 +00006946 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02006947 op_index = self._check_or_add_scale_suboperation(
garciadeblas5697b8b2021-03-24 09:17:02 +01006948 db_nslcmop,
garciadeblas5697b8b2021-03-24 09:17:02 +01006949 vnf_index,
6950 vnf_config_primitive,
6951 primitive_params,
6952 "POST-SCALE",
6953 )
quilesj4cda56b2019-12-05 10:02:20 +00006954 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02006955 # Skip sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006956 result = "COMPLETED"
6957 result_detail = "Done"
6958 self.logger.debug(
6959 logging_text
6960 + "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
6961 vnf_config_primitive, result, result_detail
6962 )
6963 )
kuuseac3a8882019-10-03 10:48:06 +02006964 else:
quilesj4cda56b2019-12-05 10:02:20 +00006965 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02006966 # New sub-operation: Get index of this sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006967 op_index = (
6968 len(db_nslcmop.get("_admin", {}).get("operations"))
6969 - 1
6970 )
6971 self.logger.debug(
6972 logging_text
6973 + "vnf_config_primitive={} New sub-operation".format(
6974 vnf_config_primitive
6975 )
6976 )
kuuseac3a8882019-10-03 10:48:06 +02006977 else:
tierno7c4e24c2020-05-13 08:41:35 +00006978 # retry: Get registered params for this existing sub-operation
garciadeblas5697b8b2021-03-24 09:17:02 +01006979 op = db_nslcmop.get("_admin", {}).get("operations", [])[
6980 op_index
6981 ]
6982 vnf_index = op.get("member_vnf_index")
6983 vnf_config_primitive = op.get("primitive")
6984 primitive_params = op.get("primitive_params")
6985 self.logger.debug(
6986 logging_text
6987 + "vnf_config_primitive={} Sub-operation retry".format(
6988 vnf_config_primitive
6989 )
6990 )
tierno588547c2020-07-01 15:30:20 +00006991 # Execute the primitive, either with new (first-time) or registered (reintent) args
garciadeblas5697b8b2021-03-24 09:17:02 +01006992 ee_descriptor_id = config_primitive.get(
6993 "execution-environment-ref"
6994 )
6995 primitive_name = config_primitive.get(
6996 "execution-environment-primitive", vnf_config_primitive
6997 )
6998 ee_id, vca_type = self._look_for_deployed_vca(
6999 nsr_deployed["VCA"],
7000 member_vnf_index=vnf_index,
7001 vdu_id=None,
7002 vdu_count_index=None,
7003 ee_descriptor_id=ee_descriptor_id,
7004 )
kuuseac3a8882019-10-03 10:48:06 +02007005 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02007006 ee_id,
7007 primitive_name,
7008 primitive_params,
7009 vca_type=vca_type,
7010 vca_id=vca_id,
7011 )
garciadeblas5697b8b2021-03-24 09:17:02 +01007012 self.logger.debug(
7013 logging_text
7014 + "vnf_config_primitive={} Done with result {} {}".format(
7015 vnf_config_primitive, result, result_detail
7016 )
7017 )
kuuseac3a8882019-10-03 10:48:06 +02007018 # Update operationState = COMPLETED | FAILED
7019 self._update_suboperation_status(
garciadeblas5697b8b2021-03-24 09:17:02 +01007020 db_nslcmop, op_index, result, result_detail
7021 )
kuuseac3a8882019-10-03 10:48:06 +02007022
tierno59d22d22018-09-25 18:10:19 +02007023 if result == "FAILED":
7024 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02007025 db_nsr_update["config-status"] = old_config_status
7026 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02007027 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02007028
garciadeblas5697b8b2021-03-24 09:17:02 +01007029 db_nsr_update[
7030 "detailed-status"
7031 ] = "" # "scaled {} {}".format(scaling_group, scaling_type)
7032 db_nsr_update["operational-status"] = (
7033 "running"
7034 if old_operational_status == "failed"
ikalyvas02d9e7b2019-05-27 18:16:01 +03007035 else old_operational_status
garciadeblas5697b8b2021-03-24 09:17:02 +01007036 )
tiernod6de1992018-10-11 13:05:52 +02007037 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02007038 return
garciadeblas5697b8b2021-03-24 09:17:02 +01007039 except (
7040 ROclient.ROClientException,
7041 DbException,
7042 LcmException,
7043 NgRoException,
7044 ) as e:
tierno59d22d22018-09-25 18:10:19 +02007045 self.logger.error(logging_text + "Exit Exception {}".format(e))
7046 exc = e
7047 except asyncio.CancelledError:
garciadeblas5697b8b2021-03-24 09:17:02 +01007048 self.logger.error(
7049 logging_text + "Cancelled Exception while '{}'".format(step)
7050 )
tierno59d22d22018-09-25 18:10:19 +02007051 exc = "Operation was cancelled"
7052 except Exception as e:
7053 exc = traceback.format_exc()
garciadeblas5697b8b2021-03-24 09:17:02 +01007054 self.logger.critical(
7055 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7056 exc_info=True,
7057 )
tierno59d22d22018-09-25 18:10:19 +02007058 finally:
garciadeblas5697b8b2021-03-24 09:17:02 +01007059 self._write_ns_status(
7060 nsr_id=nsr_id,
7061 ns_state=None,
7062 current_operation="IDLE",
7063 current_operation_id=None,
7064 )
aktas13251562021-02-12 22:19:10 +03007065 if tasks_dict_info:
7066 stage[1] = "Waiting for instantiate pending tasks."
7067 self.logger.debug(logging_text + stage[1])
garciadeblas5697b8b2021-03-24 09:17:02 +01007068 exc = await self._wait_for_tasks(
7069 logging_text,
7070 tasks_dict_info,
7071 self.timeout_ns_deploy,
7072 stage,
7073 nslcmop_id,
7074 nsr_id=nsr_id,
7075 )
tierno59d22d22018-09-25 18:10:19 +02007076 if exc:
garciadeblas5697b8b2021-03-24 09:17:02 +01007077 db_nslcmop_update[
7078 "detailed-status"
7079 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
tiernoa17d4f42020-04-28 09:59:23 +00007080 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02007081 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02007082 db_nsr_update["operational-status"] = old_operational_status
7083 db_nsr_update["config-status"] = old_config_status
7084 db_nsr_update["detailed-status"] = ""
7085 if scale_process:
7086 if "VCA" in scale_process:
7087 db_nsr_update["config-status"] = "failed"
7088 if "RO" in scale_process:
7089 db_nsr_update["operational-status"] = "failed"
garciadeblas5697b8b2021-03-24 09:17:02 +01007090 db_nsr_update[
7091 "detailed-status"
7092 ] = "FAILED scaling nslcmop={} {}: {}".format(
7093 nslcmop_id, step, exc
7094 )
tiernoa17d4f42020-04-28 09:59:23 +00007095 else:
7096 error_description_nslcmop = None
7097 nslcmop_operation_state = "COMPLETED"
7098 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00007099
garciadeblas5697b8b2021-03-24 09:17:02 +01007100 self._write_op_status(
7101 op_id=nslcmop_id,
7102 stage="",
7103 error_message=error_description_nslcmop,
7104 operation_state=nslcmop_operation_state,
7105 other_update=db_nslcmop_update,
7106 )
tiernoa17d4f42020-04-28 09:59:23 +00007107 if db_nsr:
garciadeblas5697b8b2021-03-24 09:17:02 +01007108 self._write_ns_status(
7109 nsr_id=nsr_id,
7110 ns_state=None,
7111 current_operation="IDLE",
7112 current_operation_id=None,
7113 other_update=db_nsr_update,
7114 )
tiernoa17d4f42020-04-28 09:59:23 +00007115
tierno59d22d22018-09-25 18:10:19 +02007116 if nslcmop_operation_state:
7117 try:
garciadeblas5697b8b2021-03-24 09:17:02 +01007118 msg = {
7119 "nsr_id": nsr_id,
7120 "nslcmop_id": nslcmop_id,
7121 "operationState": nslcmop_operation_state,
7122 }
bravof922c4172020-11-24 21:21:43 -03007123 await self.msg.aiowrite("ns", "scaled", msg, loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02007124 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +01007125 self.logger.error(
7126 logging_text + "kafka_write notification Exception {}".format(e)
7127 )
tierno59d22d22018-09-25 18:10:19 +02007128 self.logger.debug(logging_text + "Exit")
7129 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00007130
aktas5f75f102021-03-15 11:26:10 +03007131 async def _scale_kdu(
7132 self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
7133 ):
7134 _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
7135 for kdu_name in _scaling_info:
7136 for kdu_scaling_info in _scaling_info[kdu_name]:
7137 deployed_kdu, index = get_deployed_kdu(
7138 nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
7139 )
7140 cluster_uuid = deployed_kdu["k8scluster-uuid"]
7141 kdu_instance = deployed_kdu["kdu-instance"]
aktasc41fe832021-11-29 18:41:42 +03007142 kdu_model = deployed_kdu.get("kdu-model")
aktas5f75f102021-03-15 11:26:10 +03007143 scale = int(kdu_scaling_info["scale"])
7144 k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
7145
7146 db_dict = {
7147 "collection": "nsrs",
7148 "filter": {"_id": nsr_id},
7149 "path": "_admin.deployed.K8s.{}".format(index),
7150 }
7151
7152 step = "scaling application {}".format(
7153 kdu_scaling_info["resource-name"]
7154 )
7155 self.logger.debug(logging_text + step)
7156
7157 if kdu_scaling_info["type"] == "delete":
7158 kdu_config = get_configuration(db_vnfd, kdu_name)
7159 if (
7160 kdu_config
7161 and kdu_config.get("terminate-config-primitive")
7162 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7163 ):
7164 terminate_config_primitive_list = kdu_config.get(
7165 "terminate-config-primitive"
7166 )
7167 terminate_config_primitive_list.sort(
7168 key=lambda val: int(val["seq"])
7169 )
7170
7171 for (
7172 terminate_config_primitive
7173 ) in terminate_config_primitive_list:
7174 primitive_params_ = self._map_primitive_params(
7175 terminate_config_primitive, {}, {}
7176 )
7177 step = "execute terminate config primitive"
7178 self.logger.debug(logging_text + step)
7179 await asyncio.wait_for(
7180 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7181 cluster_uuid=cluster_uuid,
7182 kdu_instance=kdu_instance,
7183 primitive_name=terminate_config_primitive["name"],
7184 params=primitive_params_,
7185 db_dict=db_dict,
7186 vca_id=vca_id,
7187 ),
7188 timeout=600,
7189 )
7190
7191 await asyncio.wait_for(
7192 self.k8scluster_map[k8s_cluster_type].scale(
7193 kdu_instance,
7194 scale,
7195 kdu_scaling_info["resource-name"],
7196 vca_id=vca_id,
aktasc41fe832021-11-29 18:41:42 +03007197 cluster_uuid=cluster_uuid,
7198 kdu_model=kdu_model,
7199 atomic=True,
7200 db_dict=db_dict,
aktas5f75f102021-03-15 11:26:10 +03007201 ),
7202 timeout=self.timeout_vca_on_error,
7203 )
7204
7205 if kdu_scaling_info["type"] == "create":
7206 kdu_config = get_configuration(db_vnfd, kdu_name)
7207 if (
7208 kdu_config
7209 and kdu_config.get("initial-config-primitive")
7210 and get_juju_ee_ref(db_vnfd, kdu_name) is None
7211 ):
7212 initial_config_primitive_list = kdu_config.get(
7213 "initial-config-primitive"
7214 )
7215 initial_config_primitive_list.sort(
7216 key=lambda val: int(val["seq"])
7217 )
7218
7219 for initial_config_primitive in initial_config_primitive_list:
7220 primitive_params_ = self._map_primitive_params(
7221 initial_config_primitive, {}, {}
7222 )
7223 step = "execute initial config primitive"
7224 self.logger.debug(logging_text + step)
7225 await asyncio.wait_for(
7226 self.k8scluster_map[k8s_cluster_type].exec_primitive(
7227 cluster_uuid=cluster_uuid,
7228 kdu_instance=kdu_instance,
7229 primitive_name=initial_config_primitive["name"],
7230 params=primitive_params_,
7231 db_dict=db_dict,
7232 vca_id=vca_id,
7233 ),
7234 timeout=600,
7235 )
7236
garciadeblas5697b8b2021-03-24 09:17:02 +01007237 async def _scale_ng_ro(
7238 self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
7239 ):
tierno2357f4e2020-10-19 16:38:59 +00007240 nsr_id = db_nslcmop["nsInstanceId"]
7241 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7242 db_vnfrs = {}
7243
7244 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03007245 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00007246
7247 # for each vnf in ns, read vnfd
7248 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
7249 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
7250 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00007251 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03007252 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00007253 # read from db
7254 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03007255 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00007256 n2vc_key = self.n2vc.get_public_key()
7257 n2vc_key_list = [n2vc_key]
garciadeblas5697b8b2021-03-24 09:17:02 +01007258 self.scale_vnfr(
7259 db_vnfr,
7260 vdu_scaling_info.get("vdu-create"),
7261 vdu_scaling_info.get("vdu-delete"),
7262 mark_delete=True,
7263 )
tierno2357f4e2020-10-19 16:38:59 +00007264 # db_vnfr has been updated, update db_vnfrs to use it
7265 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
garciadeblas5697b8b2021-03-24 09:17:02 +01007266 await self._instantiate_ng_ro(
7267 logging_text,
7268 nsr_id,
7269 db_nsd,
7270 db_nsr,
7271 db_nslcmop,
7272 db_vnfrs,
7273 db_vnfds,
7274 n2vc_key_list,
7275 stage=stage,
7276 start_deploy=time(),
7277 timeout_ns_deploy=self.timeout_ns_deploy,
7278 )
tierno2357f4e2020-10-19 16:38:59 +00007279 if vdu_scaling_info.get("vdu-delete"):
garciadeblas5697b8b2021-03-24 09:17:02 +01007280 self.scale_vnfr(
7281 db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False
7282 )
tierno2357f4e2020-10-19 16:38:59 +00007283
bravof73bac502021-05-11 07:38:47 -04007284 async def extract_prometheus_scrape_jobs(
aticig15db6142022-01-24 12:51:26 +03007285 self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip
garciadeblas5697b8b2021-03-24 09:17:02 +01007286 ):
tiernob996d942020-07-03 14:52:28 +00007287 # look if exist a file called 'prometheus*.j2' and
7288 artifact_content = self.fs.dir_ls(artifact_path)
garciadeblas5697b8b2021-03-24 09:17:02 +01007289 job_file = next(
7290 (
7291 f
7292 for f in artifact_content
7293 if f.startswith("prometheus") and f.endswith(".j2")
7294 ),
7295 None,
7296 )
tiernob996d942020-07-03 14:52:28 +00007297 if not job_file:
7298 return
7299 with self.fs.file_open((artifact_path, job_file), "r") as f:
7300 job_data = f.read()
7301
7302 # TODO get_service
garciadeblas5697b8b2021-03-24 09:17:02 +01007303 _, _, service = ee_id.partition(".") # remove prefix "namespace."
tiernob996d942020-07-03 14:52:28 +00007304 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
7305 host_port = "80"
7306 vnfr_id = vnfr_id.replace("-", "")
7307 variables = {
7308 "JOB_NAME": vnfr_id,
7309 "TARGET_IP": target_ip,
7310 "EXPORTER_POD_IP": host_name,
7311 "EXPORTER_POD_PORT": host_port,
7312 }
bravof73bac502021-05-11 07:38:47 -04007313 job_list = parse_job(job_data, variables)
tiernob996d942020-07-03 14:52:28 +00007314 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
7315 for job in job_list:
garciadeblas5697b8b2021-03-24 09:17:02 +01007316 if (
7317 not isinstance(job.get("job_name"), str)
7318 or vnfr_id not in job["job_name"]
7319 ):
tiernob996d942020-07-03 14:52:28 +00007320 job["job_name"] = vnfr_id + "_" + str(randint(1, 10000))
7321 job["nsr_id"] = nsr_id
bravof73bac502021-05-11 07:38:47 -04007322 job["vnfr_id"] = vnfr_id
7323 return job_list
David Garciaaae391f2020-11-09 11:12:54 +01007324
preethika.p28b0bf82022-09-23 07:36:28 +00007325 async def rebuild_start_stop(
7326 self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
7327 ):
k4.rahulb827de92022-05-02 16:35:02 +00007328 logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
7329 self.logger.info(logging_text + "Enter")
7330 stage = ["Preparing the environment", ""]
7331 # database nsrs record
7332 db_nsr_update = {}
7333 vdu_vim_name = None
7334 vim_vm_id = None
7335 # in case of error, indicates what part of scale was failed to put nsr at error status
7336 start_deploy = time()
7337 try:
7338 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
7339 vim_account_id = db_vnfr.get("vim-account-id")
7340 vim_info_key = "vim:" + vim_account_id
k4.rahul4ca27532022-07-27 10:37:26 +00007341 vdu_id = additional_param["vdu_id"]
7342 vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
k4.rahulb827de92022-05-02 16:35:02 +00007343 vdur = find_in_list(
k4.rahul4ca27532022-07-27 10:37:26 +00007344 vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
preethika.p28b0bf82022-09-23 07:36:28 +00007345 )
k4.rahulb827de92022-05-02 16:35:02 +00007346 if vdur:
7347 vdu_vim_name = vdur["name"]
7348 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
7349 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
k4.rahul4ca27532022-07-27 10:37:26 +00007350 else:
7351 raise LcmException("Target vdu is not found")
k4.rahulb827de92022-05-02 16:35:02 +00007352 self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
7353 # wait for any previous tasks in process
7354 stage[1] = "Waiting for previous operations to terminate"
7355 self.logger.info(stage[1])
preethika.p28b0bf82022-09-23 07:36:28 +00007356 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
k4.rahulb827de92022-05-02 16:35:02 +00007357
7358 stage[1] = "Reading from database."
7359 self.logger.info(stage[1])
7360 self._write_ns_status(
7361 nsr_id=nsr_id,
7362 ns_state=None,
7363 current_operation=operation_type.upper(),
preethika.p28b0bf82022-09-23 07:36:28 +00007364 current_operation_id=nslcmop_id,
k4.rahulb827de92022-05-02 16:35:02 +00007365 )
7366 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7367
7368 # read from db: ns
7369 stage[1] = "Getting nsr={} from db.".format(nsr_id)
7370 db_nsr_update["operational-status"] = operation_type
7371 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7372 # Payload for RO
7373 desc = {
7374 operation_type: {
7375 "vim_vm_id": vim_vm_id,
7376 "vnf_id": vnf_id,
7377 "vdu_index": additional_param["count-index"],
7378 "vdu_id": vdur["id"],
7379 "target_vim": target_vim,
preethika.p28b0bf82022-09-23 07:36:28 +00007380 "vim_account_id": vim_account_id,
k4.rahulb827de92022-05-02 16:35:02 +00007381 }
7382 }
7383 stage[1] = "Sending rebuild request to RO... {}".format(desc)
7384 self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
7385 self.logger.info("ro nsr id: {}".format(nsr_id))
7386 result_dict = await self.RO.operate(nsr_id, desc, operation_type)
7387 self.logger.info("response from RO: {}".format(result_dict))
7388 action_id = result_dict["action_id"]
7389 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007390 nsr_id,
7391 action_id,
7392 nslcmop_id,
7393 start_deploy,
7394 self.timeout_operate,
7395 None,
7396 "start_stop_rebuild",
k4.rahulb827de92022-05-02 16:35:02 +00007397 )
7398 return "COMPLETED", "Done"
7399 except (ROclient.ROClientException, DbException, LcmException) as e:
7400 self.logger.error("Exit Exception {}".format(e))
7401 exc = e
7402 except asyncio.CancelledError:
7403 self.logger.error("Cancelled Exception while '{}'".format(stage))
7404 exc = "Operation was cancelled"
7405 except Exception as e:
7406 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00007407 self.logger.critical(
7408 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7409 )
k4.rahulb827de92022-05-02 16:35:02 +00007410 return "FAILED", "Error in operate VNF {}".format(exc)
7411
David Garciaaae391f2020-11-09 11:12:54 +01007412 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7413 """
7414 Get VCA Cloud and VCA Cloud Credentials for the VIM account
7415
7416 :param: vim_account_id: VIM Account ID
7417
7418 :return: (cloud_name, cloud_credential)
7419 """
bravof922c4172020-11-24 21:21:43 -03007420 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007421 return config.get("vca_cloud"), config.get("vca_cloud_credential")
7422
7423 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
7424 """
7425 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
7426
7427 :param: vim_account_id: VIM Account ID
7428
7429 :return: (cloud_name, cloud_credential)
7430 """
bravof922c4172020-11-24 21:21:43 -03007431 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01007432 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")
elumalai80bcf1c2022-04-28 18:05:01 +05307433
7434 async def migrate(self, nsr_id, nslcmop_id):
7435 """
7436 Migrate VNFs and VDUs instances in a NS
7437
7438 :param: nsr_id: NS Instance ID
7439 :param: nslcmop_id: nslcmop ID of migrate
7440
7441 """
7442 # Try to lock HA task here
7443 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7444 if not task_is_locked_by_me:
7445 return
7446 logging_text = "Task ns={} migrate ".format(nsr_id)
7447 self.logger.debug(logging_text + "Enter")
7448 # get all needed from database
7449 db_nslcmop = None
7450 db_nslcmop_update = {}
7451 nslcmop_operation_state = None
7452 db_nsr_update = {}
7453 target = {}
7454 exc = None
7455 # in case of error, indicates what part of scale was failed to put nsr at error status
7456 start_deploy = time()
7457
7458 try:
7459 # wait for any previous tasks in process
7460 step = "Waiting for previous operations to terminate"
aticig349aa462022-05-19 12:29:35 +03007461 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
elumalai80bcf1c2022-04-28 18:05:01 +05307462
7463 self._write_ns_status(
7464 nsr_id=nsr_id,
7465 ns_state=None,
7466 current_operation="MIGRATING",
aticig349aa462022-05-19 12:29:35 +03007467 current_operation_id=nslcmop_id,
elumalai80bcf1c2022-04-28 18:05:01 +05307468 )
7469 step = "Getting nslcmop from database"
aticig349aa462022-05-19 12:29:35 +03007470 self.logger.debug(
7471 step + " after having waited for previous tasks to be completed"
7472 )
elumalai80bcf1c2022-04-28 18:05:01 +05307473 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7474 migrate_params = db_nslcmop.get("operationParams")
7475
7476 target = {}
7477 target.update(migrate_params)
7478 desc = await self.RO.migrate(nsr_id, target)
7479 self.logger.debug("RO return > {}".format(desc))
7480 action_id = desc["action_id"]
7481 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007482 nsr_id,
7483 action_id,
7484 nslcmop_id,
7485 start_deploy,
7486 self.timeout_migrate,
7487 operation="migrate",
elumalai80bcf1c2022-04-28 18:05:01 +05307488 )
7489 except (ROclient.ROClientException, DbException, LcmException) as e:
7490 self.logger.error("Exit Exception {}".format(e))
7491 exc = e
7492 except asyncio.CancelledError:
7493 self.logger.error("Cancelled Exception while '{}'".format(step))
7494 exc = "Operation was cancelled"
7495 except Exception as e:
7496 exc = traceback.format_exc()
aticig349aa462022-05-19 12:29:35 +03007497 self.logger.critical(
7498 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
7499 )
elumalai80bcf1c2022-04-28 18:05:01 +05307500 finally:
7501 self._write_ns_status(
7502 nsr_id=nsr_id,
7503 ns_state=None,
7504 current_operation="IDLE",
7505 current_operation_id=None,
7506 )
7507 if exc:
aticig349aa462022-05-19 12:29:35 +03007508 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
elumalai80bcf1c2022-04-28 18:05:01 +05307509 nslcmop_operation_state = "FAILED"
7510 else:
7511 nslcmop_operation_state = "COMPLETED"
7512 db_nslcmop_update["detailed-status"] = "Done"
7513 db_nsr_update["detailed-status"] = "Done"
7514
7515 self._write_op_status(
7516 op_id=nslcmop_id,
7517 stage="",
7518 error_message="",
7519 operation_state=nslcmop_operation_state,
7520 other_update=db_nslcmop_update,
7521 )
7522 if nslcmop_operation_state:
7523 try:
7524 msg = {
7525 "nsr_id": nsr_id,
7526 "nslcmop_id": nslcmop_id,
7527 "operationState": nslcmop_operation_state,
7528 }
7529 await self.msg.aiowrite("ns", "migrated", msg, loop=self.loop)
7530 except Exception as e:
7531 self.logger.error(
7532 logging_text + "kafka_write notification Exception {}".format(e)
7533 )
7534 self.logger.debug(logging_text + "Exit")
7535 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007536
garciadeblas07f4e4c2022-06-09 09:42:58 +02007537 async def heal(self, nsr_id, nslcmop_id):
7538 """
7539 Heal NS
7540
7541 :param nsr_id: ns instance to heal
7542 :param nslcmop_id: operation to run
7543 :return:
7544 """
7545
7546 # Try to lock HA task here
7547 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
7548 if not task_is_locked_by_me:
7549 return
7550
7551 logging_text = "Task ns={} heal={} ".format(nsr_id, nslcmop_id)
7552 stage = ["", "", ""]
7553 tasks_dict_info = {}
7554 # ^ stage, step, VIM progress
7555 self.logger.debug(logging_text + "Enter")
7556 # get all needed from database
7557 db_nsr = None
7558 db_nslcmop_update = {}
7559 db_nsr_update = {}
7560 db_vnfrs = {} # vnf's info indexed by _id
7561 exc = None
7562 old_operational_status = ""
7563 old_config_status = ""
7564 nsi_id = None
7565 try:
7566 # wait for any previous tasks in process
7567 step = "Waiting for previous operations to terminate"
7568 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
7569 self._write_ns_status(
7570 nsr_id=nsr_id,
7571 ns_state=None,
7572 current_operation="HEALING",
7573 current_operation_id=nslcmop_id,
7574 )
7575
7576 step = "Getting nslcmop from database"
7577 self.logger.debug(
7578 step + " after having waited for previous tasks to be completed"
7579 )
7580 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
7581
7582 step = "Getting nsr from database"
7583 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
7584 old_operational_status = db_nsr["operational-status"]
7585 old_config_status = db_nsr["config-status"]
7586
7587 db_nsr_update = {
7588 "_admin.deployed.RO.operational-status": "healing",
7589 }
7590 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7591
7592 step = "Sending heal order to VIM"
7593 task_ro = asyncio.ensure_future(
7594 self.heal_RO(
7595 logging_text=logging_text,
7596 nsr_id=nsr_id,
7597 db_nslcmop=db_nslcmop,
7598 stage=stage,
7599 )
7600 )
7601 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "heal_RO", task_ro)
7602 tasks_dict_info[task_ro] = "Healing at VIM"
7603
7604 # VCA tasks
7605 # read from db: nsd
7606 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
7607 self.logger.debug(logging_text + stage[1])
7608 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
7609 self.fs.sync(db_nsr["nsd-id"])
7610 db_nsr["nsd"] = nsd
7611 # read from db: vnfr's of this ns
7612 step = "Getting vnfrs from db"
7613 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
7614 for vnfr in db_vnfrs_list:
7615 db_vnfrs[vnfr["_id"]] = vnfr
7616 self.logger.debug("ns.heal db_vnfrs={}".format(db_vnfrs))
7617
7618 # Check for each target VNF
7619 target_list = db_nslcmop.get("operationParams", {}).get("healVnfData", {})
7620 for target_vnf in target_list:
7621 # Find this VNF in the list from DB
7622 vnfr_id = target_vnf.get("vnfInstanceId", None)
7623 if vnfr_id:
7624 db_vnfr = db_vnfrs[vnfr_id]
7625 vnfd_id = db_vnfr.get("vnfd-id")
7626 vnfd_ref = db_vnfr.get("vnfd-ref")
7627 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
7628 base_folder = vnfd["_admin"]["storage"]
7629 vdu_id = None
7630 vdu_index = 0
7631 vdu_name = None
7632 kdu_name = None
7633 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
7634 member_vnf_index = db_vnfr.get("member-vnf-index-ref")
7635
7636 # Check each target VDU and deploy N2VC
preethika.p28b0bf82022-09-23 07:36:28 +00007637 target_vdu_list = target_vnf.get("additionalParams", {}).get(
7638 "vdu", []
7639 )
garciadeblas50639832022-09-01 13:09:47 +02007640 if not target_vdu_list:
7641 # Codigo nuevo para crear diccionario
7642 target_vdu_list = []
7643 for existing_vdu in db_vnfr.get("vdur"):
7644 vdu_name = existing_vdu.get("vdu-name", None)
7645 vdu_index = existing_vdu.get("count-index", 0)
preethika.p28b0bf82022-09-23 07:36:28 +00007646 vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
7647 "run-day1", False
7648 )
7649 vdu_to_be_healed = {
7650 "vdu-id": vdu_name,
7651 "count-index": vdu_index,
7652 "run-day1": vdu_run_day1,
7653 }
garciadeblas50639832022-09-01 13:09:47 +02007654 target_vdu_list.append(vdu_to_be_healed)
7655 for target_vdu in target_vdu_list:
garciadeblas07f4e4c2022-06-09 09:42:58 +02007656 deploy_params_vdu = target_vdu
7657 # Set run-day1 vnf level value if not vdu level value exists
preethika.p28b0bf82022-09-23 07:36:28 +00007658 if not deploy_params_vdu.get("run-day1") and target_vnf[
7659 "additionalParams"
7660 ].get("run-day1"):
7661 deploy_params_vdu["run-day1"] = target_vnf[
7662 "additionalParams"
7663 ].get("run-day1")
garciadeblas07f4e4c2022-06-09 09:42:58 +02007664 vdu_name = target_vdu.get("vdu-id", None)
7665 # TODO: Get vdu_id from vdud.
7666 vdu_id = vdu_name
7667 # For multi instance VDU count-index is mandatory
7668 # For single session VDU count-indes is 0
preethika.p28b0bf82022-09-23 07:36:28 +00007669 vdu_index = target_vdu.get("count-index", 0)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007670
7671 # n2vc_redesign STEP 3 to 6 Deploy N2VC
7672 stage[1] = "Deploying Execution Environments."
7673 self.logger.debug(logging_text + stage[1])
7674
7675 # VNF Level charm. Normal case when proxy charms.
7676 # If target instance is management machine continue with actions: recreate EE for native charms or reinject juju key for proxy charms.
7677 descriptor_config = get_configuration(vnfd, vnfd_ref)
7678 if descriptor_config:
7679 # Continue if healed machine is management machine
7680 vnf_ip_address = db_vnfr.get("ip-address")
7681 target_instance = None
7682 for instance in db_vnfr.get("vdur", None):
preethika.p28b0bf82022-09-23 07:36:28 +00007683 if (
7684 instance["vdu-name"] == vdu_name
7685 and instance["count-index"] == vdu_index
7686 ):
garciadeblas07f4e4c2022-06-09 09:42:58 +02007687 target_instance = instance
7688 break
7689 if vnf_ip_address == target_instance.get("ip-address"):
7690 self._heal_n2vc(
preethika.p28b0bf82022-09-23 07:36:28 +00007691 logging_text=logging_text
7692 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
7693 member_vnf_index, vdu_name, vdu_index
7694 ),
7695 db_nsr=db_nsr,
7696 db_vnfr=db_vnfr,
7697 nslcmop_id=nslcmop_id,
7698 nsr_id=nsr_id,
7699 nsi_id=nsi_id,
7700 vnfd_id=vnfd_ref,
7701 vdu_id=None,
7702 kdu_name=None,
7703 member_vnf_index=member_vnf_index,
7704 vdu_index=0,
7705 vdu_name=None,
7706 deploy_params=deploy_params_vdu,
7707 descriptor_config=descriptor_config,
7708 base_folder=base_folder,
7709 task_instantiation_info=tasks_dict_info,
7710 stage=stage,
7711 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007712
7713 # VDU Level charm. Normal case with native charms.
7714 descriptor_config = get_configuration(vnfd, vdu_name)
7715 if descriptor_config:
7716 self._heal_n2vc(
7717 logging_text=logging_text
7718 + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
7719 member_vnf_index, vdu_name, vdu_index
7720 ),
7721 db_nsr=db_nsr,
7722 db_vnfr=db_vnfr,
7723 nslcmop_id=nslcmop_id,
7724 nsr_id=nsr_id,
7725 nsi_id=nsi_id,
7726 vnfd_id=vnfd_ref,
7727 vdu_id=vdu_id,
7728 kdu_name=kdu_name,
7729 member_vnf_index=member_vnf_index,
7730 vdu_index=vdu_index,
7731 vdu_name=vdu_name,
7732 deploy_params=deploy_params_vdu,
7733 descriptor_config=descriptor_config,
7734 base_folder=base_folder,
7735 task_instantiation_info=tasks_dict_info,
7736 stage=stage,
7737 )
7738
7739 except (
7740 ROclient.ROClientException,
7741 DbException,
7742 LcmException,
7743 NgRoException,
7744 ) as e:
7745 self.logger.error(logging_text + "Exit Exception {}".format(e))
7746 exc = e
7747 except asyncio.CancelledError:
7748 self.logger.error(
7749 logging_text + "Cancelled Exception while '{}'".format(step)
7750 )
7751 exc = "Operation was cancelled"
7752 except Exception as e:
7753 exc = traceback.format_exc()
7754 self.logger.critical(
7755 logging_text + "Exit Exception {} {}".format(type(e).__name__, e),
7756 exc_info=True,
7757 )
7758 finally:
7759 if tasks_dict_info:
7760 stage[1] = "Waiting for healing pending tasks."
7761 self.logger.debug(logging_text + stage[1])
7762 exc = await self._wait_for_tasks(
7763 logging_text,
7764 tasks_dict_info,
7765 self.timeout_ns_deploy,
7766 stage,
7767 nslcmop_id,
7768 nsr_id=nsr_id,
7769 )
7770 if exc:
7771 db_nslcmop_update[
7772 "detailed-status"
7773 ] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
7774 nslcmop_operation_state = "FAILED"
7775 if db_nsr:
7776 db_nsr_update["operational-status"] = old_operational_status
7777 db_nsr_update["config-status"] = old_config_status
7778 db_nsr_update[
7779 "detailed-status"
preethika.p28b0bf82022-09-23 07:36:28 +00007780 ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007781 for task, task_name in tasks_dict_info.items():
7782 if not task.done() or task.cancelled() or task.exception():
7783 if task_name.startswith(self.task_name_deploy_vca):
7784 # A N2VC task is pending
7785 db_nsr_update["config-status"] = "failed"
7786 else:
7787 # RO task is pending
7788 db_nsr_update["operational-status"] = "failed"
7789 else:
7790 error_description_nslcmop = None
7791 nslcmop_operation_state = "COMPLETED"
7792 db_nslcmop_update["detailed-status"] = "Done"
7793 db_nsr_update["detailed-status"] = "Done"
7794 db_nsr_update["operational-status"] = "running"
7795 db_nsr_update["config-status"] = "configured"
7796
7797 self._write_op_status(
7798 op_id=nslcmop_id,
7799 stage="",
7800 error_message=error_description_nslcmop,
7801 operation_state=nslcmop_operation_state,
7802 other_update=db_nslcmop_update,
7803 )
7804 if db_nsr:
7805 self._write_ns_status(
7806 nsr_id=nsr_id,
7807 ns_state=None,
7808 current_operation="IDLE",
7809 current_operation_id=None,
7810 other_update=db_nsr_update,
7811 )
7812
7813 if nslcmop_operation_state:
7814 try:
7815 msg = {
7816 "nsr_id": nsr_id,
7817 "nslcmop_id": nslcmop_id,
7818 "operationState": nslcmop_operation_state,
7819 }
7820 await self.msg.aiowrite("ns", "healed", msg, loop=self.loop)
7821 except Exception as e:
7822 self.logger.error(
7823 logging_text + "kafka_write notification Exception {}".format(e)
7824 )
7825 self.logger.debug(logging_text + "Exit")
7826 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_heal")
7827
7828 async def heal_RO(
7829 self,
7830 logging_text,
7831 nsr_id,
7832 db_nslcmop,
7833 stage,
7834 ):
7835 """
7836 Heal at RO
7837 :param logging_text: preffix text to use at logging
7838 :param nsr_id: nsr identity
7839 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
7840 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
7841 :return: None or exception
7842 """
preethika.p28b0bf82022-09-23 07:36:28 +00007843
garciadeblas07f4e4c2022-06-09 09:42:58 +02007844 def get_vim_account(vim_account_id):
7845 nonlocal db_vims
7846 if vim_account_id in db_vims:
7847 return db_vims[vim_account_id]
7848 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
7849 db_vims[vim_account_id] = db_vim
7850 return db_vim
7851
7852 try:
7853 start_heal = time()
7854 ns_params = db_nslcmop.get("operationParams")
7855 if ns_params and ns_params.get("timeout_ns_heal"):
7856 timeout_ns_heal = ns_params["timeout_ns_heal"]
7857 else:
preethika.p28b0bf82022-09-23 07:36:28 +00007858 timeout_ns_heal = self.timeout.get("ns_heal", self.timeout_ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02007859
7860 db_vims = {}
7861
7862 nslcmop_id = db_nslcmop["_id"]
7863 target = {
7864 "action_id": nslcmop_id,
7865 }
preethika.p28b0bf82022-09-23 07:36:28 +00007866 self.logger.warning(
7867 "db_nslcmop={} and timeout_ns_heal={}".format(
7868 db_nslcmop, timeout_ns_heal
7869 )
7870 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02007871 target.update(db_nslcmop.get("operationParams", {}))
7872
7873 self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
7874 desc = await self.RO.recreate(nsr_id, target)
7875 self.logger.debug("RO return > {}".format(desc))
7876 action_id = desc["action_id"]
7877 # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
7878 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00007879 nsr_id,
7880 action_id,
7881 nslcmop_id,
7882 start_heal,
7883 timeout_ns_heal,
7884 stage,
7885 operation="healing",
garciadeblas07f4e4c2022-06-09 09:42:58 +02007886 )
7887
7888 # Updating NSR
7889 db_nsr_update = {
7890 "_admin.deployed.RO.operational-status": "running",
7891 "detailed-status": " ".join(stage),
7892 }
7893 self.update_db_2("nsrs", nsr_id, db_nsr_update)
7894 self._write_op_status(nslcmop_id, stage)
7895 self.logger.debug(
7896 logging_text + "ns healed at RO. RO_id={}".format(action_id)
7897 )
7898
7899 except Exception as e:
7900 stage[2] = "ERROR healing at VIM"
preethika.p28b0bf82022-09-23 07:36:28 +00007901 # self.set_vnfr_at_error(db_vnfrs, str(e))
garciadeblas07f4e4c2022-06-09 09:42:58 +02007902 self.logger.error(
7903 "Error healing at VIM {}".format(e),
7904 exc_info=not isinstance(
7905 e,
7906 (
7907 ROclient.ROClientException,
7908 LcmException,
7909 DbException,
7910 NgRoException,
7911 ),
7912 ),
7913 )
7914 raise
7915
7916 def _heal_n2vc(
7917 self,
7918 logging_text,
7919 db_nsr,
7920 db_vnfr,
7921 nslcmop_id,
7922 nsr_id,
7923 nsi_id,
7924 vnfd_id,
7925 vdu_id,
7926 kdu_name,
7927 member_vnf_index,
7928 vdu_index,
7929 vdu_name,
7930 deploy_params,
7931 descriptor_config,
7932 base_folder,
7933 task_instantiation_info,
7934 stage,
7935 ):
7936 # launch instantiate_N2VC in a asyncio task and register task object
7937 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
7938 # if not found, create one entry and update database
7939 # fill db_nsr._admin.deployed.VCA.<index>
7940
7941 self.logger.debug(
7942 logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id)
7943 )
aticig9bc63ac2022-07-27 09:32:06 +03007944
7945 charm_name = ""
7946 get_charm_name = False
garciadeblas07f4e4c2022-06-09 09:42:58 +02007947 if "execution-environment-list" in descriptor_config:
7948 ee_list = descriptor_config.get("execution-environment-list", [])
7949 elif "juju" in descriptor_config:
7950 ee_list = [descriptor_config] # ns charms
aticig9bc63ac2022-07-27 09:32:06 +03007951 if "execution-environment-list" not in descriptor_config:
7952 # charm name is only required for ns charms
7953 get_charm_name = True
garciadeblas07f4e4c2022-06-09 09:42:58 +02007954 else: # other types as script are not supported
7955 ee_list = []
7956
7957 for ee_item in ee_list:
7958 self.logger.debug(
7959 logging_text
7960 + "_deploy_n2vc ee_item juju={}, helm={}".format(
7961 ee_item.get("juju"), ee_item.get("helm-chart")
7962 )
7963 )
7964 ee_descriptor_id = ee_item.get("id")
7965 if ee_item.get("juju"):
7966 vca_name = ee_item["juju"].get("charm")
aticig9bc63ac2022-07-27 09:32:06 +03007967 if get_charm_name:
7968 charm_name = self.find_charm_name(db_nsr, str(vca_name))
garciadeblas07f4e4c2022-06-09 09:42:58 +02007969 vca_type = (
7970 "lxc_proxy_charm"
7971 if ee_item["juju"].get("charm") is not None
7972 else "native_charm"
7973 )
7974 if ee_item["juju"].get("cloud") == "k8s":
7975 vca_type = "k8s_proxy_charm"
7976 elif ee_item["juju"].get("proxy") is False:
7977 vca_type = "native_charm"
7978 elif ee_item.get("helm-chart"):
7979 vca_name = ee_item["helm-chart"]
7980 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
7981 vca_type = "helm"
7982 else:
7983 vca_type = "helm-v3"
7984 else:
7985 self.logger.debug(
7986 logging_text + "skipping non juju neither charm configuration"
7987 )
7988 continue
7989
7990 vca_index = -1
7991 for vca_index, vca_deployed in enumerate(
7992 db_nsr["_admin"]["deployed"]["VCA"]
7993 ):
7994 if not vca_deployed:
7995 continue
7996 if (
7997 vca_deployed.get("member-vnf-index") == member_vnf_index
7998 and vca_deployed.get("vdu_id") == vdu_id
7999 and vca_deployed.get("kdu_name") == kdu_name
8000 and vca_deployed.get("vdu_count_index", 0) == vdu_index
8001 and vca_deployed.get("ee_descriptor_id") == ee_descriptor_id
8002 ):
8003 break
8004 else:
8005 # not found, create one.
8006 target = (
8007 "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
8008 )
8009 if vdu_id:
8010 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
8011 elif kdu_name:
8012 target += "/kdu/{}".format(kdu_name)
8013 vca_deployed = {
8014 "target_element": target,
8015 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
8016 "member-vnf-index": member_vnf_index,
8017 "vdu_id": vdu_id,
8018 "kdu_name": kdu_name,
8019 "vdu_count_index": vdu_index,
8020 "operational-status": "init", # TODO revise
8021 "detailed-status": "", # TODO revise
8022 "step": "initial-deploy", # TODO revise
8023 "vnfd_id": vnfd_id,
8024 "vdu_name": vdu_name,
8025 "type": vca_type,
8026 "ee_descriptor_id": ee_descriptor_id,
aticig9bc63ac2022-07-27 09:32:06 +03008027 "charm_name": charm_name,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008028 }
8029 vca_index += 1
8030
8031 # create VCA and configurationStatus in db
8032 db_dict = {
8033 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
8034 "configurationStatus.{}".format(vca_index): dict(),
8035 }
8036 self.update_db_2("nsrs", nsr_id, db_dict)
8037
8038 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
8039
8040 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
8041 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
8042 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
8043
8044 # Launch task
8045 task_n2vc = asyncio.ensure_future(
8046 self.heal_N2VC(
8047 logging_text=logging_text,
8048 vca_index=vca_index,
8049 nsi_id=nsi_id,
8050 db_nsr=db_nsr,
8051 db_vnfr=db_vnfr,
8052 vdu_id=vdu_id,
8053 kdu_name=kdu_name,
8054 vdu_index=vdu_index,
8055 deploy_params=deploy_params,
8056 config_descriptor=descriptor_config,
8057 base_folder=base_folder,
8058 nslcmop_id=nslcmop_id,
8059 stage=stage,
8060 vca_type=vca_type,
8061 vca_name=vca_name,
8062 ee_config_descriptor=ee_item,
8063 )
8064 )
8065 self.lcm_tasks.register(
8066 "ns",
8067 nsr_id,
8068 nslcmop_id,
8069 "instantiate_N2VC-{}".format(vca_index),
8070 task_n2vc,
8071 )
8072 task_instantiation_info[
8073 task_n2vc
8074 ] = self.task_name_deploy_vca + " {}.{}".format(
8075 member_vnf_index or "", vdu_id or ""
8076 )
8077
8078 async def heal_N2VC(
8079 self,
8080 logging_text,
8081 vca_index,
8082 nsi_id,
8083 db_nsr,
8084 db_vnfr,
8085 vdu_id,
8086 kdu_name,
8087 vdu_index,
8088 config_descriptor,
8089 deploy_params,
8090 base_folder,
8091 nslcmop_id,
8092 stage,
8093 vca_type,
8094 vca_name,
8095 ee_config_descriptor,
8096 ):
8097 nsr_id = db_nsr["_id"]
8098 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
8099 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
8100 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
8101 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
8102 db_dict = {
8103 "collection": "nsrs",
8104 "filter": {"_id": nsr_id},
8105 "path": db_update_entry,
8106 }
8107 step = ""
8108 try:
8109
8110 element_type = "NS"
8111 element_under_configuration = nsr_id
8112
8113 vnfr_id = None
8114 if db_vnfr:
8115 vnfr_id = db_vnfr["_id"]
8116 osm_config["osm"]["vnf_id"] = vnfr_id
8117
8118 namespace = "{nsi}.{ns}".format(nsi=nsi_id if nsi_id else "", ns=nsr_id)
8119
8120 if vca_type == "native_charm":
8121 index_number = 0
8122 else:
8123 index_number = vdu_index or 0
8124
8125 if vnfr_id:
8126 element_type = "VNF"
8127 element_under_configuration = vnfr_id
8128 namespace += ".{}-{}".format(vnfr_id, index_number)
8129 if vdu_id:
8130 namespace += ".{}-{}".format(vdu_id, index_number)
8131 element_type = "VDU"
8132 element_under_configuration = "{}-{}".format(vdu_id, index_number)
8133 osm_config["osm"]["vdu_id"] = vdu_id
8134 elif kdu_name:
8135 namespace += ".{}".format(kdu_name)
8136 element_type = "KDU"
8137 element_under_configuration = kdu_name
8138 osm_config["osm"]["kdu_name"] = kdu_name
8139
8140 # Get artifact path
8141 if base_folder["pkg-dir"]:
8142 artifact_path = "{}/{}/{}/{}".format(
8143 base_folder["folder"],
8144 base_folder["pkg-dir"],
8145 "charms"
8146 if vca_type
8147 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8148 else "helm-charts",
8149 vca_name,
8150 )
8151 else:
8152 artifact_path = "{}/Scripts/{}/{}/".format(
8153 base_folder["folder"],
8154 "charms"
8155 if vca_type
8156 in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
8157 else "helm-charts",
8158 vca_name,
8159 )
8160
8161 self.logger.debug("Artifact path > {}".format(artifact_path))
8162
8163 # get initial_config_primitive_list that applies to this element
8164 initial_config_primitive_list = config_descriptor.get(
8165 "initial-config-primitive"
8166 )
8167
8168 self.logger.debug(
8169 "Initial config primitive list > {}".format(
8170 initial_config_primitive_list
8171 )
8172 )
8173
8174 # add config if not present for NS charm
8175 ee_descriptor_id = ee_config_descriptor.get("id")
8176 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
8177 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(
8178 initial_config_primitive_list, vca_deployed, ee_descriptor_id
8179 )
8180
8181 self.logger.debug(
8182 "Initial config primitive list #2 > {}".format(
8183 initial_config_primitive_list
8184 )
8185 )
8186 # n2vc_redesign STEP 3.1
8187 # find old ee_id if exists
8188 ee_id = vca_deployed.get("ee_id")
8189
8190 vca_id = self.get_vca_id(db_vnfr, db_nsr)
8191 # create or register execution environment in VCA. Only for native charms when healing
8192 if vca_type == "native_charm":
8193 step = "Waiting to VM being up and getting IP address"
8194 self.logger.debug(logging_text + step)
8195 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8196 logging_text,
8197 nsr_id,
8198 vnfr_id,
8199 vdu_id,
8200 vdu_index,
8201 user=None,
8202 pub_key=None,
8203 )
8204 credentials = {"hostname": rw_mgmt_ip}
8205 # get username
8206 username = deep_get(
8207 config_descriptor, ("config-access", "ssh-access", "default-user")
8208 )
8209 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
8210 # merged. Meanwhile let's get username from initial-config-primitive
8211 if not username and initial_config_primitive_list:
8212 for config_primitive in initial_config_primitive_list:
8213 for param in config_primitive.get("parameter", ()):
8214 if param["name"] == "ssh-username":
8215 username = param["value"]
8216 break
8217 if not username:
8218 raise LcmException(
8219 "Cannot determine the username neither with 'initial-config-primitive' nor with "
8220 "'config-access.ssh-access.default-user'"
8221 )
8222 credentials["username"] = username
8223
8224 # n2vc_redesign STEP 3.2
8225 # TODO: Before healing at RO it is needed to destroy native charm units to be deleted.
8226 self._write_configuration_status(
8227 nsr_id=nsr_id,
8228 vca_index=vca_index,
8229 status="REGISTERING",
8230 element_under_configuration=element_under_configuration,
8231 element_type=element_type,
8232 )
8233
8234 step = "register execution environment {}".format(credentials)
8235 self.logger.debug(logging_text + step)
8236 ee_id = await self.vca_map[vca_type].register_execution_environment(
8237 credentials=credentials,
8238 namespace=namespace,
8239 db_dict=db_dict,
8240 vca_id=vca_id,
8241 )
8242
8243 # update ee_id en db
8244 db_dict_ee_id = {
8245 "_admin.deployed.VCA.{}.ee_id".format(vca_index): ee_id,
8246 }
8247 self.update_db_2("nsrs", nsr_id, db_dict_ee_id)
8248
8249 # for compatibility with MON/POL modules, the need model and application name at database
8250 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
8251 # Not sure if this need to be done when healing
8252 """
8253 ee_id_parts = ee_id.split(".")
8254 db_nsr_update = {db_update_entry + "ee_id": ee_id}
8255 if len(ee_id_parts) >= 2:
8256 model_name = ee_id_parts[0]
8257 application_name = ee_id_parts[1]
8258 db_nsr_update[db_update_entry + "model"] = model_name
8259 db_nsr_update[db_update_entry + "application"] = application_name
8260 """
8261
8262 # n2vc_redesign STEP 3.3
8263 # Install configuration software. Only for native charms.
8264 step = "Install configuration Software"
8265
8266 self._write_configuration_status(
8267 nsr_id=nsr_id,
8268 vca_index=vca_index,
8269 status="INSTALLING SW",
8270 element_under_configuration=element_under_configuration,
8271 element_type=element_type,
preethika.p28b0bf82022-09-23 07:36:28 +00008272 # other_update=db_nsr_update,
garciadeblas07f4e4c2022-06-09 09:42:58 +02008273 other_update=None,
8274 )
8275
8276 # TODO check if already done
8277 self.logger.debug(logging_text + step)
8278 config = None
8279 if vca_type == "native_charm":
8280 config_primitive = next(
8281 (p for p in initial_config_primitive_list if p["name"] == "config"),
8282 None,
8283 )
8284 if config_primitive:
8285 config = self._map_primitive_params(
8286 config_primitive, {}, deploy_params
8287 )
8288 await self.vca_map[vca_type].install_configuration_sw(
8289 ee_id=ee_id,
8290 artifact_path=artifact_path,
8291 db_dict=db_dict,
8292 config=config,
8293 num_units=1,
8294 vca_id=vca_id,
8295 vca_type=vca_type,
8296 )
8297
8298 # write in db flag of configuration_sw already installed
8299 self.update_db_2(
8300 "nsrs", nsr_id, {db_update_entry + "config_sw_installed": True}
8301 )
8302
8303 # Not sure if this need to be done when healing
8304 """
8305 # add relations for this VCA (wait for other peers related with this VCA)
8306 await self._add_vca_relations(
8307 logging_text=logging_text,
8308 nsr_id=nsr_id,
8309 vca_type=vca_type,
8310 vca_index=vca_index,
8311 )
8312 """
8313
8314 # if SSH access is required, then get execution environment SSH public
8315 # if native charm we have waited already to VM be UP
8316 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
8317 pub_key = None
8318 user = None
8319 # self.logger.debug("get ssh key block")
8320 if deep_get(
8321 config_descriptor, ("config-access", "ssh-access", "required")
8322 ):
8323 # self.logger.debug("ssh key needed")
8324 # Needed to inject a ssh key
8325 user = deep_get(
8326 config_descriptor,
8327 ("config-access", "ssh-access", "default-user"),
8328 )
8329 step = "Install configuration Software, getting public ssh key"
8330 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
8331 ee_id=ee_id, db_dict=db_dict, vca_id=vca_id
8332 )
8333
8334 step = "Insert public key into VM user={} ssh_key={}".format(
8335 user, pub_key
8336 )
8337 else:
8338 # self.logger.debug("no need to get ssh key")
8339 step = "Waiting to VM being up and getting IP address"
8340 self.logger.debug(logging_text + step)
8341
8342 # n2vc_redesign STEP 5.1
8343 # wait for RO (ip-address) Insert pub_key into VM
8344 # IMPORTANT: We need do wait for RO to complete healing operation.
preethika.p28b0bf82022-09-23 07:36:28 +00008345 await self._wait_heal_ro(nsr_id, self.timeout_ns_heal)
garciadeblas07f4e4c2022-06-09 09:42:58 +02008346 if vnfr_id:
8347 if kdu_name:
8348 rw_mgmt_ip = await self.wait_kdu_up(
8349 logging_text, nsr_id, vnfr_id, kdu_name
8350 )
8351 else:
8352 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
8353 logging_text,
8354 nsr_id,
8355 vnfr_id,
8356 vdu_id,
8357 vdu_index,
8358 user=user,
8359 pub_key=pub_key,
8360 )
8361 else:
8362 rw_mgmt_ip = None # This is for a NS configuration
8363
8364 self.logger.debug(logging_text + " VM_ip_address={}".format(rw_mgmt_ip))
8365
8366 # store rw_mgmt_ip in deploy params for later replacement
8367 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
8368
8369 # Day1 operations.
8370 # get run-day1 operation parameter
preethika.p28b0bf82022-09-23 07:36:28 +00008371 runDay1 = deploy_params.get("run-day1", False)
8372 self.logger.debug(
8373 "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
8374 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008375 if runDay1:
8376 # n2vc_redesign STEP 6 Execute initial config primitive
8377 step = "execute initial config primitive"
8378
8379 # wait for dependent primitives execution (NS -> VNF -> VDU)
8380 if initial_config_primitive_list:
preethika.p28b0bf82022-09-23 07:36:28 +00008381 await self._wait_dependent_n2vc(
8382 nsr_id, vca_deployed_list, vca_index
8383 )
garciadeblas07f4e4c2022-06-09 09:42:58 +02008384
8385 # stage, in function of element type: vdu, kdu, vnf or ns
8386 my_vca = vca_deployed_list[vca_index]
8387 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
8388 # VDU or KDU
8389 stage[0] = "Stage 3/5: running Day-1 primitives for VDU."
8390 elif my_vca.get("member-vnf-index"):
8391 # VNF
8392 stage[0] = "Stage 4/5: running Day-1 primitives for VNF."
8393 else:
8394 # NS
8395 stage[0] = "Stage 5/5: running Day-1 primitives for NS."
8396
8397 self._write_configuration_status(
8398 nsr_id=nsr_id, vca_index=vca_index, status="EXECUTING PRIMITIVE"
8399 )
8400
8401 self._write_op_status(op_id=nslcmop_id, stage=stage)
8402
8403 check_if_terminated_needed = True
8404 for initial_config_primitive in initial_config_primitive_list:
8405 # adding information on the vca_deployed if it is a NS execution environment
8406 if not vca_deployed["member-vnf-index"]:
8407 deploy_params["ns_config_info"] = json.dumps(
8408 self._get_ns_config_info(nsr_id)
8409 )
8410 # TODO check if already done
8411 primitive_params_ = self._map_primitive_params(
8412 initial_config_primitive, {}, deploy_params
8413 )
8414
8415 step = "execute primitive '{}' params '{}'".format(
8416 initial_config_primitive["name"], primitive_params_
8417 )
8418 self.logger.debug(logging_text + step)
8419 await self.vca_map[vca_type].exec_primitive(
8420 ee_id=ee_id,
8421 primitive_name=initial_config_primitive["name"],
8422 params_dict=primitive_params_,
8423 db_dict=db_dict,
8424 vca_id=vca_id,
8425 vca_type=vca_type,
8426 )
8427 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
8428 if check_if_terminated_needed:
8429 if config_descriptor.get("terminate-config-primitive"):
8430 self.update_db_2(
preethika.p28b0bf82022-09-23 07:36:28 +00008431 "nsrs",
8432 nsr_id,
8433 {db_update_entry + "needed_terminate": True},
garciadeblas07f4e4c2022-06-09 09:42:58 +02008434 )
8435 check_if_terminated_needed = False
8436
8437 # TODO register in database that primitive is done
8438
8439 # STEP 7 Configure metrics
8440 # Not sure if this need to be done when healing
8441 """
8442 if vca_type == "helm" or vca_type == "helm-v3":
8443 prometheus_jobs = await self.extract_prometheus_scrape_jobs(
8444 ee_id=ee_id,
8445 artifact_path=artifact_path,
8446 ee_config_descriptor=ee_config_descriptor,
8447 vnfr_id=vnfr_id,
8448 nsr_id=nsr_id,
8449 target_ip=rw_mgmt_ip,
8450 )
8451 if prometheus_jobs:
8452 self.update_db_2(
8453 "nsrs",
8454 nsr_id,
8455 {db_update_entry + "prometheus_jobs": prometheus_jobs},
8456 )
8457
8458 for job in prometheus_jobs:
8459 self.db.set_one(
8460 "prometheus_jobs",
8461 {"job_name": job["job_name"]},
8462 job,
8463 upsert=True,
8464 fail_on_empty=False,
8465 )
8466
8467 """
8468 step = "instantiated at VCA"
8469 self.logger.debug(logging_text + step)
8470
8471 self._write_configuration_status(
8472 nsr_id=nsr_id, vca_index=vca_index, status="READY"
8473 )
8474
8475 except Exception as e: # TODO not use Exception but N2VC exception
8476 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
8477 if not isinstance(
8478 e, (DbException, N2VCException, LcmException, asyncio.CancelledError)
8479 ):
8480 self.logger.error(
8481 "Exception while {} : {}".format(step, e), exc_info=True
8482 )
8483 self._write_configuration_status(
8484 nsr_id=nsr_id, vca_index=vca_index, status="BROKEN"
8485 )
8486 raise LcmException("{} {}".format(step, e)) from e
8487
8488 async def _wait_heal_ro(
8489 self,
8490 nsr_id,
8491 timeout=600,
8492 ):
8493 start_time = time()
8494 while time() <= start_time + timeout:
8495 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
preethika.p28b0bf82022-09-23 07:36:28 +00008496 operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
8497 "operational-status"
8498 ]
garciadeblas07f4e4c2022-06-09 09:42:58 +02008499 self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
8500 if operational_status_ro != "healing":
8501 break
8502 await asyncio.sleep(15, loop=self.loop)
8503 else: # timeout_ns_deploy
8504 raise NgRoException("Timeout waiting ns to deploy")
govindarajul4ff4b512022-05-02 20:02:41 +05308505
8506 async def vertical_scale(self, nsr_id, nslcmop_id):
8507 """
8508 Vertical Scale the VDUs in a NS
8509
8510 :param: nsr_id: NS Instance ID
8511 :param: nslcmop_id: nslcmop ID of migrate
8512
8513 """
8514 # Try to lock HA task here
8515 task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
8516 if not task_is_locked_by_me:
8517 return
8518 logging_text = "Task ns={} vertical scale ".format(nsr_id)
8519 self.logger.debug(logging_text + "Enter")
8520 # get all needed from database
8521 db_nslcmop = None
8522 db_nslcmop_update = {}
8523 nslcmop_operation_state = None
8524 db_nsr_update = {}
8525 target = {}
8526 exc = None
8527 # in case of error, indicates what part of scale was failed to put nsr at error status
8528 start_deploy = time()
8529
8530 try:
8531 # wait for any previous tasks in process
8532 step = "Waiting for previous operations to terminate"
preethika.p28b0bf82022-09-23 07:36:28 +00008533 await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
govindarajul4ff4b512022-05-02 20:02:41 +05308534
8535 self._write_ns_status(
8536 nsr_id=nsr_id,
8537 ns_state=None,
8538 current_operation="VerticalScale",
preethika.p28b0bf82022-09-23 07:36:28 +00008539 current_operation_id=nslcmop_id,
govindarajul4ff4b512022-05-02 20:02:41 +05308540 )
8541 step = "Getting nslcmop from database"
preethika.p28b0bf82022-09-23 07:36:28 +00008542 self.logger.debug(
8543 step + " after having waited for previous tasks to be completed"
8544 )
govindarajul4ff4b512022-05-02 20:02:41 +05308545 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
8546 operationParams = db_nslcmop.get("operationParams")
8547 target = {}
8548 target.update(operationParams)
8549 desc = await self.RO.vertical_scale(nsr_id, target)
8550 self.logger.debug("RO return > {}".format(desc))
8551 action_id = desc["action_id"]
8552 await self._wait_ng_ro(
preethika.p28b0bf82022-09-23 07:36:28 +00008553 nsr_id,
8554 action_id,
8555 nslcmop_id,
8556 start_deploy,
8557 self.timeout_verticalscale,
8558 operation="verticalscale",
govindarajul4ff4b512022-05-02 20:02:41 +05308559 )
8560 except (ROclient.ROClientException, DbException, LcmException) as e:
8561 self.logger.error("Exit Exception {}".format(e))
8562 exc = e
8563 except asyncio.CancelledError:
8564 self.logger.error("Cancelled Exception while '{}'".format(step))
8565 exc = "Operation was cancelled"
8566 except Exception as e:
8567 exc = traceback.format_exc()
preethika.p28b0bf82022-09-23 07:36:28 +00008568 self.logger.critical(
8569 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
8570 )
govindarajul4ff4b512022-05-02 20:02:41 +05308571 finally:
8572 self._write_ns_status(
8573 nsr_id=nsr_id,
8574 ns_state=None,
8575 current_operation="IDLE",
8576 current_operation_id=None,
8577 )
8578 if exc:
preethika.p28b0bf82022-09-23 07:36:28 +00008579 db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
govindarajul4ff4b512022-05-02 20:02:41 +05308580 nslcmop_operation_state = "FAILED"
8581 else:
8582 nslcmop_operation_state = "COMPLETED"
8583 db_nslcmop_update["detailed-status"] = "Done"
8584 db_nsr_update["detailed-status"] = "Done"
8585
8586 self._write_op_status(
8587 op_id=nslcmop_id,
8588 stage="",
8589 error_message="",
8590 operation_state=nslcmop_operation_state,
8591 other_update=db_nslcmop_update,
8592 )
8593 if nslcmop_operation_state:
8594 try:
8595 msg = {
8596 "nsr_id": nsr_id,
8597 "nslcmop_id": nslcmop_id,
8598 "operationState": nslcmop_operation_state,
8599 }
8600 await self.msg.aiowrite("ns", "verticalscaled", msg, loop=self.loop)
8601 except Exception as e:
8602 self.logger.error(
8603 logging_text + "kafka_write notification Exception {}".format(e)
8604 )
8605 self.logger.debug(logging_text + "Exit")
8606 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")