blob: 6fd9e5a68533f44550f8904270a1285032f38aa4 [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
20import yaml
21import logging
22import logging.handlers
tierno59d22d22018-09-25 18:10:19 +020023import traceback
David Garciad4816682019-12-09 14:57:43 +010024import json
tierno72ef84f2020-10-06 08:22:07 +000025from jinja2 import Environment, TemplateError, TemplateNotFound, StrictUndefined, UndefinedError
tierno59d22d22018-09-25 18:10:19 +020026
tierno77677d92019-08-22 13:46:35 +000027from osm_lcm import ROclient
tierno69f0d382020-05-07 13:08:09 +000028from osm_lcm.ng_ro import NgRoClient, NgRoException
tierno744303e2020-01-13 16:46:31 +000029from osm_lcm.lcm_utils import LcmException, LcmExceptionNoMgmtIP, LcmBase, deep_get, get_iterable, populate_dict
bravof922c4172020-11-24 21:21:43 -030030from osm_lcm.data_utils.nsd import get_vnf_profiles
bravofe5a31bc2021-02-17 19:09:12 -030031from osm_lcm.data_utils.vnfd import get_vdu_list, get_vdu_profile, \
bravof922c4172020-11-24 21:21:43 -030032 get_ee_sorted_initial_config_primitive_list, get_ee_sorted_terminate_config_primitive_list, \
bravofe5a31bc2021-02-17 19:09:12 -030033 get_kdu_list, get_virtual_link_profiles, get_vdu, get_configuration, \
bravof9a256db2021-02-22 18:02:07 -030034 get_vdu_index, get_scaling_aspect, get_number_of_instances, get_juju_ee_ref
bravof922c4172020-11-24 21:21:43 -030035from osm_lcm.data_utils.list_utils import find_in_list
aktas13251562021-02-12 22:19:10 +030036from osm_lcm.data_utils.vnfr import get_osm_params, get_vdur_index
bravof922c4172020-11-24 21:21:43 -030037from osm_lcm.data_utils.dict_utils import parse_yaml_strings
38from osm_lcm.data_utils.database.vim_account import VimAccountDB
calvinosanch9f9c6f22019-11-04 13:37:39 +010039from n2vc.k8s_helm_conn import K8sHelmConnector
lloretgalleg18ebc3a2020-10-22 09:54:51 +000040from n2vc.k8s_helm3_conn import K8sHelm3Connector
Adam Israelbaacc302019-12-01 12:41:39 -050041from n2vc.k8s_juju_conn import K8sJujuConnector
tierno59d22d22018-09-25 18:10:19 +020042
tierno27246d82018-09-27 15:59:09 +020043from osm_common.dbbase import DbException
tierno59d22d22018-09-25 18:10:19 +020044from osm_common.fsbase import FsException
quilesj7e13aeb2019-10-08 13:34:55 +020045
bravof922c4172020-11-24 21:21:43 -030046from osm_lcm.data_utils.database.database import Database
47from osm_lcm.data_utils.filesystem.filesystem import Filesystem
48
quilesj7e13aeb2019-10-08 13:34:55 +020049from n2vc.n2vc_juju_conn import N2VCJujuConnector
tiernof59ad6c2020-04-08 12:50:52 +000050from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
tierno59d22d22018-09-25 18:10:19 +020051
tierno588547c2020-07-01 15:30:20 +000052from osm_lcm.lcm_helm_conn import LCMHelmConn
53
tierno27246d82018-09-27 15:59:09 +020054from copy import copy, deepcopy
tierno59d22d22018-09-25 18:10:19 +020055from time import time
tierno27246d82018-09-27 15:59:09 +020056from uuid import uuid4
lloretgalleg7c121132020-07-08 07:53:22 +000057
tiernob996d942020-07-03 14:52:28 +000058from random import randint
tierno59d22d22018-09-25 18:10:19 +020059
tierno69f0d382020-05-07 13:08:09 +000060__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
tierno59d22d22018-09-25 18:10:19 +020061
62
63class NsLcm(LcmBase):
tierno63de62e2018-10-31 16:38:52 +010064 timeout_vca_on_error = 5 * 60 # Time for charm from first time at blocked,error status to mark as failed
tierno744303e2020-01-13 16:46:31 +000065 timeout_ns_deploy = 2 * 3600 # default global timeout for deployment a ns
tiernoe876f672020-02-13 14:34:48 +000066 timeout_ns_terminate = 1800 # default global timeout for un deployment a ns
garciadeblasf9b04952019-04-09 18:53:58 +020067 timeout_charm_delete = 10 * 60
David Garciaf6919842020-05-21 16:41:07 +020068 timeout_primitive = 30 * 60 # timeout for primitive execution
69 timeout_progress_primitive = 10 * 60 # timeout for some progress in a primitive execution
tierno59d22d22018-09-25 18:10:19 +020070
kuuseac3a8882019-10-03 10:48:06 +020071 SUBOPERATION_STATUS_NOT_FOUND = -1
72 SUBOPERATION_STATUS_NEW = -2
73 SUBOPERATION_STATUS_SKIP = -3
tiernoa2143262020-03-27 16:20:40 +000074 task_name_deploy_vca = "Deploying VCA"
kuuseac3a8882019-10-03 10:48:06 +020075
bravof922c4172020-11-24 21:21:43 -030076 def __init__(self, msg, lcm_tasks, config, loop, prometheus=None):
tierno59d22d22018-09-25 18:10:19 +020077 """
78 Init, Connect to database, filesystem storage, and messaging
79 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
80 :return: None
81 """
quilesj7e13aeb2019-10-08 13:34:55 +020082 super().__init__(
quilesj7e13aeb2019-10-08 13:34:55 +020083 msg=msg,
quilesj7e13aeb2019-10-08 13:34:55 +020084 logger=logging.getLogger('lcm.ns')
85 )
86
bravof922c4172020-11-24 21:21:43 -030087 self.db = Database().instance.db
88 self.fs = Filesystem().instance.fs
tierno59d22d22018-09-25 18:10:19 +020089 self.loop = loop
90 self.lcm_tasks = lcm_tasks
tierno744303e2020-01-13 16:46:31 +000091 self.timeout = config["timeout"]
92 self.ro_config = config["ro_config"]
tierno69f0d382020-05-07 13:08:09 +000093 self.ng_ro = config["ro_config"].get("ng")
tierno744303e2020-01-13 16:46:31 +000094 self.vca_config = config["VCA"].copy()
tierno59d22d22018-09-25 18:10:19 +020095
quilesj7e13aeb2019-10-08 13:34:55 +020096 # create N2VC connector
David Garciaaae391f2020-11-09 11:12:54 +010097 self.n2vc = N2VCJujuConnector(
tierno59d22d22018-09-25 18:10:19 +020098 log=self.logger,
quilesj7e13aeb2019-10-08 13:34:55 +020099 loop=self.loop,
bravof922c4172020-11-24 21:21:43 -0300100 on_update_db=self._on_update_n2vc_db,
101 fs=self.fs,
102 db=self.db
tierno59d22d22018-09-25 18:10:19 +0200103 )
quilesj7e13aeb2019-10-08 13:34:55 +0200104
tierno588547c2020-07-01 15:30:20 +0000105 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000106 log=self.logger,
107 loop=self.loop,
tierno588547c2020-07-01 15:30:20 +0000108 vca_config=self.vca_config,
109 on_update_db=self._on_update_n2vc_db
110 )
111
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000112 self.k8sclusterhelm2 = K8sHelmConnector(
calvinosanch9f9c6f22019-11-04 13:37:39 +0100113 kubectl_command=self.vca_config.get("kubectlpath"),
114 helm_command=self.vca_config.get("helmpath"),
calvinosanch9f9c6f22019-11-04 13:37:39 +0100115 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100116 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300117 fs=self.fs,
118 db=self.db
calvinosanch9f9c6f22019-11-04 13:37:39 +0100119 )
120
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000121 self.k8sclusterhelm3 = K8sHelm3Connector(
122 kubectl_command=self.vca_config.get("kubectlpath"),
123 helm_command=self.vca_config.get("helm3path"),
124 fs=self.fs,
125 log=self.logger,
126 db=self.db,
127 on_update_db=None,
128 )
129
Adam Israelbaacc302019-12-01 12:41:39 -0500130 self.k8sclusterjuju = K8sJujuConnector(
131 kubectl_command=self.vca_config.get("kubectlpath"),
132 juju_command=self.vca_config.get("jujupath"),
Adam Israelbaacc302019-12-01 12:41:39 -0500133 log=self.logger,
David Garciaba89cbb2020-10-16 13:05:34 +0200134 loop=self.loop,
ksaikiranr656b6dd2021-02-19 10:25:18 +0530135 on_update_db=self._on_update_k8s_db,
bravof922c4172020-11-24 21:21:43 -0300136 fs=self.fs,
137 db=self.db
Adam Israelbaacc302019-12-01 12:41:39 -0500138 )
139
tiernoa2143262020-03-27 16:20:40 +0000140 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000141 "helm-chart": self.k8sclusterhelm2,
142 "helm-chart-v3": self.k8sclusterhelm3,
143 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000144 "juju-bundle": self.k8sclusterjuju,
145 "juju": self.k8sclusterjuju,
146 }
tierno588547c2020-07-01 15:30:20 +0000147
148 self.vca_map = {
149 "lxc_proxy_charm": self.n2vc,
150 "native_charm": self.n2vc,
151 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000152 "helm": self.conn_helm_ee,
153 "helm-v3": self.conn_helm_ee
tierno588547c2020-07-01 15:30:20 +0000154 }
155
tiernob996d942020-07-03 14:52:28 +0000156 self.prometheus = prometheus
157
quilesj7e13aeb2019-10-08 13:34:55 +0200158 # create RO client
bravof922c4172020-11-24 21:21:43 -0300159 self.RO = NgRoClient(self.loop, **self.ro_config)
tierno59d22d22018-09-25 18:10:19 +0200160
tierno2357f4e2020-10-19 16:38:59 +0000161 @staticmethod
162 def increment_ip_mac(ip_mac, vm_index=1):
163 if not isinstance(ip_mac, str):
164 return ip_mac
165 try:
166 # try with ipv4 look for last dot
167 i = ip_mac.rfind(".")
168 if i > 0:
169 i += 1
170 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
171 # try with ipv6 or mac look for last colon. Operate in hex
172 i = ip_mac.rfind(":")
173 if i > 0:
174 i += 1
175 # format in hex, len can be 2 for mac or 4 for ipv6
176 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(ip_mac[:i], int(ip_mac[i:], 16) + vm_index)
177 except Exception:
178 pass
179 return None
180
quilesj3655ae02019-12-12 16:08:35 +0000181 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj7e13aeb2019-10-08 13:34:55 +0200182
quilesj3655ae02019-12-12 16:08:35 +0000183 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
184
185 try:
186 # TODO filter RO descriptor fields...
187
188 # write to database
189 db_dict = dict()
190 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
191 db_dict['deploymentStatus'] = ro_descriptor
192 self.update_db_2("nsrs", nsrs_id, db_dict)
193
194 except Exception as e:
195 self.logger.warn('Cannot write database RO deployment for ns={} -> {}'.format(nsrs_id, e))
196
David Garciac1fe90a2021-03-31 19:12:02 +0200197 async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
quilesj3655ae02019-12-12 16:08:35 +0000198
quilesj69a722c2020-01-09 08:30:17 +0000199 # remove last dot from path (if exists)
200 if path.endswith('.'):
201 path = path[:-1]
202
quilesj3655ae02019-12-12 16:08:35 +0000203 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
204 # .format(table, filter, path, updated_data))
quilesj3655ae02019-12-12 16:08:35 +0000205 try:
206
207 nsr_id = filter.get('_id')
208
209 # read ns record from database
210 nsr = self.db.get_one(table='nsrs', q_filter=filter)
211 current_ns_status = nsr.get('nsState')
212
213 # get vca status for NS
David Garciac1fe90a2021-03-31 19:12:02 +0200214 status_dict = await self.n2vc.get_status(namespace='.' + nsr_id, yaml_format=False, vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000215
216 # vcaStatus
217 db_dict = dict()
218 db_dict['vcaStatus'] = status_dict
David Garciac1fe90a2021-03-31 19:12:02 +0200219 await self.n2vc.update_vca_status(db_dict['vcaStatus'], vca_id=vca_id)
quilesj3655ae02019-12-12 16:08:35 +0000220
221 # update configurationStatus for this VCA
222 try:
223 vca_index = int(path[path.rfind(".")+1:])
224
225 vca_list = deep_get(target_dict=nsr, key_list=('_admin', 'deployed', 'VCA'))
226 vca_status = vca_list[vca_index].get('status')
227
228 configuration_status_list = nsr.get('configurationStatus')
229 config_status = configuration_status_list[vca_index].get('status')
230
231 if config_status == 'BROKEN' and vca_status != 'failed':
232 db_dict['configurationStatus'][vca_index] = 'READY'
233 elif config_status != 'BROKEN' and vca_status == 'failed':
234 db_dict['configurationStatus'][vca_index] = 'BROKEN'
235 except Exception as e:
236 # not update configurationStatus
237 self.logger.debug('Error updating vca_index (ignore): {}'.format(e))
238
239 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
240 # if nsState = 'DEGRADED' check if all is OK
241 is_degraded = False
242 if current_ns_status in ('READY', 'DEGRADED'):
243 error_description = ''
244 # check machines
245 if status_dict.get('machines'):
246 for machine_id in status_dict.get('machines'):
247 machine = status_dict.get('machines').get(machine_id)
248 # check machine agent-status
249 if machine.get('agent-status'):
250 s = machine.get('agent-status').get('status')
251 if s != 'started':
252 is_degraded = True
253 error_description += 'machine {} agent-status={} ; '.format(machine_id, s)
254 # check machine instance status
255 if machine.get('instance-status'):
256 s = machine.get('instance-status').get('status')
257 if s != 'running':
258 is_degraded = True
259 error_description += 'machine {} instance-status={} ; '.format(machine_id, s)
260 # check applications
261 if status_dict.get('applications'):
262 for app_id in status_dict.get('applications'):
263 app = status_dict.get('applications').get(app_id)
264 # check application status
265 if app.get('status'):
266 s = app.get('status').get('status')
267 if s != 'active':
268 is_degraded = True
269 error_description += 'application {} status={} ; '.format(app_id, s)
270
271 if error_description:
272 db_dict['errorDescription'] = error_description
273 if current_ns_status == 'READY' and is_degraded:
274 db_dict['nsState'] = 'DEGRADED'
275 if current_ns_status == 'DEGRADED' and not is_degraded:
276 db_dict['nsState'] = 'READY'
277
278 # write to database
279 self.update_db_2("nsrs", nsr_id, db_dict)
280
tierno51183952020-04-03 15:48:18 +0000281 except (asyncio.CancelledError, asyncio.TimeoutError):
282 raise
quilesj3655ae02019-12-12 16:08:35 +0000283 except Exception as e:
284 self.logger.warn('Error updating NS state for ns={}: {}'.format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200285
David Garciac1fe90a2021-03-31 19:12:02 +0200286 async def _on_update_k8s_db(self, cluster_uuid, kdu_instance, filter=None, vca_id=None):
ksaikiranr656b6dd2021-02-19 10:25:18 +0530287 """
288 Updating vca status in NSR record
289 :param cluster_uuid: UUID of a k8s cluster
290 :param kdu_instance: The unique name of the KDU instance
291 :param filter: To get nsr_id
292 :return: none
293 """
294
295 # self.logger.debug("_on_update_k8s_db(cluster_uuid={}, kdu_instance={}, filter={}"
296 # .format(cluster_uuid, kdu_instance, filter))
297
298 try:
299 nsr_id = filter.get('_id')
300
301 # get vca status for NS
David Garciac1fe90a2021-03-31 19:12:02 +0200302 vca_status = await self.k8sclusterjuju.status_kdu(
303 cluster_uuid,
304 kdu_instance,
305 complete_status=True,
306 yaml_format=False,
307 vca_id=vca_id,
308 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530309 # vcaStatus
310 db_dict = dict()
311 db_dict['vcaStatus'] = {nsr_id: vca_status}
312
David Garciac1fe90a2021-03-31 19:12:02 +0200313 await self.k8sclusterjuju.update_vca_status(
314 db_dict['vcaStatus'],
315 kdu_instance,
316 vca_id=vca_id,
317 )
ksaikiranr656b6dd2021-02-19 10:25:18 +0530318
319 # write to database
320 self.update_db_2("nsrs", nsr_id, db_dict)
321
322 except (asyncio.CancelledError, asyncio.TimeoutError):
323 raise
324 except Exception as e:
325 self.logger.warn('Error updating NS state for ns={}: {}'.format(nsr_id, e))
326
tierno72ef84f2020-10-06 08:22:07 +0000327 @staticmethod
328 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
329 try:
330 env = Environment(undefined=StrictUndefined)
331 template = env.from_string(cloud_init_text)
332 return template.render(additional_params or {})
333 except UndefinedError as e:
334 raise LcmException("Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
335 "file, must be provided in the instantiation parameters inside the "
336 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id))
337 except (TemplateError, TemplateNotFound) as e:
338 raise LcmException("Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".
339 format(vnfd_id, vdu_id, e))
340
bravof922c4172020-11-24 21:21:43 -0300341 def _get_vdu_cloud_init_content(self, vdu, vnfd):
342 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000343 try:
tierno72ef84f2020-10-06 08:22:07 +0000344 if vdu.get("cloud-init-file"):
345 base_folder = vnfd["_admin"]["storage"]
346 cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"],
347 vdu["cloud-init-file"])
348 with self.fs.file_open(cloud_init_file, "r") as ci_file:
349 cloud_init_content = ci_file.read()
350 elif vdu.get("cloud-init"):
351 cloud_init_content = vdu["cloud-init"]
352
353 return cloud_init_content
354 except FsException as e:
355 raise LcmException("Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".
356 format(vnfd["id"], vdu["id"], cloud_init_file, e))
357
tierno72ef84f2020-10-06 08:22:07 +0000358 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
359 vdur = next(vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"])
360 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300361 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000362
gcalvino35be9152018-12-20 09:33:12 +0100363 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200364 """
365 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
366 :param vnfd: input vnfd
367 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000368 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100369 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200370 :return: copy of vnfd
371 """
tierno72ef84f2020-10-06 08:22:07 +0000372 vnfd_RO = deepcopy(vnfd)
373 # remove unused by RO configuration, monitoring, scaling and internal keys
374 vnfd_RO.pop("_id", None)
375 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000376 vnfd_RO.pop("monitoring-param", None)
377 vnfd_RO.pop("scaling-group-descriptor", None)
378 vnfd_RO.pop("kdu", None)
379 vnfd_RO.pop("k8s-cluster", None)
380 if new_id:
381 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000382
tierno72ef84f2020-10-06 08:22:07 +0000383 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
384 for vdu in get_iterable(vnfd_RO, "vdu"):
385 vdu.pop("cloud-init-file", None)
386 vdu.pop("cloud-init", None)
387 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200388
tierno2357f4e2020-10-19 16:38:59 +0000389 @staticmethod
390 def ip_profile_2_RO(ip_profile):
391 RO_ip_profile = deepcopy(ip_profile)
392 if "dns-server" in RO_ip_profile:
393 if isinstance(RO_ip_profile["dns-server"], list):
394 RO_ip_profile["dns-address"] = []
395 for ds in RO_ip_profile.pop("dns-server"):
396 RO_ip_profile["dns-address"].append(ds['address'])
397 else:
398 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
399 if RO_ip_profile.get("ip-version") == "ipv4":
400 RO_ip_profile["ip-version"] = "IPv4"
401 if RO_ip_profile.get("ip-version") == "ipv6":
402 RO_ip_profile["ip-version"] = "IPv6"
403 if "dhcp-params" in RO_ip_profile:
404 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
405 return RO_ip_profile
406
bravof922c4172020-11-24 21:21:43 -0300407 def _get_ro_vim_id_for_vim_account(self, vim_account):
408 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
409 if db_vim["_admin"]["operationalState"] != "ENABLED":
410 raise LcmException("VIM={} is not available. operationalState={}".format(
411 vim_account, db_vim["_admin"]["operationalState"]))
412 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
413 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200414
bravof922c4172020-11-24 21:21:43 -0300415 def get_ro_wim_id_for_wim_account(self, wim_account):
416 if isinstance(wim_account, str):
417 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
418 if db_wim["_admin"]["operationalState"] != "ENABLED":
419 raise LcmException("WIM={} is not available. operationalState={}".format(
420 wim_account, db_wim["_admin"]["operationalState"]))
421 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
422 return RO_wim_id
423 else:
424 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200425
tierno2357f4e2020-10-19 16:38:59 +0000426 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno27246d82018-09-27 15:59:09 +0200427
tierno2357f4e2020-10-19 16:38:59 +0000428 db_vdu_push_list = []
429 db_update = {"_admin.modified": time()}
430 if vdu_create:
431 for vdu_id, vdu_count in vdu_create.items():
432 vdur = next((vdur for vdur in reversed(db_vnfr["vdur"]) if vdur["vdu-id-ref"] == vdu_id), None)
433 if not vdur:
434 raise LcmException("Error scaling OUT VNFR for {}. There is not any existing vnfr. Scaled to 0?".
435 format(vdu_id))
436
437 for count in range(vdu_count):
438 vdur_copy = deepcopy(vdur)
439 vdur_copy["status"] = "BUILD"
440 vdur_copy["status-detailed"] = None
441 vdur_copy["ip-address"]: None
tierno683eb392020-09-25 12:33:15 +0000442 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000443 vdur_copy["count-index"] += count + 1
444 vdur_copy["id"] = "{}-{}".format(vdur_copy["vdu-id-ref"], vdur_copy["count-index"])
445 vdur_copy.pop("vim_info", None)
446 for iface in vdur_copy["interfaces"]:
447 if iface.get("fixed-ip"):
448 iface["ip-address"] = self.increment_ip_mac(iface["ip-address"], count+1)
449 else:
450 iface.pop("ip-address", None)
451 if iface.get("fixed-mac"):
452 iface["mac-address"] = self.increment_ip_mac(iface["mac-address"], count+1)
453 else:
454 iface.pop("mac-address", None)
455 iface.pop("mgmt_vnf", None) # only first vdu can be managment of vnf
456 db_vdu_push_list.append(vdur_copy)
457 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200458 if vdu_delete:
tierno2357f4e2020-10-19 16:38:59 +0000459 for vdu_id, vdu_count in vdu_delete.items():
460 if mark_delete:
461 indexes_to_delete = [iv[0] for iv in enumerate(db_vnfr["vdur"]) if iv[1]["vdu-id-ref"] == vdu_id]
462 db_update.update({"vdur.{}.status".format(i): "DELETING" for i in indexes_to_delete[-vdu_count:]})
463 else:
464 # it must be deleted one by one because common.db does not allow otherwise
465 vdus_to_delete = [v for v in reversed(db_vnfr["vdur"]) if v["vdu-id-ref"] == vdu_id]
466 for vdu in vdus_to_delete[:vdu_count]:
467 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, None, pull={"vdur": {"_id": vdu["_id"]}})
468 db_push = {"vdur": db_vdu_push_list} if db_vdu_push_list else None
469 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
470 # modify passed dictionary db_vnfr
471 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
472 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200473
tiernof578e552018-11-08 19:07:20 +0100474 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
475 """
476 Updates database nsr with the RO info for the created vld
477 :param ns_update_nsr: dictionary to be filled with the updated info
478 :param db_nsr: content of db_nsr. This is also modified
479 :param nsr_desc_RO: nsr descriptor from RO
480 :return: Nothing, LcmException is raised on errors
481 """
482
483 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
484 for net_RO in get_iterable(nsr_desc_RO, "nets"):
485 if vld["id"] != net_RO.get("ns_net_osm_id"):
486 continue
487 vld["vim-id"] = net_RO.get("vim_net_id")
488 vld["name"] = net_RO.get("vim_name")
489 vld["status"] = net_RO.get("status")
490 vld["status-detailed"] = net_RO.get("error_msg")
491 ns_update_nsr["vld.{}".format(vld_index)] = vld
492 break
493 else:
494 raise LcmException("ns_update_nsr: Not found vld={} at RO info".format(vld["id"]))
495
tiernoe876f672020-02-13 14:34:48 +0000496 def set_vnfr_at_error(self, db_vnfrs, error_text):
497 try:
498 for db_vnfr in db_vnfrs.values():
499 vnfr_update = {"status": "ERROR"}
500 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
501 if "status" not in vdur:
502 vdur["status"] = "ERROR"
503 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
504 if error_text:
505 vdur["status-detailed"] = str(error_text)
506 vnfr_update["vdur.{}.status-detailed".format(vdu_index)] = "ERROR"
507 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
508 except DbException as e:
509 self.logger.error("Cannot update vnf. {}".format(e))
510
tierno59d22d22018-09-25 18:10:19 +0200511 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
512 """
513 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 +0200514 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
515 :param nsr_desc_RO: nsr descriptor from RO
516 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200517 """
518 for vnf_index, db_vnfr in db_vnfrs.items():
519 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200520 if vnf_RO["member_vnf_index"] != vnf_index:
521 continue
522 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100523 if vnf_RO.get("ip_address"):
tierno1674de82019-04-09 13:03:14 +0000524 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO["ip_address"].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100525 elif not db_vnfr.get("ip-address"):
tierno0ec0c272020-02-19 17:43:01 +0000526 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
527 raise LcmExceptionNoMgmtIP("ns member_vnf_index '{}' has no IP address".format(vnf_index))
tierno59d22d22018-09-25 18:10:19 +0200528
tierno27246d82018-09-27 15:59:09 +0200529 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
530 vdur_RO_count_index = 0
531 if vdur.get("pdu-type"):
532 continue
533 for vdur_RO in get_iterable(vnf_RO, "vms"):
534 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
535 continue
536 if vdur["count-index"] != vdur_RO_count_index:
537 vdur_RO_count_index += 1
538 continue
539 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000540 if vdur_RO.get("ip_address"):
541 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000542 else:
543 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200544 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
545 vdur["name"] = vdur_RO.get("vim_name")
546 vdur["status"] = vdur_RO.get("status")
547 vdur["status-detailed"] = vdur_RO.get("error_msg")
548 for ifacer in get_iterable(vdur, "interfaces"):
549 for interface_RO in get_iterable(vdur_RO, "interfaces"):
550 if ifacer["name"] == interface_RO.get("internal_name"):
551 ifacer["ip-address"] = interface_RO.get("ip_address")
552 ifacer["mac-address"] = interface_RO.get("mac_address")
553 break
554 else:
555 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
quilesj7e13aeb2019-10-08 13:34:55 +0200556 "from VIM info"
557 .format(vnf_index, vdur["vdu-id-ref"], ifacer["name"]))
tierno27246d82018-09-27 15:59:09 +0200558 vnfr_update["vdur.{}".format(vdu_index)] = vdur
559 break
560 else:
tierno15b1cf12019-08-29 13:21:40 +0000561 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
562 "VIM info".format(vnf_index, vdur["vdu-id-ref"], vdur["count-index"]))
tiernof578e552018-11-08 19:07:20 +0100563
564 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
565 for net_RO in get_iterable(nsr_desc_RO, "nets"):
566 if vld["id"] != net_RO.get("vnf_net_osm_id"):
567 continue
568 vld["vim-id"] = net_RO.get("vim_net_id")
569 vld["name"] = net_RO.get("vim_name")
570 vld["status"] = net_RO.get("status")
571 vld["status-detailed"] = net_RO.get("error_msg")
572 vnfr_update["vld.{}".format(vld_index)] = vld
573 break
574 else:
tierno15b1cf12019-08-29 13:21:40 +0000575 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
tiernof578e552018-11-08 19:07:20 +0100576 vnf_index, vld["id"]))
577
tierno27246d82018-09-27 15:59:09 +0200578 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
579 break
tierno59d22d22018-09-25 18:10:19 +0200580
581 else:
tierno15b1cf12019-08-29 13:21:40 +0000582 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(vnf_index))
tierno59d22d22018-09-25 18:10:19 +0200583
tierno5ee02052019-12-05 19:55:02 +0000584 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000585 """
586 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000587 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000588 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
589 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
590 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
591 """
tierno5ee02052019-12-05 19:55:02 +0000592 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
593 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000594 mapping = {}
595 ns_config_info = {"osm-config-mapping": mapping}
596 for vca in vca_deployed_list:
597 if not vca["member-vnf-index"]:
598 continue
599 if not vca["vdu_id"]:
600 mapping[vca["member-vnf-index"]] = vca["application"]
601 else:
602 mapping["{}.{}.{}".format(vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"])] =\
603 vca["application"]
604 return ns_config_info
605
bravof922c4172020-11-24 21:21:43 -0300606 async def _instantiate_ng_ro(self, logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs, db_vnfds,
tierno69f0d382020-05-07 13:08:09 +0000607 n2vc_key_list, stage, start_deploy, timeout_ns_deploy):
tierno2357f4e2020-10-19 16:38:59 +0000608
609 db_vims = {}
610
611 def get_vim_account(vim_account_id):
612 nonlocal db_vims
613 if vim_account_id in db_vims:
614 return db_vims[vim_account_id]
615 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
616 db_vims[vim_account_id] = db_vim
617 return db_vim
618
619 # modify target_vld info with instantiation parameters
620 def parse_vld_instantiation_params(target_vim, target_vld, vld_params, target_sdn):
621 if vld_params.get("ip-profile"):
622 target_vld["vim_info"][target_vim]["ip_profile"] = vld_params["ip-profile"]
623 if vld_params.get("provider-network"):
624 target_vld["vim_info"][target_vim]["provider_network"] = vld_params["provider-network"]
625 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
626 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params["provider-network"]["sdn-ports"]
627 if vld_params.get("wimAccountId"):
628 target_wim = "wim:{}".format(vld_params["wimAccountId"])
629 target_vld["vim_info"][target_wim] = {}
630 for param in ("vim-network-name", "vim-network-id"):
631 if vld_params.get(param):
632 if isinstance(vld_params[param], dict):
garciaale04694c62021-03-02 10:49:28 -0300633 for vim, vim_net in vld_params[param].items():
bravof922c4172020-11-24 21:21:43 -0300634 other_target_vim = "vim:" + vim
635 populate_dict(target_vld["vim_info"], (other_target_vim, param.replace("-", "_")), vim_net)
tierno2357f4e2020-10-19 16:38:59 +0000636 else: # isinstance str
637 target_vld["vim_info"][target_vim][param.replace("-", "_")] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300638 if vld_params.get("common_id"):
639 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000640
tierno69f0d382020-05-07 13:08:09 +0000641 nslcmop_id = db_nslcmop["_id"]
642 target = {
643 "name": db_nsr["name"],
644 "ns": {"vld": []},
645 "vnf": [],
646 "image": deepcopy(db_nsr["image"]),
647 "flavor": deepcopy(db_nsr["flavor"]),
648 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000649 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000650 }
651 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000652 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000653 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000654 flavor["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000655
tierno2357f4e2020-10-19 16:38:59 +0000656 if db_nslcmop.get("lcmOperationType") != "instantiate":
657 # get parameters of instantiation:
658 db_nslcmop_instantiate = self.db.get_list("nslcmops", {"nsInstanceId": db_nslcmop["nsInstanceId"],
659 "lcmOperationType": "instantiate"})[-1]
660 ns_params = db_nslcmop_instantiate.get("operationParams")
661 else:
662 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300663 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
664 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000665
666 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000667 for vld_index, vld in enumerate(db_nsr.get("vld")):
668 target_vim = "vim:{}".format(ns_params["vimAccountId"])
669 target_vld = {
670 "id": vld["id"],
671 "name": vld["name"],
672 "mgmt-network": vld.get("mgmt-network", False),
673 "type": vld.get("type"),
674 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300675 target_vim: {
676 "vim_network_name": vld.get("vim-network-name"),
677 "vim_account_id": ns_params["vimAccountId"]
678 }
tierno2357f4e2020-10-19 16:38:59 +0000679 }
680 }
681 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000682 if vld.get("pci-interfaces"):
garciadeblasa5ae90b2021-02-12 11:26:46 +0000683 db_vim = get_vim_account(ns_params["vimAccountId"])
tierno2357f4e2020-10-19 16:38:59 +0000684 sdnc_id = db_vim["config"].get("sdn-controller")
685 if sdnc_id:
garciadeblasa5ae90b2021-02-12 11:26:46 +0000686 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
687 target_sdn = "sdn:{}".format(sdnc_id)
688 target_vld["vim_info"][target_sdn] = {
689 "sdn": True, "target_vim": target_vim, "vlds": [sdn_vld], "type": vld.get("type")}
tierno2357f4e2020-10-19 16:38:59 +0000690
bravof922c4172020-11-24 21:21:43 -0300691 nsd_vnf_profiles = get_vnf_profiles(nsd)
692 for nsd_vnf_profile in nsd_vnf_profiles:
693 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
694 if cp["virtual-link-profile-id"] == vld["id"]:
695 cp2target["member_vnf:{}.{}".format(
696 cp["constituent-cpd-id"][0]["constituent-base-element-id"],
697 cp["constituent-cpd-id"][0]["constituent-cpd-id"]
698 )] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000699
700 # check at nsd descriptor, if there is an ip-profile
701 vld_params = {}
lloretgalleg19008482021-04-19 11:40:18 +0000702 nsd_vlp = find_in_list(
703 get_virtual_link_profiles(nsd),
704 lambda a_link_profile: a_link_profile["virtual-link-desc-id"] == vld["id"])
705 if nsd_vlp and nsd_vlp.get("virtual-link-protocol-data") and \
706 nsd_vlp["virtual-link-protocol-data"].get("l3-protocol-data"):
707 ip_profile_source_data = nsd_vlp["virtual-link-protocol-data"]["l3-protocol-data"]
708 ip_profile_dest_data = {}
709 if "ip-version" in ip_profile_source_data:
710 ip_profile_dest_data["ip-version"] = ip_profile_source_data["ip-version"]
711 if "cidr" in ip_profile_source_data:
712 ip_profile_dest_data["subnet-address"] = ip_profile_source_data["cidr"]
713 if "gateway-ip" in ip_profile_source_data:
714 ip_profile_dest_data["gateway-address"] = ip_profile_source_data["gateway-ip"]
715 if "dhcp-enabled" in ip_profile_source_data:
716 ip_profile_dest_data["dhcp-params"] = {
717 "enabled": ip_profile_source_data["dhcp-enabled"]
718 }
719 vld_params["ip-profile"] = ip_profile_dest_data
bravof922c4172020-11-24 21:21:43 -0300720
tierno2357f4e2020-10-19 16:38:59 +0000721 # update vld_params with instantiation params
bravof922c4172020-11-24 21:21:43 -0300722 vld_instantiation_params = find_in_list(get_iterable(ns_params, "vld"),
723 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]))
tierno2357f4e2020-10-19 16:38:59 +0000724 if vld_instantiation_params:
725 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300726 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000727 target["ns"]["vld"].append(target_vld)
bravof922c4172020-11-24 21:21:43 -0300728
tierno69f0d382020-05-07 13:08:09 +0000729 for vnfr in db_vnfrs.values():
bravof922c4172020-11-24 21:21:43 -0300730 vnfd = find_in_list(db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"])
731 vnf_params = find_in_list(get_iterable(ns_params, "vnf"),
732 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"])
tierno69f0d382020-05-07 13:08:09 +0000733 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000734 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000735 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000736 # check if connected to a ns.vld, to fill target'
bravof922c4172020-11-24 21:21:43 -0300737 vnf_cp = find_in_list(vnfd.get("int-virtual-link-desc", ()),
738 lambda cpd: cpd.get("id") == vld["id"])
tierno69f0d382020-05-07 13:08:09 +0000739 if vnf_cp:
740 ns_cp = "member_vnf:{}.{}".format(vnfr["member-vnf-index-ref"], vnf_cp["id"])
741 if cp2target.get(ns_cp):
742 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300743
744 vld["vim_info"] = {target_vim: {"vim_network_name": vld.get("vim-network-name")}}
tierno2357f4e2020-10-19 16:38:59 +0000745 # check if this network needs SDN assist
746 target_sdn = None
747 if vld.get("pci-interfaces"):
748 db_vim = get_vim_account(vnfr["vim-account-id"])
749 sdnc_id = db_vim["config"].get("sdn-controller")
750 if sdnc_id:
751 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
752 target_sdn = "sdn:{}".format(sdnc_id)
753 vld["vim_info"][target_sdn] = {
754 "sdn": True, "target_vim": target_vim, "vlds": [sdn_vld], "type": vld.get("type")}
tierno69f0d382020-05-07 13:08:09 +0000755
tierno2357f4e2020-10-19 16:38:59 +0000756 # check at vnfd descriptor, if there is an ip-profile
757 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300758 vnfd_vlp = find_in_list(
759 get_virtual_link_profiles(vnfd),
760 lambda a_link_profile: a_link_profile["id"] == vld["id"]
761 )
762 if vnfd_vlp and vnfd_vlp.get("virtual-link-protocol-data") and \
763 vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data"):
764 ip_profile_source_data = vnfd_vlp["virtual-link-protocol-data"]["l3-protocol-data"]
765 ip_profile_dest_data = {}
766 if "ip-version" in ip_profile_source_data:
767 ip_profile_dest_data["ip-version"] = ip_profile_source_data["ip-version"]
768 if "cidr" in ip_profile_source_data:
769 ip_profile_dest_data["subnet-address"] = ip_profile_source_data["cidr"]
770 if "gateway-ip" in ip_profile_source_data:
771 ip_profile_dest_data["gateway-address"] = ip_profile_source_data["gateway-ip"]
772 if "dhcp-enabled" in ip_profile_source_data:
773 ip_profile_dest_data["dhcp-params"] = {
774 "enabled": ip_profile_source_data["dhcp-enabled"]
775 }
776
777 vld_params["ip-profile"] = ip_profile_dest_data
tierno2357f4e2020-10-19 16:38:59 +0000778 # update vld_params with instantiation params
779 if vnf_params:
bravof922c4172020-11-24 21:21:43 -0300780 vld_instantiation_params = find_in_list(get_iterable(vnf_params, "internal-vld"),
781 lambda i_vld: i_vld["name"] == vld["id"])
tierno2357f4e2020-10-19 16:38:59 +0000782 if vld_instantiation_params:
783 vld_params.update(vld_instantiation_params)
784 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
785
786 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +0000787 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +0000788 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
789 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -0300790 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +0000791
bravof922c4172020-11-24 21:21:43 -0300792 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
793
794 if ssh_keys_all:
bravofe5a31bc2021-02-17 19:09:12 -0300795 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
796 vnf_configuration = get_configuration(vnfd, vnfd["id"])
bravof922c4172020-11-24 21:21:43 -0300797 if vdu_configuration and vdu_configuration.get("config-access") and \
798 vdu_configuration.get("config-access").get("ssh-access"):
799 vdur["ssh-keys"] = ssh_keys_all
800 vdur["ssh-access-required"] = vdu_configuration["config-access"]["ssh-access"]["required"]
801 elif vnf_configuration and vnf_configuration.get("config-access") and \
802 vnf_configuration.get("config-access").get("ssh-access") and \
tierno69f0d382020-05-07 13:08:09 +0000803 any(iface.get("mgmt-vnf") for iface in vdur["interfaces"]):
bravof922c4172020-11-24 21:21:43 -0300804 vdur["ssh-keys"] = ssh_keys_all
805 vdur["ssh-access-required"] = vnf_configuration["config-access"]["ssh-access"]["required"]
806 elif ssh_keys_instantiation and \
807 find_in_list(vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")):
808 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +0000809
bravof922c4172020-11-24 21:21:43 -0300810 self.logger.debug("NS > vdur > {}".format(vdur))
811
812 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +0000813 # cloud-init
814 if vdud.get("cloud-init-file"):
815 vdur["cloud-init"] = "{}:file:{}".format(vnfd["_id"], vdud.get("cloud-init-file"))
tierno2357f4e2020-10-19 16:38:59 +0000816 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
817 if vdur["cloud-init"] not in target["cloud_init_content"]:
818 base_folder = vnfd["_admin"]["storage"]
819 cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"],
820 vdud.get("cloud-init-file"))
821 with self.fs.file_open(cloud_init_file, "r") as ci_file:
822 target["cloud_init_content"][vdur["cloud-init"]] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +0000823 elif vdud.get("cloud-init"):
bravof922c4172020-11-24 21:21:43 -0300824 vdur["cloud-init"] = "{}:vdu:{}".format(vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"]))
tierno2357f4e2020-10-19 16:38:59 +0000825 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
826 target["cloud_init_content"][vdur["cloud-init"]] = vdud["cloud-init"]
827 vdur["additionalParams"] = vdur.get("additionalParams") or {}
828 deploy_params_vdu = self._format_additional_params(vdur.get("additionalParams") or {})
bravof922c4172020-11-24 21:21:43 -0300829 deploy_params_vdu["OSM"] = get_osm_params(vnfr, vdur["vdu-id-ref"], vdur["count-index"])
tierno2357f4e2020-10-19 16:38:59 +0000830 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +0000831
832 # flavor
833 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +0000834 if target_vim not in ns_flavor["vim_info"]:
835 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg7dc94672021-02-08 11:49:50 +0000836
837 # deal with images
838 # in case alternative images are provided we must check if they should be applied
839 # for the vim_type, modify the vim_type taking into account
840 ns_image_id = int(vdur["ns-image-id"])
841 if vdur.get("alt-image-ids"):
842 db_vim = get_vim_account(vnfr["vim-account-id"])
843 vim_type = db_vim["vim_type"]
844 for alt_image_id in vdur.get("alt-image-ids"):
845 ns_alt_image = target["image"][int(alt_image_id)]
846 if vim_type == ns_alt_image.get("vim-type"):
847 # must use alternative image
848 self.logger.debug("use alternative image id: {}".format(alt_image_id))
849 ns_image_id = alt_image_id
850 vdur["ns-image-id"] = ns_image_id
851 break
852 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +0000853 if target_vim not in ns_image["vim_info"]:
854 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +0000855
tierno2357f4e2020-10-19 16:38:59 +0000856 vdur["vim_info"] = {target_vim: {}}
857 # instantiation parameters
858 # if vnf_params:
859 # vdu_instantiation_params = next((v for v in get_iterable(vnf_params, "vdu") if v["id"] ==
860 # vdud["id"]), None)
861 vdur_list.append(vdur)
862 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +0000863 target["vnf"].append(target_vnf)
864
865 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -0300866 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +0000867 action_id = desc["action_id"]
tierno2357f4e2020-10-19 16:38:59 +0000868 await self._wait_ng_ro(nsr_id, action_id, nslcmop_id, start_deploy, timeout_ns_deploy, stage)
tierno69f0d382020-05-07 13:08:09 +0000869
870 # Updating NSR
871 db_nsr_update = {
872 "_admin.deployed.RO.operational-status": "running",
873 "detailed-status": " ".join(stage)
874 }
875 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
876 self.update_db_2("nsrs", nsr_id, db_nsr_update)
877 self._write_op_status(nslcmop_id, stage)
878 self.logger.debug(logging_text + "ns deployed at RO. RO_id={}".format(action_id))
879 return
880
tierno2357f4e2020-10-19 16:38:59 +0000881 async def _wait_ng_ro(self, nsr_id, action_id, nslcmop_id=None, start_time=None, timeout=600, stage=None):
tierno69f0d382020-05-07 13:08:09 +0000882 detailed_status_old = None
883 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +0000884 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +0000885 while time() <= start_time + timeout:
886 desc_status = await self.RO.status(nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -0300887 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +0000888 if desc_status["status"] == "FAILED":
889 raise NgRoException(desc_status["details"])
890 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +0000891 if stage:
892 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +0000893 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +0000894 if stage:
895 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +0000896 break
897 else:
898 assert False, "ROclient.check_ns_status returns unknown {}".format(desc_status["status"])
tierno2357f4e2020-10-19 16:38:59 +0000899 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +0000900 detailed_status_old = stage[2]
901 db_nsr_update["detailed-status"] = " ".join(stage)
902 self.update_db_2("nsrs", nsr_id, db_nsr_update)
903 self._write_op_status(nslcmop_id, stage)
bravof922c4172020-11-24 21:21:43 -0300904 await asyncio.sleep(15, loop=self.loop)
tierno69f0d382020-05-07 13:08:09 +0000905 else: # timeout_ns_deploy
906 raise NgRoException("Timeout waiting ns to deploy")
907
908 async def _terminate_ng_ro(self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage):
909 db_nsr_update = {}
910 failed_detail = []
911 action_id = None
912 start_deploy = time()
913 try:
914 target = {
915 "ns": {"vld": []},
916 "vnf": [],
917 "image": [],
918 "flavor": [],
tierno2357f4e2020-10-19 16:38:59 +0000919 "action_id": nslcmop_id
tierno69f0d382020-05-07 13:08:09 +0000920 }
921 desc = await self.RO.deploy(nsr_id, target)
922 action_id = desc["action_id"]
923 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = action_id
924 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
925 self.logger.debug(logging_text + "ns terminate action at RO. action_id={}".format(action_id))
926
927 # wait until done
928 delete_timeout = 20 * 60 # 20 minutes
tierno2357f4e2020-10-19 16:38:59 +0000929 await self._wait_ng_ro(nsr_id, action_id, nslcmop_id, start_deploy, delete_timeout, stage)
tierno69f0d382020-05-07 13:08:09 +0000930
931 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
932 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
933 # delete all nsr
934 await self.RO.delete(nsr_id)
935 except Exception as e:
936 if isinstance(e, NgRoException) and e.http_code == 404: # not found
937 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
938 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
939 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
940 self.logger.debug(logging_text + "RO_action_id={} already deleted".format(action_id))
941 elif isinstance(e, NgRoException) and e.http_code == 409: # conflict
942 failed_detail.append("delete conflict: {}".format(e))
943 self.logger.debug(logging_text + "RO_action_id={} delete conflict: {}".format(action_id, e))
944 else:
945 failed_detail.append("delete error: {}".format(e))
946 self.logger.error(logging_text + "RO_action_id={} delete error: {}".format(action_id, e))
947
948 if failed_detail:
949 stage[2] = "Error deleting from VIM"
950 else:
951 stage[2] = "Deleted from VIM"
952 db_nsr_update["detailed-status"] = " ".join(stage)
953 self.update_db_2("nsrs", nsr_id, db_nsr_update)
954 self._write_op_status(nslcmop_id, stage)
955
956 if failed_detail:
957 raise LcmException("; ".join(failed_detail))
958 return
959
bravof922c4172020-11-24 21:21:43 -0300960 async def instantiate_RO(self, logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs, db_vnfds,
tiernoe876f672020-02-13 14:34:48 +0000961 n2vc_key_list, stage):
tiernoe95ed362020-04-23 08:24:57 +0000962 """
963 Instantiate at RO
964 :param logging_text: preffix text to use at logging
965 :param nsr_id: nsr identity
966 :param nsd: database content of ns descriptor
967 :param db_nsr: database content of ns record
968 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
969 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -0300970 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +0000971 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
972 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
973 :return: None or exception
974 """
tiernoe876f672020-02-13 14:34:48 +0000975 try:
tiernoe876f672020-02-13 14:34:48 +0000976 start_deploy = time()
977 ns_params = db_nslcmop.get("operationParams")
978 if ns_params and ns_params.get("timeout_ns_deploy"):
979 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
980 else:
981 timeout_ns_deploy = self.timeout.get("ns_deploy", self.timeout_ns_deploy)
quilesj7e13aeb2019-10-08 13:34:55 +0200982
tiernoe876f672020-02-13 14:34:48 +0000983 # Check for and optionally request placement optimization. Database will be updated if placement activated
984 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +0000985 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
986 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
987 for vnfr in db_vnfrs.values():
988 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
989 break
990 else:
991 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +0200992
bravof922c4172020-11-24 21:21:43 -0300993 return await self._instantiate_ng_ro(logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs,
994 db_vnfds, n2vc_key_list, stage, start_deploy, timeout_ns_deploy)
tierno2357f4e2020-10-19 16:38:59 +0000995 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +0000996 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +0000997 self.set_vnfr_at_error(db_vnfrs, str(e))
tierno2357f4e2020-10-19 16:38:59 +0000998 self.logger.error("Error deploying at VIM {}".format(e),
999 exc_info=not isinstance(e, (ROclient.ROClientException, LcmException, DbException,
1000 NgRoException)))
tiernoe876f672020-02-13 14:34:48 +00001001 raise
quilesj7e13aeb2019-10-08 13:34:55 +02001002
tierno7ecbc342020-09-21 14:05:39 +00001003 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
1004 """
1005 Wait for kdu to be up, get ip address
1006 :param logging_text: prefix use for logging
1007 :param nsr_id:
1008 :param vnfr_id:
1009 :param kdu_name:
1010 :return: IP address
1011 """
1012
1013 # self.logger.debug(logging_text + "Starting wait_kdu_up")
1014 nb_tries = 0
1015
1016 while nb_tries < 360:
1017 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
tiernoe5d05972020-10-09 12:03:24 +00001018 kdur = next((x for x in get_iterable(db_vnfr, "kdur") if x.get("kdu-name") == kdu_name), None)
tierno7ecbc342020-09-21 14:05:39 +00001019 if not kdur:
1020 raise LcmException("Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name))
1021 if kdur.get("status"):
1022 if kdur["status"] in ("READY", "ENABLED"):
1023 return kdur.get("ip-address")
1024 else:
1025 raise LcmException("target KDU={} is in error state".format(kdu_name))
1026
1027 await asyncio.sleep(10, loop=self.loop)
1028 nb_tries += 1
1029 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
1030
tiernoa5088192019-11-26 16:12:53 +00001031 async def wait_vm_up_insert_key_ro(self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None):
1032 """
1033 Wait for ip addres at RO, and optionally, insert public key in virtual machine
1034 :param logging_text: prefix use for logging
1035 :param nsr_id:
1036 :param vnfr_id:
1037 :param vdu_id:
1038 :param vdu_index:
1039 :param pub_key: public ssh key to inject, None to skip
1040 :param user: user to apply the public ssh key
1041 :return: IP address
1042 """
quilesj7e13aeb2019-10-08 13:34:55 +02001043
tierno2357f4e2020-10-19 16:38:59 +00001044 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +00001045 ro_nsr_id = None
1046 ip_address = None
1047 nb_tries = 0
1048 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001049 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001050
tiernod8323042019-08-09 11:32:23 +00001051 while True:
quilesj7e13aeb2019-10-08 13:34:55 +02001052
quilesj3149f262019-12-03 10:58:10 +00001053 ro_retries += 1
1054 if ro_retries >= 360: # 1 hour
1055 raise LcmException("Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id))
1056
tiernod8323042019-08-09 11:32:23 +00001057 await asyncio.sleep(10, loop=self.loop)
quilesj7e13aeb2019-10-08 13:34:55 +02001058
1059 # get ip address
tiernod8323042019-08-09 11:32:23 +00001060 if not target_vdu_id:
1061 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001062
1063 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001064 if db_vnfr.get("status") == "ERROR":
1065 raise LcmException("Cannot inject ssh-key because target VNF is in error state")
tiernod8323042019-08-09 11:32:23 +00001066 ip_address = db_vnfr.get("ip-address")
1067 if not ip_address:
1068 continue
quilesj3149f262019-12-03 10:58:10 +00001069 vdur = next((x for x in get_iterable(db_vnfr, "vdur") if x.get("ip-address") == ip_address), None)
1070 else: # VDU case
1071 vdur = next((x for x in get_iterable(db_vnfr, "vdur")
1072 if x.get("vdu-id-ref") == vdu_id and x.get("count-index") == vdu_index), None)
1073
tierno0e8c3f02020-03-12 17:18:21 +00001074 if not vdur and len(db_vnfr.get("vdur", ())) == 1: # If only one, this should be the target vdu
1075 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001076 if not vdur:
tierno0e8c3f02020-03-12 17:18:21 +00001077 raise LcmException("Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(vnfr_id, vdu_id,
1078 vdu_index))
tierno2357f4e2020-10-19 16:38:59 +00001079 # New generation RO stores information at "vim_info"
1080 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001081 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001082 if vdur.get("vim_info"):
1083 target_vim = next(t for t in vdur["vim_info"]) # there should be only one key
1084 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
1085 if vdur.get("pdu-type") or vdur.get("status") == "ACTIVE" or ng_ro_status == "ACTIVE":
quilesj3149f262019-12-03 10:58:10 +00001086 ip_address = vdur.get("ip-address")
1087 if not ip_address:
1088 continue
1089 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001090 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
quilesj3149f262019-12-03 10:58:10 +00001091 raise LcmException("Cannot inject ssh-key because target VM is in error state")
1092
tiernod8323042019-08-09 11:32:23 +00001093 if not target_vdu_id:
1094 continue
tiernod8323042019-08-09 11:32:23 +00001095
quilesj7e13aeb2019-10-08 13:34:55 +02001096 # inject public key into machine
1097 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001098 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001099 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001100 if vdur.get("pdu-type"):
1101 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1102 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001103 try:
1104 ro_vm_id = "{}-{}".format(db_vnfr["member-vnf-index-ref"], target_vdu_id) # TODO add vdu_index
tierno69f0d382020-05-07 13:08:09 +00001105 if self.ng_ro:
bravof922c4172020-11-24 21:21:43 -03001106 target = {"action": {"action": "inject_ssh_key", "key": pub_key, "user": user},
tierno2357f4e2020-10-19 16:38:59 +00001107 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
tierno69f0d382020-05-07 13:08:09 +00001108 }
tierno2357f4e2020-10-19 16:38:59 +00001109 desc = await self.RO.deploy(nsr_id, target)
1110 action_id = desc["action_id"]
1111 await self._wait_ng_ro(nsr_id, action_id, timeout=600)
1112 break
tierno69f0d382020-05-07 13:08:09 +00001113 else:
tierno2357f4e2020-10-19 16:38:59 +00001114 # wait until NS is deployed at RO
1115 if not ro_nsr_id:
1116 db_nsrs = self.db.get_one("nsrs", {"_id": nsr_id})
1117 ro_nsr_id = deep_get(db_nsrs, ("_admin", "deployed", "RO", "nsr_id"))
1118 if not ro_nsr_id:
1119 continue
tierno69f0d382020-05-07 13:08:09 +00001120 result_dict = await self.RO.create_action(
1121 item="ns",
1122 item_id_name=ro_nsr_id,
1123 descriptor={"add_public_key": pub_key, "vms": [ro_vm_id], "user": user}
1124 )
1125 # result_dict contains the format {VM-id: {vim_result: 200, description: text}}
1126 if not result_dict or not isinstance(result_dict, dict):
1127 raise LcmException("Unknown response from RO when injecting key")
1128 for result in result_dict.values():
1129 if result.get("vim_result") == 200:
1130 break
1131 else:
1132 raise ROclient.ROClientException("error injecting key: {}".format(
1133 result.get("description")))
1134 break
1135 except NgRoException as e:
1136 raise LcmException("Reaching max tries injecting key. Error: {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02001137 except ROclient.ROClientException as e:
tiernoa5088192019-11-26 16:12:53 +00001138 if not nb_tries:
1139 self.logger.debug(logging_text + "error injecting key: {}. Retrying until {} seconds".
1140 format(e, 20*10))
quilesj7e13aeb2019-10-08 13:34:55 +02001141 nb_tries += 1
tiernoa5088192019-11-26 16:12:53 +00001142 if nb_tries >= 20:
quilesj7e13aeb2019-10-08 13:34:55 +02001143 raise LcmException("Reaching max tries injecting key. Error: {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02001144 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001145 break
1146
1147 return ip_address
1148
tierno5ee02052019-12-05 19:55:02 +00001149 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1150 """
1151 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1152 """
1153 my_vca = vca_deployed_list[vca_index]
1154 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001155 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001156 return
1157 timeout = 300
1158 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001159 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1160 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1161 configuration_status_list = db_nsr["configurationStatus"]
1162 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001163 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001164 # myself
tierno5ee02052019-12-05 19:55:02 +00001165 continue
1166 if not my_vca.get("member-vnf-index") or \
1167 (vca_deployed.get("member-vnf-index") == my_vca.get("member-vnf-index")):
quilesj3655ae02019-12-12 16:08:35 +00001168 internal_status = configuration_status_list[index].get("status")
1169 if internal_status == 'READY':
1170 continue
1171 elif internal_status == 'BROKEN':
tierno5ee02052019-12-05 19:55:02 +00001172 raise LcmException("Configuration aborted because dependent charm/s has failed")
quilesj3655ae02019-12-12 16:08:35 +00001173 else:
1174 break
tierno5ee02052019-12-05 19:55:02 +00001175 else:
quilesj3655ae02019-12-12 16:08:35 +00001176 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001177 return
1178 await asyncio.sleep(10)
1179 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001180
1181 raise LcmException("Configuration aborted because dependent charm/s timeout")
1182
David Garciac1fe90a2021-03-31 19:12:02 +02001183 def get_vca_id(self, db_vnfr: dict, db_nsr: dict):
1184 return (
1185 deep_get(db_vnfr, ("vca-id",)) or
1186 deep_get(db_nsr, ("instantiate_params", "vcaId"))
1187 )
1188
tiernoe876f672020-02-13 14:34:48 +00001189 async def instantiate_N2VC(self, logging_text, vca_index, nsi_id, db_nsr, db_vnfr, vdu_id, kdu_name, vdu_index,
tiernob996d942020-07-03 14:52:28 +00001190 config_descriptor, deploy_params, base_folder, nslcmop_id, stage, vca_type, vca_name,
1191 ee_config_descriptor):
tiernod8323042019-08-09 11:32:23 +00001192 nsr_id = db_nsr["_id"]
1193 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001194 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001195 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001196 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001197 db_dict = {
1198 'collection': 'nsrs',
1199 'filter': {'_id': nsr_id},
1200 'path': db_update_entry
1201 }
tiernod8323042019-08-09 11:32:23 +00001202 step = ""
1203 try:
quilesj3655ae02019-12-12 16:08:35 +00001204
1205 element_type = 'NS'
1206 element_under_configuration = nsr_id
1207
tiernod8323042019-08-09 11:32:23 +00001208 vnfr_id = None
1209 if db_vnfr:
1210 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001211 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001212
1213 namespace = "{nsi}.{ns}".format(
1214 nsi=nsi_id if nsi_id else "",
1215 ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001216
tiernod8323042019-08-09 11:32:23 +00001217 if vnfr_id:
quilesj3655ae02019-12-12 16:08:35 +00001218 element_type = 'VNF'
1219 element_under_configuration = vnfr_id
aktas13251562021-02-12 22:19:10 +03001220 namespace += ".{}-{}".format(vnfr_id, vdu_index or 0)
tiernod8323042019-08-09 11:32:23 +00001221 if vdu_id:
1222 namespace += ".{}-{}".format(vdu_id, vdu_index or 0)
quilesj3655ae02019-12-12 16:08:35 +00001223 element_type = 'VDU'
quilesjb8a35dd2020-01-09 15:10:14 +00001224 element_under_configuration = "{}-{}".format(vdu_id, vdu_index or 0)
tiernob996d942020-07-03 14:52:28 +00001225 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001226 elif kdu_name:
aktas13251562021-02-12 22:19:10 +03001227 namespace += ".{}.{}".format(kdu_name, vdu_index or 0)
tierno51183952020-04-03 15:48:18 +00001228 element_type = 'KDU'
1229 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001230 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001231
1232 # Get artifact path
tierno588547c2020-07-01 15:30:20 +00001233 artifact_path = "{}/{}/{}/{}".format(
tiernod8323042019-08-09 11:32:23 +00001234 base_folder["folder"],
1235 base_folder["pkg-dir"],
tierno588547c2020-07-01 15:30:20 +00001236 "charms" if vca_type in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm") else "helm-charts",
1237 vca_name
tiernod8323042019-08-09 11:32:23 +00001238 )
bravof922c4172020-11-24 21:21:43 -03001239
1240 self.logger.debug("Artifact path > {}".format(artifact_path))
1241
tiernoa278b842020-07-08 15:33:55 +00001242 # get initial_config_primitive_list that applies to this element
1243 initial_config_primitive_list = config_descriptor.get('initial-config-primitive')
1244
bravof922c4172020-11-24 21:21:43 -03001245 self.logger.debug("Initial config primitive list > {}".format(initial_config_primitive_list))
1246
tiernoa278b842020-07-08 15:33:55 +00001247 # add config if not present for NS charm
1248 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001249 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
1250 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(initial_config_primitive_list,
1251 vca_deployed, ee_descriptor_id)
tiernod8323042019-08-09 11:32:23 +00001252
bravof922c4172020-11-24 21:21:43 -03001253 self.logger.debug("Initial config primitive list #2 > {}".format(initial_config_primitive_list))
tierno588547c2020-07-01 15:30:20 +00001254 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001255 # find old ee_id if exists
1256 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001257
David Garciac1fe90a2021-03-31 19:12:02 +02001258 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno588547c2020-07-01 15:30:20 +00001259 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001260 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
quilesj7e13aeb2019-10-08 13:34:55 +02001261
tierno588547c2020-07-01 15:30:20 +00001262 self._write_configuration_status(
1263 nsr_id=nsr_id,
1264 vca_index=vca_index,
1265 status='CREATING',
1266 element_under_configuration=element_under_configuration,
1267 element_type=element_type
1268 )
tiernod8323042019-08-09 11:32:23 +00001269
tierno588547c2020-07-01 15:30:20 +00001270 step = "create execution environment"
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001271 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001272
1273 ee_id = None
1274 credentials = None
1275 if vca_type == "k8s_proxy_charm":
1276 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
1277 charm_name=artifact_path[artifact_path.rfind("/") + 1:],
1278 namespace=namespace,
1279 artifact_path=artifact_path,
1280 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001281 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001282 )
David Garciad64e2742021-02-25 20:19:18 +01001283 elif vca_type == "helm" or vca_type == "helm-v3":
bravof922c4172020-11-24 21:21:43 -03001284 ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
1285 namespace=namespace,
1286 reuse_ee_id=ee_id,
1287 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001288 config=osm_config,
1289 artifact_path=artifact_path,
1290 vca_type=vca_type
bravof922c4172020-11-24 21:21:43 -03001291 )
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001292 else:
David Garciaaae391f2020-11-09 11:12:54 +01001293 ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
1294 namespace=namespace,
1295 reuse_ee_id=ee_id,
1296 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001297 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001298 )
quilesj3655ae02019-12-12 16:08:35 +00001299
tierno588547c2020-07-01 15:30:20 +00001300 elif vca_type == "native_charm":
1301 step = "Waiting to VM being up and getting IP address"
1302 self.logger.debug(logging_text + step)
1303 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(logging_text, nsr_id, vnfr_id, vdu_id, vdu_index,
1304 user=None, pub_key=None)
1305 credentials = {"hostname": rw_mgmt_ip}
1306 # get username
1307 username = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user"))
1308 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1309 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001310 if not username and initial_config_primitive_list:
1311 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001312 for param in config_primitive.get("parameter", ()):
1313 if param["name"] == "ssh-username":
1314 username = param["value"]
1315 break
1316 if not username:
tiernoa278b842020-07-08 15:33:55 +00001317 raise LcmException("Cannot determine the username neither with 'initial-config-primitive' nor with "
tierno588547c2020-07-01 15:30:20 +00001318 "'config-access.ssh-access.default-user'")
1319 credentials["username"] = username
1320 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001321
tierno588547c2020-07-01 15:30:20 +00001322 self._write_configuration_status(
1323 nsr_id=nsr_id,
1324 vca_index=vca_index,
1325 status='REGISTERING',
1326 element_under_configuration=element_under_configuration,
1327 element_type=element_type
1328 )
quilesj3655ae02019-12-12 16:08:35 +00001329
tierno588547c2020-07-01 15:30:20 +00001330 step = "register execution environment {}".format(credentials)
1331 self.logger.debug(logging_text + step)
1332 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001333 credentials=credentials,
1334 namespace=namespace,
1335 db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02001336 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001337 )
tierno3bedc9b2019-11-27 15:46:57 +00001338
tierno588547c2020-07-01 15:30:20 +00001339 # for compatibility with MON/POL modules, the need model and application name at database
1340 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
1341 ee_id_parts = ee_id.split('.')
1342 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1343 if len(ee_id_parts) >= 2:
1344 model_name = ee_id_parts[0]
1345 application_name = ee_id_parts[1]
1346 db_nsr_update[db_update_entry + "model"] = model_name
1347 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001348
1349 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001350 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001351
tiernoc231a872020-01-21 08:49:05 +00001352 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001353 nsr_id=nsr_id,
1354 vca_index=vca_index,
1355 status='INSTALLING SW',
1356 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001357 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001358 other_update=db_nsr_update
quilesj3655ae02019-12-12 16:08:35 +00001359 )
1360
tierno3bedc9b2019-11-27 15:46:57 +00001361 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001362 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001363 config = None
tierno588547c2020-07-01 15:30:20 +00001364 if vca_type == "native_charm":
tiernoa278b842020-07-08 15:33:55 +00001365 config_primitive = next((p for p in initial_config_primitive_list if p["name"] == "config"), None)
1366 if config_primitive:
1367 config = self._map_primitive_params(
1368 config_primitive,
1369 {},
1370 deploy_params
1371 )
tierno588547c2020-07-01 15:30:20 +00001372 num_units = 1
1373 if vca_type == "lxc_proxy_charm":
1374 if element_type == "NS":
1375 num_units = db_nsr.get("config-units") or 1
1376 elif element_type == "VNF":
1377 num_units = db_vnfr.get("config-units") or 1
1378 elif element_type == "VDU":
1379 for v in db_vnfr["vdur"]:
1380 if vdu_id == v["vdu-id-ref"]:
1381 num_units = v.get("config-units") or 1
1382 break
David Garciaaae391f2020-11-09 11:12:54 +01001383 if vca_type != "k8s_proxy_charm":
1384 await self.vca_map[vca_type].install_configuration_sw(
1385 ee_id=ee_id,
1386 artifact_path=artifact_path,
1387 db_dict=db_dict,
1388 config=config,
1389 num_units=num_units,
David Garciac1fe90a2021-03-31 19:12:02 +02001390 vca_id=vca_id,
David Garciaaae391f2020-11-09 11:12:54 +01001391 )
quilesj7e13aeb2019-10-08 13:34:55 +02001392
quilesj63f90042020-01-17 09:53:55 +00001393 # write in db flag of configuration_sw already installed
1394 self.update_db_2("nsrs", nsr_id, {db_update_entry + "config_sw_installed": True})
1395
1396 # add relations for this VCA (wait for other peers related with this VCA)
tierno588547c2020-07-01 15:30:20 +00001397 await self._add_vca_relations(logging_text=logging_text, nsr_id=nsr_id,
David Garciac1fe90a2021-03-31 19:12:02 +02001398 vca_index=vca_index, vca_id=vca_id, vca_type=vca_type)
quilesj63f90042020-01-17 09:53:55 +00001399
quilesj7e13aeb2019-10-08 13:34:55 +02001400 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001401 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001402 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001403 pub_key = None
1404 user = None
tierno588547c2020-07-01 15:30:20 +00001405 # self.logger.debug("get ssh key block")
tierno3bedc9b2019-11-27 15:46:57 +00001406 if deep_get(config_descriptor, ("config-access", "ssh-access", "required")):
tierno588547c2020-07-01 15:30:20 +00001407 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001408 # Needed to inject a ssh key
1409 user = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user"))
1410 step = "Install configuration Software, getting public ssh key"
David Garciac1fe90a2021-03-31 19:12:02 +02001411 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(
1412 ee_id=ee_id,
1413 db_dict=db_dict,
1414 vca_id=vca_id
1415 )
quilesj7e13aeb2019-10-08 13:34:55 +02001416
tiernoacc90452019-12-10 11:06:54 +00001417 step = "Insert public key into VM user={} ssh_key={}".format(user, pub_key)
tierno3bedc9b2019-11-27 15:46:57 +00001418 else:
tierno588547c2020-07-01 15:30:20 +00001419 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001420 step = "Waiting to VM being up and getting IP address"
1421 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001422
tierno3bedc9b2019-11-27 15:46:57 +00001423 # n2vc_redesign STEP 5.1
1424 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001425 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001426 if kdu_name:
1427 rw_mgmt_ip = await self.wait_kdu_up(logging_text, nsr_id, vnfr_id, kdu_name)
1428 else:
1429 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(logging_text, nsr_id, vnfr_id, vdu_id,
1430 vdu_index, user=user, pub_key=pub_key)
tierno5ee02052019-12-05 19:55:02 +00001431 else:
1432 rw_mgmt_ip = None # This is for a NS configuration
tierno3bedc9b2019-11-27 15:46:57 +00001433
1434 self.logger.debug(logging_text + ' VM_ip_address={}'.format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001435
tiernoa5088192019-11-26 16:12:53 +00001436 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001437 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001438
1439 # n2vc_redesign STEP 6 Execute initial config primitive
quilesj7e13aeb2019-10-08 13:34:55 +02001440 step = 'execute initial config primitive'
quilesj3655ae02019-12-12 16:08:35 +00001441
1442 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001443 if initial_config_primitive_list:
1444 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001445
1446 # stage, in function of element type: vdu, kdu, vnf or ns
1447 my_vca = vca_deployed_list[vca_index]
1448 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1449 # VDU or KDU
tiernoe876f672020-02-13 14:34:48 +00001450 stage[0] = 'Stage 3/5: running Day-1 primitives for VDU.'
quilesj3655ae02019-12-12 16:08:35 +00001451 elif my_vca.get("member-vnf-index"):
1452 # VNF
tiernoe876f672020-02-13 14:34:48 +00001453 stage[0] = 'Stage 4/5: running Day-1 primitives for VNF.'
quilesj3655ae02019-12-12 16:08:35 +00001454 else:
1455 # NS
tiernoe876f672020-02-13 14:34:48 +00001456 stage[0] = 'Stage 5/5: running Day-1 primitives for NS.'
quilesj3655ae02019-12-12 16:08:35 +00001457
tiernoc231a872020-01-21 08:49:05 +00001458 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001459 nsr_id=nsr_id,
1460 vca_index=vca_index,
1461 status='EXECUTING PRIMITIVE'
1462 )
1463
1464 self._write_op_status(
1465 op_id=nslcmop_id,
1466 stage=stage
1467 )
1468
tiernoe876f672020-02-13 14:34:48 +00001469 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001470 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001471 # adding information on the vca_deployed if it is a NS execution environment
1472 if not vca_deployed["member-vnf-index"]:
David Garciad4816682019-12-09 14:57:43 +01001473 deploy_params["ns_config_info"] = json.dumps(self._get_ns_config_info(nsr_id))
tiernod8323042019-08-09 11:32:23 +00001474 # TODO check if already done
1475 primitive_params_ = self._map_primitive_params(initial_config_primitive, {}, deploy_params)
tierno3bedc9b2019-11-27 15:46:57 +00001476
tiernod8323042019-08-09 11:32:23 +00001477 step = "execute primitive '{}' params '{}'".format(initial_config_primitive["name"], primitive_params_)
1478 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001479 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001480 ee_id=ee_id,
1481 primitive_name=initial_config_primitive["name"],
1482 params_dict=primitive_params_,
David Garciac1fe90a2021-03-31 19:12:02 +02001483 db_dict=db_dict,
1484 vca_id=vca_id,
quilesj7e13aeb2019-10-08 13:34:55 +02001485 )
tiernoe876f672020-02-13 14:34:48 +00001486 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1487 if check_if_terminated_needed:
1488 if config_descriptor.get('terminate-config-primitive'):
1489 self.update_db_2("nsrs", nsr_id, {db_update_entry + "needed_terminate": True})
1490 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001491
tiernod8323042019-08-09 11:32:23 +00001492 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001493
tiernob996d942020-07-03 14:52:28 +00001494 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001495 if vca_type == "helm" or vca_type == "helm-v3":
tiernob996d942020-07-03 14:52:28 +00001496 prometheus_jobs = await self.add_prometheus_metrics(
1497 ee_id=ee_id,
1498 artifact_path=artifact_path,
1499 ee_config_descriptor=ee_config_descriptor,
1500 vnfr_id=vnfr_id,
1501 nsr_id=nsr_id,
1502 target_ip=rw_mgmt_ip,
1503 )
1504 if prometheus_jobs:
1505 self.update_db_2("nsrs", nsr_id, {db_update_entry + "prometheus_jobs": prometheus_jobs})
1506
quilesj7e13aeb2019-10-08 13:34:55 +02001507 step = "instantiated at VCA"
1508 self.logger.debug(logging_text + step)
1509
tiernoc231a872020-01-21 08:49:05 +00001510 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001511 nsr_id=nsr_id,
1512 vca_index=vca_index,
1513 status='READY'
1514 )
1515
tiernod8323042019-08-09 11:32:23 +00001516 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00001517 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
tiernoe876f672020-02-13 14:34:48 +00001518 if not isinstance(e, (DbException, N2VCException, LcmException, asyncio.CancelledError)):
1519 self.logger.error("Exception while {} : {}".format(step, e), exc_info=True)
tiernoc231a872020-01-21 08:49:05 +00001520 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001521 nsr_id=nsr_id,
1522 vca_index=vca_index,
1523 status='BROKEN'
1524 )
tiernoe876f672020-02-13 14:34:48 +00001525 raise LcmException("{} {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00001526
quilesj4cda56b2019-12-05 10:02:20 +00001527 def _write_ns_status(self, nsr_id: str, ns_state: str, current_operation: str, current_operation_id: str,
tiernoa2143262020-03-27 16:20:40 +00001528 error_description: str = None, error_detail: str = None, other_update: dict = None):
tiernoe876f672020-02-13 14:34:48 +00001529 """
1530 Update db_nsr fields.
1531 :param nsr_id:
1532 :param ns_state:
1533 :param current_operation:
1534 :param current_operation_id:
1535 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00001536 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00001537 :param other_update: Other required changes at database if provided, will be cleared
1538 :return:
1539 """
quilesj4cda56b2019-12-05 10:02:20 +00001540 try:
tiernoe876f672020-02-13 14:34:48 +00001541 db_dict = other_update or {}
1542 db_dict["_admin.nslcmop"] = current_operation_id # for backward compatibility
1543 db_dict["_admin.current-operation"] = current_operation_id
1544 db_dict["_admin.operation-type"] = current_operation if current_operation != "IDLE" else None
quilesj4cda56b2019-12-05 10:02:20 +00001545 db_dict["currentOperation"] = current_operation
1546 db_dict["currentOperationID"] = current_operation_id
1547 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00001548 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00001549
1550 if ns_state:
1551 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00001552 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001553 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001554 self.logger.warn('Error writing NS status, ns={}: {}'.format(nsr_id, e))
1555
tiernoe876f672020-02-13 14:34:48 +00001556 def _write_op_status(self, op_id: str, stage: list = None, error_message: str = None, queuePosition: int = 0,
1557 operation_state: str = None, other_update: dict = None):
quilesj3655ae02019-12-12 16:08:35 +00001558 try:
tiernoe876f672020-02-13 14:34:48 +00001559 db_dict = other_update or {}
quilesj3655ae02019-12-12 16:08:35 +00001560 db_dict['queuePosition'] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00001561 if isinstance(stage, list):
1562 db_dict['stage'] = stage[0]
1563 db_dict['detailed-status'] = " ".join(stage)
1564 elif stage is not None:
1565 db_dict['stage'] = str(stage)
1566
1567 if error_message is not None:
quilesj3655ae02019-12-12 16:08:35 +00001568 db_dict['errorMessage'] = error_message
tiernoe876f672020-02-13 14:34:48 +00001569 if operation_state is not None:
1570 db_dict['operationState'] = operation_state
1571 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00001572 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001573 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001574 self.logger.warn('Error writing OPERATION status for op_id: {} -> {}'.format(op_id, e))
1575
tierno51183952020-04-03 15:48:18 +00001576 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00001577 try:
tierno51183952020-04-03 15:48:18 +00001578 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00001579 # configurationStatus
1580 config_status = db_nsr.get('configurationStatus')
1581 if config_status:
tierno51183952020-04-03 15:48:18 +00001582 db_nsr_update = {"configurationStatus.{}.status".format(index): status for index, v in
1583 enumerate(config_status) if v}
quilesj3655ae02019-12-12 16:08:35 +00001584 # update status
tierno51183952020-04-03 15:48:18 +00001585 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00001586
tiernoe876f672020-02-13 14:34:48 +00001587 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001588 self.logger.warn('Error writing all configuration status, ns={}: {}'.format(nsr_id, e))
1589
quilesj63f90042020-01-17 09:53:55 +00001590 def _write_configuration_status(self, nsr_id: str, vca_index: int, status: str = None,
tierno51183952020-04-03 15:48:18 +00001591 element_under_configuration: str = None, element_type: str = None,
1592 other_update: dict = None):
quilesj3655ae02019-12-12 16:08:35 +00001593
1594 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
1595 # .format(vca_index, status))
1596
1597 try:
1598 db_path = 'configurationStatus.{}.'.format(vca_index)
tierno51183952020-04-03 15:48:18 +00001599 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00001600 if status:
1601 db_dict[db_path + 'status'] = status
quilesj3655ae02019-12-12 16:08:35 +00001602 if element_under_configuration:
1603 db_dict[db_path + 'elementUnderConfiguration'] = element_under_configuration
1604 if element_type:
1605 db_dict[db_path + 'elementType'] = element_type
1606 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001607 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001608 self.logger.warn('Error writing configuration status={}, ns={}, vca_index={}: {}'
1609 .format(status, nsr_id, vca_index, e))
quilesj4cda56b2019-12-05 10:02:20 +00001610
tierno38089af2020-04-16 07:56:58 +00001611 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
1612 """
1613 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
1614 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
1615 Database is used because the result can be obtained from a different LCM worker in case of HA.
1616 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
1617 :param db_nslcmop: database content of nslcmop
1618 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00001619 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
1620 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00001621 """
tierno8790a3d2020-04-23 22:49:52 +00001622 modified = False
tierno38089af2020-04-16 07:56:58 +00001623 nslcmop_id = db_nslcmop['_id']
magnussonle9198bb2020-01-21 13:00:51 +01001624 placement_engine = deep_get(db_nslcmop, ('operationParams', 'placement-engine'))
1625 if placement_engine == "PLA":
tierno38089af2020-04-16 07:56:58 +00001626 self.logger.debug(logging_text + "Invoke and wait for placement optimization")
1627 await self.msg.aiowrite("pla", "get_placement", {'nslcmopId': nslcmop_id}, loop=self.loop)
magnussonle9198bb2020-01-21 13:00:51 +01001628 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00001629 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01001630 pla_result = None
1631 while not pla_result and wait >= 0:
1632 await asyncio.sleep(db_poll_interval)
1633 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00001634 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01001635 pla_result = deep_get(db_nslcmop, ('_admin', 'pla'))
1636
1637 if not pla_result:
tierno38089af2020-04-16 07:56:58 +00001638 raise LcmException("Placement timeout for nslcmopId={}".format(nslcmop_id))
magnussonle9198bb2020-01-21 13:00:51 +01001639
1640 for pla_vnf in pla_result['vnf']:
1641 vnfr = db_vnfrs.get(pla_vnf['member-vnf-index'])
1642 if not pla_vnf.get('vimAccountId') or not vnfr:
1643 continue
tierno8790a3d2020-04-23 22:49:52 +00001644 modified = True
magnussonle9198bb2020-01-21 13:00:51 +01001645 self.db.set_one("vnfrs", {"_id": vnfr["_id"]}, {"vim-account-id": pla_vnf['vimAccountId']})
tierno38089af2020-04-16 07:56:58 +00001646 # Modifies db_vnfrs
1647 vnfr["vim-account-id"] = pla_vnf['vimAccountId']
tierno8790a3d2020-04-23 22:49:52 +00001648 return modified
magnussonle9198bb2020-01-21 13:00:51 +01001649
1650 def update_nsrs_with_pla_result(self, params):
1651 try:
1652 nslcmop_id = deep_get(params, ('placement', 'nslcmopId'))
1653 self.update_db_2("nslcmops", nslcmop_id, {"_admin.pla": params.get('placement')})
1654 except Exception as e:
1655 self.logger.warn('Update failed for nslcmop_id={}:{}'.format(nslcmop_id, e))
1656
tierno59d22d22018-09-25 18:10:19 +02001657 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02001658 """
1659
1660 :param nsr_id: ns instance to deploy
1661 :param nslcmop_id: operation to run
1662 :return:
1663 """
kuused124bfe2019-06-18 12:09:24 +02001664
1665 # Try to lock HA task here
1666 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
1667 if not task_is_locked_by_me:
quilesj3655ae02019-12-12 16:08:35 +00001668 self.logger.debug('instantiate() task is not locked by me, ns={}'.format(nsr_id))
kuused124bfe2019-06-18 12:09:24 +02001669 return
1670
tierno59d22d22018-09-25 18:10:19 +02001671 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
1672 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02001673
tierno59d22d22018-09-25 18:10:19 +02001674 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02001675
1676 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02001677 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02001678
1679 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02001680 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02001681
1682 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00001683 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02001684 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02001685 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02001686
tierno59d22d22018-09-25 18:10:19 +02001687 nslcmop_operation_state = None
quilesj7e13aeb2019-10-08 13:34:55 +02001688 db_vnfrs = {} # vnf's info indexed by member-index
1689 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00001690 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02001691 exc = None
tiernoe876f672020-02-13 14:34:48 +00001692 error_list = []
1693 stage = ['Stage 1/5: preparation of the environment.', "Waiting for previous operations to terminate.", ""]
1694 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02001695 try:
kuused124bfe2019-06-18 12:09:24 +02001696 # wait for any previous tasks in process
1697 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
1698
tiernob5203912020-08-11 11:20:13 +00001699 stage[1] = "Sync filesystem from database."
tierno21e42212020-07-09 13:51:20 +00001700 self.fs.sync() # TODO, make use of partial sync, only for the needed packages
1701
quilesj7e13aeb2019-10-08 13:34:55 +02001702 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00001703 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00001704 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00001705 db_nsr_update["detailed-status"] = "creating"
1706 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00001707 self._write_ns_status(
1708 nsr_id=nsr_id,
1709 ns_state="BUILDING",
1710 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00001711 current_operation_id=nslcmop_id,
1712 other_update=db_nsr_update
1713 )
1714 self._write_op_status(
1715 op_id=nslcmop_id,
1716 stage=stage,
1717 queuePosition=0
quilesj4cda56b2019-12-05 10:02:20 +00001718 )
1719
quilesj7e13aeb2019-10-08 13:34:55 +02001720 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00001721 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02001722 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
tierno744303e2020-01-13 16:46:31 +00001723 ns_params = db_nslcmop.get("operationParams")
1724 if ns_params and ns_params.get("timeout_ns_deploy"):
1725 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1726 else:
1727 timeout_ns_deploy = self.timeout.get("ns_deploy", self.timeout_ns_deploy)
quilesj7e13aeb2019-10-08 13:34:55 +02001728
1729 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00001730 stage[1] = "Getting nsr={} from db.".format(nsr_id)
tierno59d22d22018-09-25 18:10:19 +02001731 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00001732 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00001733 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
1734 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00001735 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02001736
quilesj7e13aeb2019-10-08 13:34:55 +02001737 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00001738 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00001739 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02001740 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02001741
quilesj7e13aeb2019-10-08 13:34:55 +02001742 # read from db: vnfd's for every vnf
bravof922c4172020-11-24 21:21:43 -03001743 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02001744
1745 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02001746 for vnfr in db_vnfrs_list:
bravof922c4172020-11-24 21:21:43 -03001747 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
1748 vnfd_id = vnfr["vnfd-id"]
1749 vnfd_ref = vnfr["vnfd-ref"]
lloretgalleg6d488782020-07-22 10:13:46 +00001750
quilesj7e13aeb2019-10-08 13:34:55 +02001751 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02001752 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00001753 # read from db
tiernob5203912020-08-11 11:20:13 +00001754 stage[1] = "Getting vnfd={} id='{}' from db.".format(vnfd_id, vnfd_ref)
tiernoe876f672020-02-13 14:34:48 +00001755 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02001756 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02001757
quilesj7e13aeb2019-10-08 13:34:55 +02001758 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01001759 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02001760
1761 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00001762 vca_deployed_list = None
1763 if db_nsr["_admin"].get("deployed"):
1764 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
1765 if vca_deployed_list is None:
1766 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00001767 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00001768 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00001769 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02001770 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00001771 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00001772 elif isinstance(vca_deployed_list, dict):
1773 # maintain backward compatibility. Change a dict to list at database
1774 vca_deployed_list = list(vca_deployed_list.values())
1775 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00001776 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00001777
tierno6cf25f52019-09-12 09:33:40 +00001778 if not isinstance(deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list):
tiernoa009e552019-01-30 16:45:44 +00001779 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
1780 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02001781
tiernobaa51102018-12-14 13:16:18 +00001782 # set state to INSTANTIATED. When instantiated NBI will not delete directly
1783 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
1784 self.update_db_2("nsrs", nsr_id, db_nsr_update)
lloretgalleg6d488782020-07-22 10:13:46 +00001785 self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"})
quilesj3655ae02019-12-12 16:08:35 +00001786
1787 # n2vc_redesign STEP 2 Deploy Network Scenario
tiernoe876f672020-02-13 14:34:48 +00001788 stage[0] = 'Stage 2/5: deployment of KDUs, VMs and execution environments.'
quilesj3655ae02019-12-12 16:08:35 +00001789 self._write_op_status(
1790 op_id=nslcmop_id,
tiernoe876f672020-02-13 14:34:48 +00001791 stage=stage
quilesj3655ae02019-12-12 16:08:35 +00001792 )
1793
tiernob5203912020-08-11 11:20:13 +00001794 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00001795 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01001796 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00001797 await self.deploy_kdus(
1798 logging_text=logging_text,
1799 nsr_id=nsr_id,
1800 nslcmop_id=nslcmop_id,
1801 db_vnfrs=db_vnfrs,
1802 db_vnfds=db_vnfds,
1803 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001804 )
tiernoe876f672020-02-13 14:34:48 +00001805
1806 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00001807 # n2vc_redesign STEP 1 Get VCA public ssh-key
1808 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00001809 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00001810 n2vc_key_list = [n2vc_key]
1811 if self.vca_config.get("public_key"):
1812 n2vc_key_list.append(self.vca_config["public_key"])
tierno98ad6ea2019-05-30 17:16:28 +00001813
tiernoe876f672020-02-13 14:34:48 +00001814 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00001815 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02001816 self.instantiate_RO(
1817 logging_text=logging_text,
1818 nsr_id=nsr_id,
1819 nsd=nsd,
1820 db_nsr=db_nsr,
1821 db_nslcmop=db_nslcmop,
1822 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03001823 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00001824 n2vc_key_list=n2vc_key_list,
1825 stage=stage
tierno98ad6ea2019-05-30 17:16:28 +00001826 )
tiernod8323042019-08-09 11:32:23 +00001827 )
1828 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00001829 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00001830
tiernod8323042019-08-09 11:32:23 +00001831 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00001832 stage[1] = "Deploying Execution Environments."
1833 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00001834
tiernod8323042019-08-09 11:32:23 +00001835 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03001836 for vnf_profile in get_vnf_profiles(nsd):
1837 vnfd_id = vnf_profile["vnfd-id"]
1838 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
1839 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00001840 db_vnfr = db_vnfrs[member_vnf_index]
1841 base_folder = vnfd["_admin"]["storage"]
1842 vdu_id = None
1843 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00001844 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001845 kdu_name = None
tierno59d22d22018-09-25 18:10:19 +02001846
tierno8a518872018-12-21 13:42:14 +00001847 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03001848 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00001849 if db_vnfr.get("additionalParamsForVnf"):
bravof922c4172020-11-24 21:21:43 -03001850 deploy_params.update(parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy()))
tierno8a518872018-12-21 13:42:14 +00001851
bravofe5a31bc2021-02-17 19:09:12 -03001852 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00001853 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02001854 self._deploy_n2vc(
tiernoa54150d2019-12-05 17:15:10 +00001855 logging_text=logging_text + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02001856 db_nsr=db_nsr,
1857 db_vnfr=db_vnfr,
1858 nslcmop_id=nslcmop_id,
1859 nsr_id=nsr_id,
1860 nsi_id=nsi_id,
1861 vnfd_id=vnfd_id,
1862 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001863 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001864 member_vnf_index=member_vnf_index,
1865 vdu_index=vdu_index,
1866 vdu_name=vdu_name,
1867 deploy_params=deploy_params,
1868 descriptor_config=descriptor_config,
1869 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00001870 task_instantiation_info=tasks_dict_info,
1871 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001872 )
tierno59d22d22018-09-25 18:10:19 +02001873
1874 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03001875 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00001876 vdu_id = vdud["id"]
bravofe5a31bc2021-02-17 19:09:12 -03001877 descriptor_config = get_configuration(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03001878 vdur = find_in_list(db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id)
1879
tierno626e0152019-11-29 14:16:16 +00001880 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03001881 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00001882 else:
1883 deploy_params_vdu = deploy_params
bravof922c4172020-11-24 21:21:43 -03001884 deploy_params_vdu["OSM"] = get_osm_params(db_vnfr, vdu_id, vdu_count_index=0)
1885 vdud_count = get_vdu_profile(vnfd, vdu_id).get("max-number-of-instances", 1)
1886
1887 self.logger.debug("VDUD > {}".format(vdud))
1888 self.logger.debug("Descriptor config > {}".format(descriptor_config))
tierno588547c2020-07-01 15:30:20 +00001889 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00001890 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001891 kdu_name = None
bravof922c4172020-11-24 21:21:43 -03001892 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00001893 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02001894 self._deploy_n2vc(
tiernoa54150d2019-12-05 17:15:10 +00001895 logging_text=logging_text + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
1896 member_vnf_index, vdu_id, vdu_index),
quilesj7e13aeb2019-10-08 13:34:55 +02001897 db_nsr=db_nsr,
1898 db_vnfr=db_vnfr,
1899 nslcmop_id=nslcmop_id,
1900 nsr_id=nsr_id,
1901 nsi_id=nsi_id,
1902 vnfd_id=vnfd_id,
1903 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001904 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001905 member_vnf_index=member_vnf_index,
1906 vdu_index=vdu_index,
1907 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00001908 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02001909 descriptor_config=descriptor_config,
1910 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001911 task_instantiation_info=tasks_dict_info,
1912 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001913 )
bravof922c4172020-11-24 21:21:43 -03001914 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01001915 kdu_name = kdud["name"]
bravofe5a31bc2021-02-17 19:09:12 -03001916 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00001917 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01001918 vdu_id = None
1919 vdu_index = 0
1920 vdu_name = None
tierno72ef84f2020-10-06 08:22:07 +00001921 kdur = next(x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name)
bravof922c4172020-11-24 21:21:43 -03001922 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00001923 if kdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03001924 deploy_params_kdu = parse_yaml_strings(kdur["additionalParams"])
tierno59d22d22018-09-25 18:10:19 +02001925
calvinosanch9f9c6f22019-11-04 13:37:39 +01001926 self._deploy_n2vc(
1927 logging_text=logging_text,
1928 db_nsr=db_nsr,
1929 db_vnfr=db_vnfr,
1930 nslcmop_id=nslcmop_id,
1931 nsr_id=nsr_id,
1932 nsi_id=nsi_id,
1933 vnfd_id=vnfd_id,
1934 vdu_id=vdu_id,
1935 kdu_name=kdu_name,
1936 member_vnf_index=member_vnf_index,
1937 vdu_index=vdu_index,
1938 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00001939 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001940 descriptor_config=descriptor_config,
1941 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001942 task_instantiation_info=tasks_dict_info,
1943 stage=stage
calvinosanch9f9c6f22019-11-04 13:37:39 +01001944 )
tierno59d22d22018-09-25 18:10:19 +02001945
tierno1b633412019-02-25 16:48:23 +00001946 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00001947 descriptor_config = nsd.get("ns-configuration")
1948 if descriptor_config and descriptor_config.get("juju"):
1949 vnfd_id = None
1950 db_vnfr = None
1951 member_vnf_index = None
1952 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001953 kdu_name = None
tiernod8323042019-08-09 11:32:23 +00001954 vdu_index = 0
1955 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00001956
tiernod8323042019-08-09 11:32:23 +00001957 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01001958 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00001959 if db_nsr.get("additionalParamsForNs"):
bravof922c4172020-11-24 21:21:43 -03001960 deploy_params.update(parse_yaml_strings(db_nsr["additionalParamsForNs"].copy()))
tiernod8323042019-08-09 11:32:23 +00001961 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02001962 self._deploy_n2vc(
1963 logging_text=logging_text,
1964 db_nsr=db_nsr,
1965 db_vnfr=db_vnfr,
1966 nslcmop_id=nslcmop_id,
1967 nsr_id=nsr_id,
1968 nsi_id=nsi_id,
1969 vnfd_id=vnfd_id,
1970 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001971 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001972 member_vnf_index=member_vnf_index,
1973 vdu_index=vdu_index,
1974 vdu_name=vdu_name,
1975 deploy_params=deploy_params,
1976 descriptor_config=descriptor_config,
1977 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001978 task_instantiation_info=tasks_dict_info,
1979 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001980 )
tierno1b633412019-02-25 16:48:23 +00001981
tiernoe876f672020-02-13 14:34:48 +00001982 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00001983
tiernoe876f672020-02-13 14:34:48 +00001984 except (ROclient.ROClientException, DbException, LcmException, N2VCException) as e:
1985 self.logger.error(logging_text + "Exit Exception while '{}': {}".format(stage[1], e))
tierno59d22d22018-09-25 18:10:19 +02001986 exc = e
1987 except asyncio.CancelledError:
tiernoe876f672020-02-13 14:34:48 +00001988 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(stage[1]))
tierno59d22d22018-09-25 18:10:19 +02001989 exc = "Operation was cancelled"
1990 except Exception as e:
1991 exc = traceback.format_exc()
tiernoe876f672020-02-13 14:34:48 +00001992 self.logger.critical(logging_text + "Exit Exception while '{}': {}".format(stage[1], e), exc_info=True)
tierno59d22d22018-09-25 18:10:19 +02001993 finally:
1994 if exc:
tiernoe876f672020-02-13 14:34:48 +00001995 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00001996 try:
tiernoe876f672020-02-13 14:34:48 +00001997 # wait for pending tasks
1998 if tasks_dict_info:
1999 stage[1] = "Waiting for instantiate pending tasks."
2000 self.logger.debug(logging_text + stage[1])
2001 error_list += await self._wait_for_tasks(logging_text, tasks_dict_info, timeout_ns_deploy,
2002 stage, nslcmop_id, nsr_id=nsr_id)
2003 stage[1] = stage[2] = ""
2004 except asyncio.CancelledError:
2005 error_list.append("Cancelled")
2006 # TODO cancel all tasks
2007 except Exception as exc:
2008 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00002009
tiernoe876f672020-02-13 14:34:48 +00002010 # update operation-status
2011 db_nsr_update["operational-status"] = "running"
2012 # let's begin with VCA 'configured' status (later we can change it)
2013 db_nsr_update["config-status"] = "configured"
2014 for task, task_name in tasks_dict_info.items():
2015 if not task.done() or task.cancelled() or task.exception():
2016 if task_name.startswith(self.task_name_deploy_vca):
2017 # A N2VC task is pending
2018 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00002019 else:
tiernoe876f672020-02-13 14:34:48 +00002020 # RO or KDU task is pending
2021 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00002022
tiernoe876f672020-02-13 14:34:48 +00002023 # update status at database
2024 if error_list:
tiernoa2143262020-03-27 16:20:40 +00002025 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00002026 self.logger.error(logging_text + error_detail)
tiernob5203912020-08-11 11:20:13 +00002027 error_description_nslcmop = '{} Detail: {}'.format(stage[0], error_detail)
2028 error_description_nsr = 'Operation: INSTANTIATING.{}, {}'.format(nslcmop_id, stage[0])
quilesj3655ae02019-12-12 16:08:35 +00002029
tiernoa2143262020-03-27 16:20:40 +00002030 db_nsr_update["detailed-status"] = error_description_nsr + " Detail: " + error_detail
tiernoe876f672020-02-13 14:34:48 +00002031 db_nslcmop_update["detailed-status"] = error_detail
2032 nslcmop_operation_state = "FAILED"
2033 ns_state = "BROKEN"
2034 else:
tiernoa2143262020-03-27 16:20:40 +00002035 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00002036 error_description_nsr = error_description_nslcmop = None
2037 ns_state = "READY"
2038 db_nsr_update["detailed-status"] = "Done"
2039 db_nslcmop_update["detailed-status"] = "Done"
2040 nslcmop_operation_state = "COMPLETED"
quilesj4cda56b2019-12-05 10:02:20 +00002041
tiernoe876f672020-02-13 14:34:48 +00002042 if db_nsr:
2043 self._write_ns_status(
2044 nsr_id=nsr_id,
2045 ns_state=ns_state,
2046 current_operation="IDLE",
2047 current_operation_id=None,
2048 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00002049 error_detail=error_detail,
tiernoe876f672020-02-13 14:34:48 +00002050 other_update=db_nsr_update
2051 )
tiernoa17d4f42020-04-28 09:59:23 +00002052 self._write_op_status(
2053 op_id=nslcmop_id,
2054 stage="",
2055 error_message=error_description_nslcmop,
2056 operation_state=nslcmop_operation_state,
2057 other_update=db_nslcmop_update,
2058 )
quilesj3655ae02019-12-12 16:08:35 +00002059
tierno59d22d22018-09-25 18:10:19 +02002060 if nslcmop_operation_state:
2061 try:
2062 await self.msg.aiowrite("ns", "instantiated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tierno8a518872018-12-21 13:42:14 +00002063 "operationState": nslcmop_operation_state},
2064 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02002065 except Exception as e:
2066 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
2067
2068 self.logger.debug(logging_text + "Exit")
2069 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
2070
David Garciac1fe90a2021-03-31 19:12:02 +02002071 async def _add_vca_relations(
2072 self,
2073 logging_text,
2074 nsr_id,
2075 vca_index: int,
2076 timeout: int = 3600,
2077 vca_type: str = None,
2078 vca_id: str = None,
2079 ) -> bool:
quilesj63f90042020-01-17 09:53:55 +00002080
2081 # steps:
2082 # 1. find all relations for this VCA
2083 # 2. wait for other peers related
2084 # 3. add relations
2085
2086 try:
tierno588547c2020-07-01 15:30:20 +00002087 vca_type = vca_type or "lxc_proxy_charm"
quilesj63f90042020-01-17 09:53:55 +00002088
2089 # STEP 1: find all relations for this VCA
2090
2091 # read nsr record
2092 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garcia171f3542020-05-21 16:41:07 +02002093 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
quilesj63f90042020-01-17 09:53:55 +00002094
2095 # this VCA data
2096 my_vca = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))[vca_index]
2097
2098 # read all ns-configuration relations
2099 ns_relations = list()
David Garcia171f3542020-05-21 16:41:07 +02002100 db_ns_relations = deep_get(nsd, ('ns-configuration', 'relation'))
quilesj63f90042020-01-17 09:53:55 +00002101 if db_ns_relations:
2102 for r in db_ns_relations:
2103 # check if this VCA is in the relation
2104 if my_vca.get('member-vnf-index') in\
2105 (r.get('entities')[0].get('id'), r.get('entities')[1].get('id')):
2106 ns_relations.append(r)
2107
2108 # read all vnf-configuration relations
2109 vnf_relations = list()
2110 db_vnfd_list = db_nsr.get('vnfd-id')
2111 if db_vnfd_list:
2112 for vnfd in db_vnfd_list:
aktas45966a02021-05-04 19:32:45 +03002113 db_vnf_relations = None
quilesj63f90042020-01-17 09:53:55 +00002114 db_vnfd = self.db.get_one("vnfds", {"_id": vnfd})
aktas45966a02021-05-04 19:32:45 +03002115 db_vnf_configuration = get_configuration(db_vnfd, db_vnfd["id"])
2116 if db_vnf_configuration:
2117 db_vnf_relations = db_vnf_configuration.get("relation", [])
quilesj63f90042020-01-17 09:53:55 +00002118 if db_vnf_relations:
2119 for r in db_vnf_relations:
2120 # check if this VCA is in the relation
2121 if my_vca.get('vdu_id') in (r.get('entities')[0].get('id'), r.get('entities')[1].get('id')):
2122 vnf_relations.append(r)
2123
2124 # if no relations, terminate
2125 if not ns_relations and not vnf_relations:
2126 self.logger.debug(logging_text + ' No relations')
2127 return True
2128
2129 self.logger.debug(logging_text + ' adding relations\n {}\n {}'.format(ns_relations, vnf_relations))
2130
2131 # add all relations
2132 start = time()
2133 while True:
2134 # check timeout
2135 now = time()
2136 if now - start >= timeout:
2137 self.logger.error(logging_text + ' : timeout adding relations')
2138 return False
2139
2140 # reload nsr from database (we need to update record: _admin.deloyed.VCA)
2141 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
2142
2143 # for each defined NS relation, find the VCA's related
tierno364c4572020-09-14 12:11:32 +00002144 for r in ns_relations.copy():
quilesj63f90042020-01-17 09:53:55 +00002145 from_vca_ee_id = None
2146 to_vca_ee_id = None
2147 from_vca_endpoint = None
2148 to_vca_endpoint = None
2149 vca_list = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))
2150 for vca in vca_list:
2151 if vca.get('member-vnf-index') == r.get('entities')[0].get('id') \
2152 and vca.get('config_sw_installed'):
2153 from_vca_ee_id = vca.get('ee_id')
2154 from_vca_endpoint = r.get('entities')[0].get('endpoint')
2155 if vca.get('member-vnf-index') == r.get('entities')[1].get('id') \
2156 and vca.get('config_sw_installed'):
2157 to_vca_ee_id = vca.get('ee_id')
2158 to_vca_endpoint = r.get('entities')[1].get('endpoint')
2159 if from_vca_ee_id and to_vca_ee_id:
2160 # add relation
tierno588547c2020-07-01 15:30:20 +00002161 await self.vca_map[vca_type].add_relation(
quilesj63f90042020-01-17 09:53:55 +00002162 ee_id_1=from_vca_ee_id,
2163 ee_id_2=to_vca_ee_id,
2164 endpoint_1=from_vca_endpoint,
David Garciac1fe90a2021-03-31 19:12:02 +02002165 endpoint_2=to_vca_endpoint,
2166 vca_id=vca_id,
2167 )
quilesj63f90042020-01-17 09:53:55 +00002168 # remove entry from relations list
2169 ns_relations.remove(r)
2170 else:
2171 # check failed peers
2172 try:
2173 vca_status_list = db_nsr.get('configurationStatus')
2174 if vca_status_list:
2175 for i in range(len(vca_list)):
2176 vca = vca_list[i]
2177 vca_status = vca_status_list[i]
2178 if vca.get('member-vnf-index') == r.get('entities')[0].get('id'):
2179 if vca_status.get('status') == 'BROKEN':
2180 # peer broken: remove relation from list
2181 ns_relations.remove(r)
2182 if vca.get('member-vnf-index') == r.get('entities')[1].get('id'):
2183 if vca_status.get('status') == 'BROKEN':
2184 # peer broken: remove relation from list
2185 ns_relations.remove(r)
2186 except Exception:
2187 # ignore
2188 pass
2189
2190 # for each defined VNF relation, find the VCA's related
tierno364c4572020-09-14 12:11:32 +00002191 for r in vnf_relations.copy():
quilesj63f90042020-01-17 09:53:55 +00002192 from_vca_ee_id = None
2193 to_vca_ee_id = None
2194 from_vca_endpoint = None
2195 to_vca_endpoint = None
2196 vca_list = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))
2197 for vca in vca_list:
David Garcia97be6832020-09-09 15:40:44 +02002198 key_to_check = "vdu_id"
2199 if vca.get("vdu_id") is None:
2200 key_to_check = "vnfd_id"
2201 if vca.get(key_to_check) == r.get('entities')[0].get('id') and vca.get('config_sw_installed'):
quilesj63f90042020-01-17 09:53:55 +00002202 from_vca_ee_id = vca.get('ee_id')
2203 from_vca_endpoint = r.get('entities')[0].get('endpoint')
David Garcia97be6832020-09-09 15:40:44 +02002204 if vca.get(key_to_check) == r.get('entities')[1].get('id') and vca.get('config_sw_installed'):
quilesj63f90042020-01-17 09:53:55 +00002205 to_vca_ee_id = vca.get('ee_id')
2206 to_vca_endpoint = r.get('entities')[1].get('endpoint')
2207 if from_vca_ee_id and to_vca_ee_id:
2208 # add relation
tierno588547c2020-07-01 15:30:20 +00002209 await self.vca_map[vca_type].add_relation(
quilesj63f90042020-01-17 09:53:55 +00002210 ee_id_1=from_vca_ee_id,
2211 ee_id_2=to_vca_ee_id,
2212 endpoint_1=from_vca_endpoint,
David Garciac1fe90a2021-03-31 19:12:02 +02002213 endpoint_2=to_vca_endpoint,
2214 vca_id=vca_id,
2215 )
quilesj63f90042020-01-17 09:53:55 +00002216 # remove entry from relations list
2217 vnf_relations.remove(r)
2218 else:
2219 # check failed peers
2220 try:
2221 vca_status_list = db_nsr.get('configurationStatus')
2222 if vca_status_list:
2223 for i in range(len(vca_list)):
2224 vca = vca_list[i]
2225 vca_status = vca_status_list[i]
2226 if vca.get('vdu_id') == r.get('entities')[0].get('id'):
2227 if vca_status.get('status') == 'BROKEN':
2228 # peer broken: remove relation from list
David Garcia092afbd2020-08-25 13:17:25 +02002229 vnf_relations.remove(r)
quilesj63f90042020-01-17 09:53:55 +00002230 if vca.get('vdu_id') == r.get('entities')[1].get('id'):
2231 if vca_status.get('status') == 'BROKEN':
2232 # peer broken: remove relation from list
David Garcia092afbd2020-08-25 13:17:25 +02002233 vnf_relations.remove(r)
quilesj63f90042020-01-17 09:53:55 +00002234 except Exception:
2235 # ignore
2236 pass
2237
2238 # wait for next try
2239 await asyncio.sleep(5.0)
2240
2241 if not ns_relations and not vnf_relations:
2242 self.logger.debug('Relations added')
2243 break
2244
2245 return True
2246
2247 except Exception as e:
2248 self.logger.warn(logging_text + ' ERROR adding relations: {}'.format(e))
2249 return False
2250
tierno7ecbc342020-09-21 14:05:39 +00002251 async def _install_kdu(self, nsr_id: str, nsr_db_path: str, vnfr_data: dict, kdu_index: int, kdud: dict,
David Garciac1fe90a2021-03-31 19:12:02 +02002252 vnfd: dict, k8s_instance_info: dict, k8params: dict = None, timeout: int = 600,
2253 vca_id: str = None):
lloretgalleg7c121132020-07-08 07:53:22 +00002254
tiernob9018152020-04-16 14:18:24 +00002255 try:
lloretgalleg7c121132020-07-08 07:53:22 +00002256 k8sclustertype = k8s_instance_info["k8scluster-type"]
2257 # Instantiate kdu
2258 db_dict_install = {"collection": "nsrs",
2259 "filter": {"_id": nsr_id},
2260 "path": nsr_db_path}
2261
David Garciad64e2742021-02-25 20:19:18 +01002262 kdu_instance = self.k8scluster_map[k8sclustertype].generate_kdu_instance_name(
2263 db_dict=db_dict_install,
2264 kdu_model=k8s_instance_info["kdu-model"],
David Garcia6d9a7512021-03-05 15:01:54 +01002265 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01002266 )
2267 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
2268 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00002269 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2270 kdu_model=k8s_instance_info["kdu-model"],
2271 atomic=True,
2272 params=k8params,
2273 db_dict=db_dict_install,
2274 timeout=timeout,
2275 kdu_name=k8s_instance_info["kdu-name"],
David Garciad64e2742021-02-25 20:19:18 +01002276 namespace=k8s_instance_info["namespace"],
2277 kdu_instance=kdu_instance,
David Garciac1fe90a2021-03-31 19:12:02 +02002278 vca_id=vca_id,
David Garciad64e2742021-02-25 20:19:18 +01002279 )
lloretgalleg7c121132020-07-08 07:53:22 +00002280 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
2281
2282 # Obtain services to obtain management service ip
2283 services = await self.k8scluster_map[k8sclustertype].get_services(
2284 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2285 kdu_instance=kdu_instance,
2286 namespace=k8s_instance_info["namespace"])
2287
2288 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00002289 vnfr_update_dict = {}
lloretgalleg7c121132020-07-08 07:53:22 +00002290 if services:
tierno7ecbc342020-09-21 14:05:39 +00002291 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
lloretgalleg7c121132020-07-08 07:53:22 +00002292 mgmt_services = [service for service in kdud.get("service", []) if service.get("mgmt-service")]
2293 for mgmt_service in mgmt_services:
2294 for service in services:
2295 if service["name"].startswith(mgmt_service["name"]):
2296 # Mgmt service found, Obtain service ip
2297 ip = service.get("external_ip", service.get("cluster_ip"))
2298 if isinstance(ip, list) and len(ip) == 1:
2299 ip = ip[0]
2300
2301 vnfr_update_dict["kdur.{}.ip-address".format(kdu_index)] = ip
2302
2303 # Check if must update also mgmt ip at the vnf
2304 service_external_cp = mgmt_service.get("external-connection-point-ref")
2305 if service_external_cp:
2306 if deep_get(vnfd, ("mgmt-interface", "cp")) == service_external_cp:
2307 vnfr_update_dict["ip-address"] = ip
2308
2309 break
2310 else:
2311 self.logger.warn("Mgmt service name: {} not found".format(mgmt_service["name"]))
2312
tierno7ecbc342020-09-21 14:05:39 +00002313 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
2314 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00002315
bravof9a256db2021-02-22 18:02:07 -03002316 kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
2317 if kdu_config and kdu_config.get("initial-config-primitive") and \
2318 get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None:
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02002319 initial_config_primitive_list = kdu_config.get("initial-config-primitive")
2320 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
2321
2322 for initial_config_primitive in initial_config_primitive_list:
2323 primitive_params_ = self._map_primitive_params(initial_config_primitive, {}, {})
2324
2325 await asyncio.wait_for(
2326 self.k8scluster_map[k8sclustertype].exec_primitive(
2327 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2328 kdu_instance=kdu_instance,
2329 primitive_name=initial_config_primitive["name"],
David Garciac1fe90a2021-03-31 19:12:02 +02002330 params=primitive_params_, db_dict=db_dict_install,
2331 vca_id=vca_id,
2332 ),
2333 timeout=timeout
2334 )
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02002335
tiernob9018152020-04-16 14:18:24 +00002336 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00002337 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00002338 try:
lloretgalleg7c121132020-07-08 07:53:22 +00002339 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)})
tierno7ecbc342020-09-21 14:05:39 +00002340 self.update_db_2("vnfrs", vnfr_data.get("_id"), {"kdur.{}.status".format(kdu_index): "ERROR"})
tiernob9018152020-04-16 14:18:24 +00002341 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00002342 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00002343 pass
lloretgalleg7c121132020-07-08 07:53:22 +00002344 # reraise original error
2345 raise
2346
2347 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00002348
tiernoe876f672020-02-13 14:34:48 +00002349 async def deploy_kdus(self, logging_text, nsr_id, nslcmop_id, db_vnfrs, db_vnfds, task_instantiation_info):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002350 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00002351
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002352 k8scluster_id_2_uuic = {"helm-chart-v3": {}, "helm-chart": {}, "juju-bundle": {}}
tierno626e0152019-11-29 14:16:16 +00002353
tierno16f4a4e2020-07-20 09:05:51 +00002354 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00002355 nonlocal k8scluster_id_2_uuic
2356 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
2357 return k8scluster_id_2_uuic[cluster_type][cluster_id]
2358
tierno16f4a4e2020-07-20 09:05:51 +00002359 # check if K8scluster is creating and wait look if previous tasks in process
2360 task_name, task_dependency = self.lcm_tasks.lookfor_related("k8scluster", cluster_id)
2361 if task_dependency:
2362 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(task_name, cluster_id)
2363 self.logger.debug(logging_text + text)
2364 await asyncio.wait(task_dependency, timeout=3600)
2365
tierno626e0152019-11-29 14:16:16 +00002366 db_k8scluster = self.db.get_one("k8sclusters", {"_id": cluster_id}, fail_on_empty=False)
2367 if not db_k8scluster:
2368 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00002369
tierno626e0152019-11-29 14:16:16 +00002370 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
2371 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002372 if cluster_type == "helm-chart-v3":
2373 try:
2374 # backward compatibility for existing clusters that have not been initialized for helm v3
2375 k8s_credentials = yaml.safe_dump(db_k8scluster.get("credentials"))
2376 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(k8s_credentials,
2377 reuse_cluster_uuid=cluster_id)
2378 db_k8scluster_update = {}
2379 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
2380 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
2381 db_k8scluster_update["_admin.helm-chart-v3.created"] = uninstall_sw
2382 db_k8scluster_update["_admin.helm-chart-v3.operationalState"] = "ENABLED"
2383 self.update_db_2("k8sclusters", cluster_id, db_k8scluster_update)
2384 except Exception as e:
2385 self.logger.error(logging_text + "error initializing helm-v3 cluster: {}".format(str(e)))
2386 raise LcmException("K8s cluster '{}' has not been initialized for '{}'".format(cluster_id,
2387 cluster_type))
2388 else:
2389 raise LcmException("K8s cluster '{}' has not been initialized for '{}'".
2390 format(cluster_id, cluster_type))
tierno626e0152019-11-29 14:16:16 +00002391 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
2392 return k8s_id
2393
2394 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00002395 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01002396 try:
tierno626e0152019-11-29 14:16:16 +00002397 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01002398 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01002399
tierno626e0152019-11-29 14:16:16 +00002400 index = 0
tiernoe876f672020-02-13 14:34:48 +00002401 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002402 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00002403
tierno626e0152019-11-29 14:16:16 +00002404 for vnfr_data in db_vnfrs.values():
David Garciac1fe90a2021-03-31 19:12:02 +02002405 vca_id = self.get_vca_id(vnfr_data, {})
lloretgalleg7c121132020-07-08 07:53:22 +00002406 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
2407 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03002408 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
quilesjacde94f2020-01-23 10:07:08 +00002409 vnfd_id = vnfr_data.get('vnfd-id')
David Garciad41dbd62020-12-10 12:52:52 +01002410 vnfd_with_id = find_in_list(db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id)
2411 kdud = next(kdud for kdud in vnfd_with_id["kdu"] if kdud["name"] == kdur["kdu-name"])
tiernode1584f2020-04-07 09:07:33 +00002412 namespace = kdur.get("k8s-namespace")
tierno626e0152019-11-29 14:16:16 +00002413 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00002414 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002415 # Default version: helm3, if helm-version is v2 assign v2
2416 k8sclustertype = "helm-chart-v3"
2417 self.logger.debug("kdur: {}".format(kdur))
2418 if kdur.get("helm-version") and kdur.get("helm-version") == "v2":
2419 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00002420 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00002421 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00002422 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00002423 else:
tiernoe876f672020-02-13 14:34:48 +00002424 raise LcmException("kdu type for kdu='{}.{}' is neither helm-chart nor "
2425 "juju-bundle. Maybe an old NBI version is running".
2426 format(vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]))
quilesjacde94f2020-01-23 10:07:08 +00002427 # check if kdumodel is a file and exists
2428 try:
David Garciad41dbd62020-12-10 12:52:52 +01002429 vnfd_with_id = find_in_list(db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id)
2430 storage = deep_get(vnfd_with_id, ('_admin', 'storage'))
tierno51183952020-04-03 15:48:18 +00002431 if storage and storage.get('pkg-dir'): # may be not present if vnfd has not artifacts
2432 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
Dominik Fleischmann010c0e72020-05-18 15:19:11 +02002433 filename = '{}/{}/{}s/{}'.format(storage["folder"], storage["pkg-dir"], k8sclustertype,
tierno51183952020-04-03 15:48:18 +00002434 kdumodel)
2435 if self.fs.file_exists(filename, mode='file') or self.fs.file_exists(filename, mode='dir'):
2436 kdumodel = self.fs.path + filename
2437 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00002438 raise
2439 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00002440 pass
lloretgallegedc5f332020-02-20 11:50:50 +01002441
tiernoe876f672020-02-13 14:34:48 +00002442 k8s_cluster_id = kdur["k8s-cluster"]["id"]
2443 step = "Synchronize repos for k8s cluster '{}'".format(k8s_cluster_id)
tierno16f4a4e2020-07-20 09:05:51 +00002444 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01002445
lloretgalleg7c121132020-07-08 07:53:22 +00002446 # Synchronize repos
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002447 if (k8sclustertype == "helm-chart" and cluster_uuid not in updated_cluster_list)\
2448 or (k8sclustertype == "helm-chart-v3" and cluster_uuid not in updated_v3_cluster_list):
tiernoe876f672020-02-13 14:34:48 +00002449 del_repo_list, added_repo_dict = await asyncio.ensure_future(
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002450 self.k8scluster_map[k8sclustertype].synchronize_repos(cluster_uuid=cluster_uuid))
tiernoe876f672020-02-13 14:34:48 +00002451 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002452 if k8sclustertype == "helm-chart":
2453 unset = {'_admin.helm_charts_added.' + item: None for item in del_repo_list}
2454 updated = {'_admin.helm_charts_added.' +
2455 item: name for item, name in added_repo_dict.items()}
2456 updated_cluster_list.append(cluster_uuid)
2457 elif k8sclustertype == "helm-chart-v3":
2458 unset = {'_admin.helm_charts_v3_added.' + item: None for item in del_repo_list}
2459 updated = {'_admin.helm_charts_v3_added.' +
2460 item: name for item, name in added_repo_dict.items()}
2461 updated_v3_cluster_list.append(cluster_uuid)
2462 self.logger.debug(logging_text + "repos synchronized on k8s cluster "
2463 "'{}' to_delete: {}, to_add: {}".
2464 format(k8s_cluster_id, del_repo_list, added_repo_dict))
tiernoe876f672020-02-13 14:34:48 +00002465 self.db.set_one("k8sclusters", {"_id": k8s_cluster_id}, updated, unset=unset)
lloretgallegedc5f332020-02-20 11:50:50 +01002466
lloretgalleg7c121132020-07-08 07:53:22 +00002467 # Instantiate kdu
tiernoe876f672020-02-13 14:34:48 +00002468 step = "Instantiating KDU {}.{} in k8s cluster {}".format(vnfr_data["member-vnf-index-ref"],
2469 kdur["kdu-name"], k8s_cluster_id)
lloretgalleg7c121132020-07-08 07:53:22 +00002470 k8s_instance_info = {"kdu-instance": None,
2471 "k8scluster-uuid": cluster_uuid,
2472 "k8scluster-type": k8sclustertype,
2473 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
2474 "kdu-name": kdur["kdu-name"],
2475 "kdu-model": kdumodel,
2476 "namespace": namespace}
tiernob9018152020-04-16 14:18:24 +00002477 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00002478 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00002479 self.update_db_2("nsrs", nsr_id, db_nsr_update)
David Garciad41dbd62020-12-10 12:52:52 +01002480 vnfd_with_id = find_in_list(db_vnfds, lambda vnf: vnf["_id"] == vnfd_id)
tiernoa2143262020-03-27 16:20:40 +00002481 task = asyncio.ensure_future(
David Garciad41dbd62020-12-10 12:52:52 +01002482 self._install_kdu(nsr_id, db_path, vnfr_data, kdu_index, kdud, vnfd_with_id,
David Garciac1fe90a2021-03-31 19:12:02 +02002483 k8s_instance_info, k8params=desc_params, timeout=600, vca_id=vca_id))
tiernoe876f672020-02-13 14:34:48 +00002484 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_KDU-{}".format(index), task)
tiernoa2143262020-03-27 16:20:40 +00002485 task_instantiation_info[task] = "Deploying KDU {}".format(kdur["kdu-name"])
tiernoe876f672020-02-13 14:34:48 +00002486
tierno626e0152019-11-29 14:16:16 +00002487 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00002488
tiernoe876f672020-02-13 14:34:48 +00002489 except (LcmException, asyncio.CancelledError):
2490 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01002491 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00002492 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
2493 if isinstance(e, (N2VCException, DbException)):
2494 self.logger.error(logging_text + msg)
2495 else:
2496 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00002497 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01002498 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002499 if db_nsr_update:
2500 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00002501
quilesj7e13aeb2019-10-08 13:34:55 +02002502 def _deploy_n2vc(self, logging_text, db_nsr, db_vnfr, nslcmop_id, nsr_id, nsi_id, vnfd_id, vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01002503 kdu_name, member_vnf_index, vdu_index, vdu_name, deploy_params, descriptor_config,
tiernoe876f672020-02-13 14:34:48 +00002504 base_folder, task_instantiation_info, stage):
quilesj7e13aeb2019-10-08 13:34:55 +02002505 # launch instantiate_N2VC in a asyncio task and register task object
2506 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
2507 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02002508 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00002509
2510 self.logger.debug(logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id))
bravof9a256db2021-02-22 18:02:07 -03002511 if "execution-environment-list" in descriptor_config:
2512 ee_list = descriptor_config.get("execution-environment-list", [])
tierno588547c2020-07-01 15:30:20 +00002513 else: # other types as script are not supported
2514 ee_list = []
2515
2516 for ee_item in ee_list:
2517 self.logger.debug(logging_text + "_deploy_n2vc ee_item juju={}, helm={}".format(ee_item.get('juju'),
2518 ee_item.get("helm-chart")))
tiernoa278b842020-07-08 15:33:55 +00002519 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00002520 if ee_item.get("juju"):
2521 vca_name = ee_item['juju'].get('charm')
2522 vca_type = "lxc_proxy_charm" if ee_item['juju'].get('charm') is not None else "native_charm"
2523 if ee_item['juju'].get('cloud') == "k8s":
2524 vca_type = "k8s_proxy_charm"
2525 elif ee_item['juju'].get('proxy') is False:
2526 vca_type = "native_charm"
2527 elif ee_item.get("helm-chart"):
2528 vca_name = ee_item['helm-chart']
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002529 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
2530 vca_type = "helm"
2531 else:
2532 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00002533 else:
2534 self.logger.debug(logging_text + "skipping non juju neither charm configuration")
quilesj7e13aeb2019-10-08 13:34:55 +02002535 continue
quilesj3655ae02019-12-12 16:08:35 +00002536
tierno588547c2020-07-01 15:30:20 +00002537 vca_index = -1
2538 for vca_index, vca_deployed in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
2539 if not vca_deployed:
2540 continue
2541 if vca_deployed.get("member-vnf-index") == member_vnf_index and \
2542 vca_deployed.get("vdu_id") == vdu_id and \
2543 vca_deployed.get("kdu_name") == kdu_name and \
tiernoa278b842020-07-08 15:33:55 +00002544 vca_deployed.get("vdu_count_index", 0) == vdu_index and \
2545 vca_deployed.get("ee_descriptor_id") == ee_descriptor_id:
tierno588547c2020-07-01 15:30:20 +00002546 break
2547 else:
2548 # not found, create one.
tiernoa278b842020-07-08 15:33:55 +00002549 target = "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
2550 if vdu_id:
2551 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
2552 elif kdu_name:
2553 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00002554 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00002555 "target_element": target,
2556 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00002557 "member-vnf-index": member_vnf_index,
2558 "vdu_id": vdu_id,
2559 "kdu_name": kdu_name,
2560 "vdu_count_index": vdu_index,
2561 "operational-status": "init", # TODO revise
2562 "detailed-status": "", # TODO revise
2563 "step": "initial-deploy", # TODO revise
2564 "vnfd_id": vnfd_id,
2565 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00002566 "type": vca_type,
2567 "ee_descriptor_id": ee_descriptor_id
tierno588547c2020-07-01 15:30:20 +00002568 }
2569 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00002570
tierno588547c2020-07-01 15:30:20 +00002571 # create VCA and configurationStatus in db
2572 db_dict = {
2573 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
2574 "configurationStatus.{}".format(vca_index): dict()
2575 }
2576 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02002577
tierno588547c2020-07-01 15:30:20 +00002578 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
2579
bravof922c4172020-11-24 21:21:43 -03002580 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
2581 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
2582 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
2583
tierno588547c2020-07-01 15:30:20 +00002584 # Launch task
2585 task_n2vc = asyncio.ensure_future(
2586 self.instantiate_N2VC(
2587 logging_text=logging_text,
2588 vca_index=vca_index,
2589 nsi_id=nsi_id,
2590 db_nsr=db_nsr,
2591 db_vnfr=db_vnfr,
2592 vdu_id=vdu_id,
2593 kdu_name=kdu_name,
2594 vdu_index=vdu_index,
2595 deploy_params=deploy_params,
2596 config_descriptor=descriptor_config,
2597 base_folder=base_folder,
2598 nslcmop_id=nslcmop_id,
2599 stage=stage,
2600 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00002601 vca_name=vca_name,
2602 ee_config_descriptor=ee_item
tierno588547c2020-07-01 15:30:20 +00002603 )
quilesj7e13aeb2019-10-08 13:34:55 +02002604 )
tierno588547c2020-07-01 15:30:20 +00002605 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_N2VC-{}".format(vca_index), task_n2vc)
2606 task_instantiation_info[task_n2vc] = self.task_name_deploy_vca + " {}.{}".format(
2607 member_vnf_index or "", vdu_id or "")
tiernobaa51102018-12-14 13:16:18 +00002608
tiernoc9556972019-07-05 15:25:25 +00002609 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02002610 def _create_nslcmop(nsr_id, operation, params):
2611 """
2612 Creates a ns-lcm-opp content to be stored at database.
2613 :param nsr_id: internal id of the instance
2614 :param operation: instantiate, terminate, scale, action, ...
2615 :param params: user parameters for the operation
2616 :return: dictionary following SOL005 format
2617 """
2618 # Raise exception if invalid arguments
2619 if not (nsr_id and operation and params):
2620 raise LcmException(
2621 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided")
2622 now = time()
2623 _id = str(uuid4())
2624 nslcmop = {
2625 "id": _id,
2626 "_id": _id,
2627 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
2628 "operationState": "PROCESSING",
2629 "statusEnteredTime": now,
2630 "nsInstanceId": nsr_id,
2631 "lcmOperationType": operation,
2632 "startTime": now,
2633 "isAutomaticInvocation": False,
2634 "operationParams": params,
2635 "isCancelPending": False,
2636 "links": {
2637 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
2638 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
2639 }
2640 }
2641 return nslcmop
2642
calvinosanch9f9c6f22019-11-04 13:37:39 +01002643 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00002644 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01002645 for key, value in params.items():
2646 if str(value).startswith("!!yaml "):
2647 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01002648 return params
2649
kuuse8b998e42019-07-30 15:22:16 +02002650 def _get_terminate_primitive_params(self, seq, vnf_index):
2651 primitive = seq.get('name')
2652 primitive_params = {}
2653 params = {
2654 "member_vnf_index": vnf_index,
2655 "primitive": primitive,
2656 "primitive_params": primitive_params,
2657 }
2658 desc_params = {}
2659 return self._map_primitive_params(seq, params, desc_params)
2660
kuuseac3a8882019-10-03 10:48:06 +02002661 # sub-operations
2662
tierno51183952020-04-03 15:48:18 +00002663 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
2664 op = deep_get(db_nslcmop, ('_admin', 'operations'), [])[op_index]
2665 if op.get('operationState') == 'COMPLETED':
kuuseac3a8882019-10-03 10:48:06 +02002666 # b. Skip sub-operation
2667 # _ns_execute_primitive() or RO.create_action() will NOT be executed
2668 return self.SUBOPERATION_STATUS_SKIP
2669 else:
tierno7c4e24c2020-05-13 08:41:35 +00002670 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02002671 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00002672 # Update operationState = 'PROCESSING' to indicate a retry.
kuuseac3a8882019-10-03 10:48:06 +02002673 operationState = 'PROCESSING'
2674 detailed_status = 'In progress'
2675 self._update_suboperation_status(
2676 db_nslcmop, op_index, operationState, detailed_status)
2677 # Return the sub-operation index
2678 # _ns_execute_primitive() or RO.create_action() will be called from scale()
2679 # with arguments extracted from the sub-operation
2680 return op_index
2681
2682 # Find a sub-operation where all keys in a matching dictionary must match
2683 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
2684 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00002685 if db_nslcmop and match:
kuuseac3a8882019-10-03 10:48:06 +02002686 op_list = db_nslcmop.get('_admin', {}).get('operations', [])
2687 for i, op in enumerate(op_list):
2688 if all(op.get(k) == match[k] for k in match):
2689 return i
2690 return self.SUBOPERATION_STATUS_NOT_FOUND
2691
2692 # Update status for a sub-operation given its index
2693 def _update_suboperation_status(self, db_nslcmop, op_index, operationState, detailed_status):
2694 # Update DB for HA tasks
2695 q_filter = {'_id': db_nslcmop['_id']}
2696 update_dict = {'_admin.operations.{}.operationState'.format(op_index): operationState,
2697 '_admin.operations.{}.detailed-status'.format(op_index): detailed_status}
2698 self.db.set_one("nslcmops",
2699 q_filter=q_filter,
2700 update_dict=update_dict,
2701 fail_on_empty=False)
2702
2703 # Add sub-operation, return the index of the added sub-operation
2704 # Optionally, set operationState, detailed-status, and operationType
2705 # Status and type are currently set for 'scale' sub-operations:
2706 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
2707 # 'detailed-status' : status message
2708 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
2709 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
tierno2357f4e2020-10-19 16:38:59 +00002710 def _add_suboperation(self, db_nslcmop, vnf_index, vdu_id, vdu_count_index, vdu_name, primitive,
quilesj7e13aeb2019-10-08 13:34:55 +02002711 mapped_primitive_params, operationState=None, detailed_status=None, operationType=None,
kuuseac3a8882019-10-03 10:48:06 +02002712 RO_nsr_id=None, RO_scaling_info=None):
tiernoe876f672020-02-13 14:34:48 +00002713 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02002714 return self.SUBOPERATION_STATUS_NOT_FOUND
2715 # Get the "_admin.operations" list, if it exists
2716 db_nslcmop_admin = db_nslcmop.get('_admin', {})
2717 op_list = db_nslcmop_admin.get('operations')
2718 # Create or append to the "_admin.operations" list
kuuse8b998e42019-07-30 15:22:16 +02002719 new_op = {'member_vnf_index': vnf_index,
2720 'vdu_id': vdu_id,
2721 'vdu_count_index': vdu_count_index,
2722 'primitive': primitive,
2723 'primitive_params': mapped_primitive_params}
kuuseac3a8882019-10-03 10:48:06 +02002724 if operationState:
2725 new_op['operationState'] = operationState
2726 if detailed_status:
2727 new_op['detailed-status'] = detailed_status
2728 if operationType:
2729 new_op['lcmOperationType'] = operationType
2730 if RO_nsr_id:
2731 new_op['RO_nsr_id'] = RO_nsr_id
2732 if RO_scaling_info:
2733 new_op['RO_scaling_info'] = RO_scaling_info
2734 if not op_list:
2735 # No existing operations, create key 'operations' with current operation as first list element
2736 db_nslcmop_admin.update({'operations': [new_op]})
2737 op_list = db_nslcmop_admin.get('operations')
2738 else:
2739 # Existing operations, append operation to list
2740 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02002741
kuuseac3a8882019-10-03 10:48:06 +02002742 db_nslcmop_update = {'_admin.operations': op_list}
2743 self.update_db_2("nslcmops", db_nslcmop['_id'], db_nslcmop_update)
2744 op_index = len(op_list) - 1
2745 return op_index
2746
2747 # Helper methods for scale() sub-operations
2748
2749 # pre-scale/post-scale:
2750 # Check for 3 different cases:
2751 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
2752 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00002753 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
quilesj7e13aeb2019-10-08 13:34:55 +02002754 def _check_or_add_scale_suboperation(self, db_nslcmop, vnf_index, vnf_config_primitive, primitive_params,
2755 operationType, RO_nsr_id=None, RO_scaling_info=None):
kuuseac3a8882019-10-03 10:48:06 +02002756 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00002757 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02002758 operationType = 'SCALE-RO'
2759 match = {
2760 'member_vnf_index': vnf_index,
2761 'RO_nsr_id': RO_nsr_id,
2762 'RO_scaling_info': RO_scaling_info,
2763 }
2764 else:
2765 match = {
2766 'member_vnf_index': vnf_index,
2767 'primitive': vnf_config_primitive,
2768 'primitive_params': primitive_params,
2769 'lcmOperationType': operationType
2770 }
2771 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00002772 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02002773 # a. New sub-operation
2774 # The sub-operation does not exist, add it.
2775 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
2776 # The following parameters are set to None for all kind of scaling:
2777 vdu_id = None
2778 vdu_count_index = None
2779 vdu_name = None
tierno51183952020-04-03 15:48:18 +00002780 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02002781 vnf_config_primitive = None
2782 primitive_params = None
2783 else:
2784 RO_nsr_id = None
2785 RO_scaling_info = None
2786 # Initial status for sub-operation
2787 operationState = 'PROCESSING'
2788 detailed_status = 'In progress'
2789 # Add sub-operation for pre/post-scaling (zero or more operations)
2790 self._add_suboperation(db_nslcmop,
2791 vnf_index,
2792 vdu_id,
2793 vdu_count_index,
2794 vdu_name,
2795 vnf_config_primitive,
2796 primitive_params,
2797 operationState,
2798 detailed_status,
2799 operationType,
2800 RO_nsr_id,
2801 RO_scaling_info)
2802 return self.SUBOPERATION_STATUS_NEW
2803 else:
2804 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
2805 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00002806 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02002807
preethika.pdf7d8e02019-12-10 13:10:48 +00002808 # Function to return execution_environment id
2809
2810 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00002811 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00002812 for vca in vca_deployed_list:
2813 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
2814 return vca["ee_id"]
2815
David Garciac1fe90a2021-03-31 19:12:02 +02002816 async def destroy_N2VC(
2817 self,
2818 logging_text,
2819 db_nslcmop,
2820 vca_deployed,
2821 config_descriptor,
2822 vca_index,
2823 destroy_ee=True,
2824 exec_primitives=True,
2825 scaling_in=False,
2826 vca_id: str = None,
2827 ):
tiernoe876f672020-02-13 14:34:48 +00002828 """
2829 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
2830 :param logging_text:
2831 :param db_nslcmop:
2832 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
2833 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
2834 :param vca_index: index in the database _admin.deployed.VCA
2835 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00002836 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
2837 not executed properly
aktas13251562021-02-12 22:19:10 +03002838 :param scaling_in: True destroys the application, False destroys the model
tiernoe876f672020-02-13 14:34:48 +00002839 :return: None or exception
2840 """
tiernoe876f672020-02-13 14:34:48 +00002841
tierno588547c2020-07-01 15:30:20 +00002842 self.logger.debug(
2843 logging_text + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
2844 vca_index, vca_deployed, config_descriptor, destroy_ee
2845 )
2846 )
2847
2848 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
2849
2850 # execute terminate_primitives
2851 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03002852 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
2853 config_descriptor.get("terminate-config-primitive"), vca_deployed.get("ee_descriptor_id"))
tierno588547c2020-07-01 15:30:20 +00002854 vdu_id = vca_deployed.get("vdu_id")
2855 vdu_count_index = vca_deployed.get("vdu_count_index")
2856 vdu_name = vca_deployed.get("vdu_name")
2857 vnf_index = vca_deployed.get("member-vnf-index")
2858 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00002859 for seq in terminate_primitives:
2860 # For each sequence in list, get primitive and call _ns_execute_primitive()
2861 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
2862 vnf_index, seq.get("name"))
2863 self.logger.debug(logging_text + step)
2864 # Create the primitive for each sequence, i.e. "primitive": "touch"
2865 primitive = seq.get('name')
2866 mapped_primitive_params = self._get_terminate_primitive_params(seq, vnf_index)
tierno588547c2020-07-01 15:30:20 +00002867
2868 # Add sub-operation
2869 self._add_suboperation(db_nslcmop,
2870 vnf_index,
2871 vdu_id,
2872 vdu_count_index,
2873 vdu_name,
2874 primitive,
2875 mapped_primitive_params)
2876 # Sub-operations: Call _ns_execute_primitive() instead of action()
2877 try:
David Garciac1fe90a2021-03-31 19:12:02 +02002878 result, result_detail = await self._ns_execute_primitive(
2879 vca_deployed["ee_id"], primitive,
2880 mapped_primitive_params,
2881 vca_type=vca_type,
2882 vca_id=vca_id,
2883 )
tierno588547c2020-07-01 15:30:20 +00002884 except LcmException:
2885 # this happens when VCA is not deployed. In this case it is not needed to terminate
2886 continue
2887 result_ok = ['COMPLETED', 'PARTIALLY_COMPLETED']
2888 if result not in result_ok:
2889 raise LcmException("terminate_primitive {} for vnf_member_index={} fails with "
2890 "error {}".format(seq.get("name"), vnf_index, result_detail))
2891 # set that this VCA do not need terminated
2892 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(vca_index)
2893 self.update_db_2("nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False})
tiernoe876f672020-02-13 14:34:48 +00002894
tiernob996d942020-07-03 14:52:28 +00002895 if vca_deployed.get("prometheus_jobs") and self.prometheus:
2896 await self.prometheus.update(remove_jobs=vca_deployed["prometheus_jobs"])
2897
tiernoe876f672020-02-13 14:34:48 +00002898 if destroy_ee:
David Garciac1fe90a2021-03-31 19:12:02 +02002899 await self.vca_map[vca_type].delete_execution_environment(
2900 vca_deployed["ee_id"],
2901 scaling_in=scaling_in,
2902 vca_id=vca_id,
2903 )
kuuse0ca67472019-05-13 15:59:27 +02002904
David Garciac1fe90a2021-03-31 19:12:02 +02002905 async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
tierno51183952020-04-03 15:48:18 +00002906 self._write_all_config_status(db_nsr=db_nsr, status='TERMINATING')
2907 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00002908 try:
David Garciac1fe90a2021-03-31 19:12:02 +02002909 await self.n2vc.delete_namespace(
2910 namespace=namespace,
2911 total_timeout=self.timeout_charm_delete,
2912 vca_id=vca_id,
2913 )
tiernof59ad6c2020-04-08 12:50:52 +00002914 except N2VCNotFound: # already deleted. Skip
2915 pass
tierno51183952020-04-03 15:48:18 +00002916 self._write_all_config_status(db_nsr=db_nsr, status='DELETED')
quilesj3655ae02019-12-12 16:08:35 +00002917
tiernoe876f672020-02-13 14:34:48 +00002918 async def _terminate_RO(self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage):
2919 """
2920 Terminates a deployment from RO
2921 :param logging_text:
2922 :param nsr_deployed: db_nsr._admin.deployed
2923 :param nsr_id:
2924 :param nslcmop_id:
2925 :param stage: list of string with the content to write on db_nslcmop.detailed-status.
2926 this method will update only the index 2, but it will write on database the concatenated content of the list
2927 :return:
2928 """
2929 db_nsr_update = {}
2930 failed_detail = []
2931 ro_nsr_id = ro_delete_action = None
2932 if nsr_deployed and nsr_deployed.get("RO"):
2933 ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
2934 ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
2935 try:
2936 if ro_nsr_id:
2937 stage[2] = "Deleting ns from VIM."
2938 db_nsr_update["detailed-status"] = " ".join(stage)
2939 self._write_op_status(nslcmop_id, stage)
2940 self.logger.debug(logging_text + stage[2])
2941 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2942 self._write_op_status(nslcmop_id, stage)
2943 desc = await self.RO.delete("ns", ro_nsr_id)
2944 ro_delete_action = desc["action_id"]
2945 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = ro_delete_action
2946 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
2947 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2948 if ro_delete_action:
2949 # wait until NS is deleted from VIM
2950 stage[2] = "Waiting ns deleted from VIM."
2951 detailed_status_old = None
2952 self.logger.debug(logging_text + stage[2] + " RO_id={} ro_delete_action={}".format(ro_nsr_id,
2953 ro_delete_action))
2954 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2955 self._write_op_status(nslcmop_id, stage)
kuused124bfe2019-06-18 12:09:24 +02002956
tiernoe876f672020-02-13 14:34:48 +00002957 delete_timeout = 20 * 60 # 20 minutes
2958 while delete_timeout > 0:
2959 desc = await self.RO.show(
2960 "ns",
2961 item_id_name=ro_nsr_id,
2962 extra_item="action",
2963 extra_item_id=ro_delete_action)
2964
2965 # deploymentStatus
2966 self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
2967
2968 ns_status, ns_status_info = self.RO.check_action_status(desc)
2969 if ns_status == "ERROR":
2970 raise ROclient.ROClientException(ns_status_info)
2971 elif ns_status == "BUILD":
2972 stage[2] = "Deleting from VIM {}".format(ns_status_info)
2973 elif ns_status == "ACTIVE":
2974 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
2975 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2976 break
2977 else:
2978 assert False, "ROclient.check_action_status returns unknown {}".format(ns_status)
2979 if stage[2] != detailed_status_old:
2980 detailed_status_old = stage[2]
2981 db_nsr_update["detailed-status"] = " ".join(stage)
2982 self._write_op_status(nslcmop_id, stage)
2983 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2984 await asyncio.sleep(5, loop=self.loop)
2985 delete_timeout -= 5
2986 else: # delete_timeout <= 0:
2987 raise ROclient.ROClientException("Timeout waiting ns deleted from VIM")
2988
2989 except Exception as e:
2990 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2991 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2992 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
2993 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2994 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
2995 self.logger.debug(logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id))
2996 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
tiernoa2143262020-03-27 16:20:40 +00002997 failed_detail.append("delete conflict: {}".format(e))
2998 self.logger.debug(logging_text + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e))
tiernoe876f672020-02-13 14:34:48 +00002999 else:
tiernoa2143262020-03-27 16:20:40 +00003000 failed_detail.append("delete error: {}".format(e))
3001 self.logger.error(logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e))
tiernoe876f672020-02-13 14:34:48 +00003002
3003 # Delete nsd
3004 if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
3005 ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
3006 try:
3007 stage[2] = "Deleting nsd from RO."
3008 db_nsr_update["detailed-status"] = " ".join(stage)
3009 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3010 self._write_op_status(nslcmop_id, stage)
3011 await self.RO.delete("nsd", ro_nsd_id)
3012 self.logger.debug(logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id))
3013 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
3014 except Exception as e:
3015 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
3016 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
3017 self.logger.debug(logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id))
3018 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
3019 failed_detail.append("ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e))
3020 self.logger.debug(logging_text + failed_detail[-1])
3021 else:
3022 failed_detail.append("ro_nsd_id={} delete error: {}".format(ro_nsd_id, e))
3023 self.logger.error(logging_text + failed_detail[-1])
3024
3025 if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
3026 for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
3027 if not vnf_deployed or not vnf_deployed["id"]:
3028 continue
3029 try:
3030 ro_vnfd_id = vnf_deployed["id"]
3031 stage[2] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
3032 vnf_deployed["member-vnf-index"], ro_vnfd_id)
3033 db_nsr_update["detailed-status"] = " ".join(stage)
3034 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3035 self._write_op_status(nslcmop_id, stage)
3036 await self.RO.delete("vnfd", ro_vnfd_id)
3037 self.logger.debug(logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id))
3038 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
3039 except Exception as e:
3040 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
3041 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
3042 self.logger.debug(logging_text + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id))
3043 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
3044 failed_detail.append("ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e))
3045 self.logger.debug(logging_text + failed_detail[-1])
3046 else:
3047 failed_detail.append("ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e))
3048 self.logger.error(logging_text + failed_detail[-1])
3049
tiernoa2143262020-03-27 16:20:40 +00003050 if failed_detail:
3051 stage[2] = "Error deleting from VIM"
3052 else:
3053 stage[2] = "Deleted from VIM"
tiernoe876f672020-02-13 14:34:48 +00003054 db_nsr_update["detailed-status"] = " ".join(stage)
3055 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3056 self._write_op_status(nslcmop_id, stage)
3057
3058 if failed_detail:
tiernoa2143262020-03-27 16:20:40 +00003059 raise LcmException("; ".join(failed_detail))
tiernoe876f672020-02-13 14:34:48 +00003060
3061 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003062 # Try to lock HA task here
3063 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3064 if not task_is_locked_by_me:
3065 return
3066
tierno59d22d22018-09-25 18:10:19 +02003067 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
3068 self.logger.debug(logging_text + "Enter")
tiernoe876f672020-02-13 14:34:48 +00003069 timeout_ns_terminate = self.timeout_ns_terminate
tierno59d22d22018-09-25 18:10:19 +02003070 db_nsr = None
3071 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00003072 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02003073 exc = None
tiernoe876f672020-02-13 14:34:48 +00003074 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02003075 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00003076 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00003077 tasks_dict_info = {}
3078 db_nsr_update = {}
3079 stage = ["Stage 1/3: Preparing task.", "Waiting for previous operations to terminate.", ""]
3080 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02003081 try:
kuused124bfe2019-06-18 12:09:24 +02003082 # wait for any previous tasks in process
3083 await self.lcm_tasks.waitfor_related_HA("ns", 'nslcmops', nslcmop_id)
3084
tiernoe876f672020-02-13 14:34:48 +00003085 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
3086 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
3087 operation_params = db_nslcmop.get("operationParams") or {}
3088 if operation_params.get("timeout_ns_terminate"):
3089 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
3090 stage[1] = "Getting nsr={} from db.".format(nsr_id)
3091 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
3092
3093 db_nsr_update["operational-status"] = "terminating"
3094 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00003095 self._write_ns_status(
3096 nsr_id=nsr_id,
3097 ns_state="TERMINATING",
3098 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00003099 current_operation_id=nslcmop_id,
3100 other_update=db_nsr_update
quilesj4cda56b2019-12-05 10:02:20 +00003101 )
quilesj3655ae02019-12-12 16:08:35 +00003102 self._write_op_status(
3103 op_id=nslcmop_id,
tiernoe876f672020-02-13 14:34:48 +00003104 queuePosition=0,
3105 stage=stage
quilesj3655ae02019-12-12 16:08:35 +00003106 )
tiernoe876f672020-02-13 14:34:48 +00003107 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02003108 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
3109 return
tierno59d22d22018-09-25 18:10:19 +02003110
tiernoe876f672020-02-13 14:34:48 +00003111 stage[1] = "Getting vnf descriptors from db."
3112 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02003113 db_vnfrs_dict = {db_vnfr["member-vnf-index-ref"]: db_vnfr for db_vnfr in db_vnfrs_list}
tiernoe876f672020-02-13 14:34:48 +00003114 db_vnfds_from_id = {}
3115 db_vnfds_from_member_index = {}
3116 # Loop over VNFRs
3117 for vnfr in db_vnfrs_list:
3118 vnfd_id = vnfr["vnfd-id"]
3119 if vnfd_id not in db_vnfds_from_id:
3120 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
3121 db_vnfds_from_id[vnfd_id] = vnfd
3122 db_vnfds_from_member_index[vnfr["member-vnf-index-ref"]] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01003123
tiernoe876f672020-02-13 14:34:48 +00003124 # Destroy individual execution environments when there are terminating primitives.
3125 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00003126 # TODO - check before calling _destroy_N2VC
3127 # if not operation_params.get("skip_terminate_primitives"):#
3128 # or not vca.get("needed_terminate"):
3129 stage[0] = "Stage 2/3 execute terminating primitives."
3130 self.logger.debug(logging_text + stage[0])
3131 stage[1] = "Looking execution environment that needs terminate."
3132 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03003133
tierno588547c2020-07-01 15:30:20 +00003134 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00003135 config_descriptor = None
David Garciac1fe90a2021-03-31 19:12:02 +02003136
3137 vca_id = self.get_vca_id(db_vnfrs_dict[vca["member-vnf-index"]], db_nsr)
tierno588547c2020-07-01 15:30:20 +00003138 if not vca or not vca.get("ee_id"):
3139 continue
3140 if not vca.get("member-vnf-index"):
3141 # ns
3142 config_descriptor = db_nsr.get("ns-configuration")
3143 elif vca.get("vdu_id"):
3144 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03003145 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00003146 elif vca.get("kdu_name"):
3147 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
bravofe5a31bc2021-02-17 19:09:12 -03003148 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00003149 else:
bravofe5a31bc2021-02-17 19:09:12 -03003150 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
aktas13251562021-02-12 22:19:10 +03003151 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00003152 vca_type = vca.get("type")
3153 exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and
3154 vca.get("needed_terminate"))
tiernoaebd7da2020-08-07 06:36:38 +00003155 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
3156 # pending native charms
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003157 destroy_ee = True if vca_type in ("helm", "helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00003158 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
3159 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00003160 task = asyncio.ensure_future(
David Garciac1fe90a2021-03-31 19:12:02 +02003161 self.destroy_N2VC(
3162 logging_text,
3163 db_nslcmop,
3164 vca,
3165 config_descriptor,
3166 vca_index,
3167 destroy_ee,
3168 exec_terminate_primitives,
3169 vca_id=vca_id,
3170 )
3171 )
tierno588547c2020-07-01 15:30:20 +00003172 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02003173
tierno588547c2020-07-01 15:30:20 +00003174 # wait for pending tasks of terminate primitives
3175 if tasks_dict_info:
tierno86e33612020-09-16 14:13:06 +00003176 self.logger.debug(logging_text + 'Waiting for tasks {}'.format(list(tasks_dict_info.keys())))
tierno588547c2020-07-01 15:30:20 +00003177 error_list = await self._wait_for_tasks(logging_text, tasks_dict_info,
3178 min(self.timeout_charm_delete, timeout_ns_terminate),
3179 stage, nslcmop_id)
tierno86e33612020-09-16 14:13:06 +00003180 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00003181 if error_list:
3182 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00003183
tiernoe876f672020-02-13 14:34:48 +00003184 # remove All execution environments at once
3185 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00003186
tierno49676be2020-04-07 16:34:35 +00003187 if nsr_deployed.get("VCA"):
3188 stage[1] = "Deleting all execution environments."
3189 self.logger.debug(logging_text + stage[1])
David Garciac1fe90a2021-03-31 19:12:02 +02003190 vca_id = self.get_vca_id({}, db_nsr)
3191 task_delete_ee = asyncio.ensure_future(
3192 asyncio.wait_for(
3193 self._delete_all_N2VC(db_nsr=db_nsr, vca_id=vca_id),
3194 timeout=self.timeout_charm_delete
3195 )
3196 )
tierno49676be2020-04-07 16:34:35 +00003197 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
3198 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02003199
tiernoe876f672020-02-13 14:34:48 +00003200 # Delete from k8scluster
3201 stage[1] = "Deleting KDUs."
3202 self.logger.debug(logging_text + stage[1])
3203 # print(nsr_deployed)
3204 for kdu in get_iterable(nsr_deployed, "K8s"):
3205 if not kdu or not kdu.get("kdu-instance"):
3206 continue
3207 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00003208 if kdu.get("k8scluster-type") in self.k8scluster_map:
David Garciac1fe90a2021-03-31 19:12:02 +02003209 # TODO: Uninstall kdu instances taking into account they could be deployed in different VIMs
3210 vca_id = self.get_vca_id({}, db_nsr)
tiernoe876f672020-02-13 14:34:48 +00003211 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00003212 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
3213 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02003214 kdu_instance=kdu_instance,
3215 vca_id=vca_id,
3216 )
3217 )
tiernoe876f672020-02-13 14:34:48 +00003218 else:
3219 self.logger.error(logging_text + "Unknown k8s deployment type {}".
3220 format(kdu.get("k8scluster-type")))
3221 continue
3222 tasks_dict_info[task_delete_kdu_instance] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02003223
3224 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00003225 stage[1] = "Deleting ns from VIM."
tierno69f0d382020-05-07 13:08:09 +00003226 if self.ng_ro:
3227 task_delete_ro = asyncio.ensure_future(
3228 self._terminate_ng_ro(logging_text, nsr_deployed, nsr_id, nslcmop_id, stage))
3229 else:
3230 task_delete_ro = asyncio.ensure_future(
3231 self._terminate_RO(logging_text, nsr_deployed, nsr_id, nslcmop_id, stage))
tiernoe876f672020-02-13 14:34:48 +00003232 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02003233
tiernoe876f672020-02-13 14:34:48 +00003234 # rest of staff will be done at finally
3235
3236 except (ROclient.ROClientException, DbException, LcmException, N2VCException) as e:
3237 self.logger.error(logging_text + "Exit Exception {}".format(e))
3238 exc = e
3239 except asyncio.CancelledError:
3240 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(stage[1]))
3241 exc = "Operation was cancelled"
3242 except Exception as e:
3243 exc = traceback.format_exc()
3244 self.logger.critical(logging_text + "Exit Exception while '{}': {}".format(stage[1], e), exc_info=True)
3245 finally:
3246 if exc:
3247 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02003248 try:
tiernoe876f672020-02-13 14:34:48 +00003249 # wait for pending tasks
3250 if tasks_dict_info:
3251 stage[1] = "Waiting for terminate pending tasks."
3252 self.logger.debug(logging_text + stage[1])
3253 error_list += await self._wait_for_tasks(logging_text, tasks_dict_info, timeout_ns_terminate,
3254 stage, nslcmop_id)
3255 stage[1] = stage[2] = ""
3256 except asyncio.CancelledError:
3257 error_list.append("Cancelled")
3258 # TODO cancell all tasks
3259 except Exception as exc:
3260 error_list.append(str(exc))
3261 # update status at database
3262 if error_list:
3263 error_detail = "; ".join(error_list)
3264 # self.logger.error(logging_text + error_detail)
tiernob5203912020-08-11 11:20:13 +00003265 error_description_nslcmop = '{} Detail: {}'.format(stage[0], error_detail)
3266 error_description_nsr = 'Operation: TERMINATING.{}, {}.'.format(nslcmop_id, stage[0])
tierno59d22d22018-09-25 18:10:19 +02003267
tierno59d22d22018-09-25 18:10:19 +02003268 db_nsr_update["operational-status"] = "failed"
tiernoa2143262020-03-27 16:20:40 +00003269 db_nsr_update["detailed-status"] = error_description_nsr + " Detail: " + error_detail
tiernoe876f672020-02-13 14:34:48 +00003270 db_nslcmop_update["detailed-status"] = error_detail
3271 nslcmop_operation_state = "FAILED"
3272 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02003273 else:
tiernoa2143262020-03-27 16:20:40 +00003274 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003275 error_description_nsr = error_description_nslcmop = None
3276 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02003277 db_nsr_update["operational-status"] = "terminated"
3278 db_nsr_update["detailed-status"] = "Done"
3279 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
3280 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00003281 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02003282
tiernoe876f672020-02-13 14:34:48 +00003283 if db_nsr:
3284 self._write_ns_status(
3285 nsr_id=nsr_id,
3286 ns_state=ns_state,
3287 current_operation="IDLE",
3288 current_operation_id=None,
3289 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003290 error_detail=error_detail,
tiernoe876f672020-02-13 14:34:48 +00003291 other_update=db_nsr_update
3292 )
tiernoa17d4f42020-04-28 09:59:23 +00003293 self._write_op_status(
3294 op_id=nslcmop_id,
3295 stage="",
3296 error_message=error_description_nslcmop,
3297 operation_state=nslcmop_operation_state,
3298 other_update=db_nslcmop_update,
3299 )
lloretgalleg6d488782020-07-22 10:13:46 +00003300 if ns_state == "NOT_INSTANTIATED":
3301 try:
3302 self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "NOT_INSTANTIATED"})
3303 except DbException as e:
3304 self.logger.warn(logging_text + 'Error writing VNFR status for nsr-id-ref: {} -> {}'.
3305 format(nsr_id, e))
tiernoa17d4f42020-04-28 09:59:23 +00003306 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00003307 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02003308 if nslcmop_operation_state:
3309 try:
3310 await self.msg.aiowrite("ns", "terminated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tiernoc2564fe2019-01-28 16:18:56 +00003311 "operationState": nslcmop_operation_state,
3312 "autoremove": autoremove},
tierno8a518872018-12-21 13:42:14 +00003313 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003314 except Exception as e:
3315 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02003316
tierno59d22d22018-09-25 18:10:19 +02003317 self.logger.debug(logging_text + "Exit")
3318 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
3319
tiernoe876f672020-02-13 14:34:48 +00003320 async def _wait_for_tasks(self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None):
3321 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00003322 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00003323 error_list = []
3324 pending_tasks = list(created_tasks_info.keys())
3325 num_tasks = len(pending_tasks)
3326 num_done = 0
3327 stage[1] = "{}/{}.".format(num_done, num_tasks)
3328 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00003329 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00003330 new_error = None
tiernoe876f672020-02-13 14:34:48 +00003331 _timeout = timeout + time_start - time()
3332 done, pending_tasks = await asyncio.wait(pending_tasks, timeout=_timeout,
3333 return_when=asyncio.FIRST_COMPLETED)
3334 num_done += len(done)
3335 if not done: # Timeout
3336 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00003337 new_error = created_tasks_info[task] + ": Timeout"
3338 error_detail_list.append(new_error)
3339 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00003340 break
3341 for task in done:
3342 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00003343 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00003344 else:
3345 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00003346 if exc:
3347 if isinstance(exc, asyncio.TimeoutError):
3348 exc = "Timeout"
3349 new_error = created_tasks_info[task] + ": {}".format(exc)
3350 error_list.append(created_tasks_info[task])
3351 error_detail_list.append(new_error)
tierno28c63da2020-04-20 16:28:56 +00003352 if isinstance(exc, (str, DbException, N2VCException, ROclient.ROClientException, LcmException,
tierno2357f4e2020-10-19 16:38:59 +00003353 K8sException, NgRoException)):
tierno067e04a2020-03-31 12:53:13 +00003354 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00003355 else:
tierno067e04a2020-03-31 12:53:13 +00003356 exc_traceback = "".join(traceback.format_exception(None, exc, exc.__traceback__))
tierno2357f4e2020-10-19 16:38:59 +00003357 self.logger.error(logging_text + created_tasks_info[task] + " " + exc_traceback)
tierno067e04a2020-03-31 12:53:13 +00003358 else:
3359 self.logger.debug(logging_text + created_tasks_info[task] + ": Done")
tiernoe876f672020-02-13 14:34:48 +00003360 stage[1] = "{}/{}.".format(num_done, num_tasks)
3361 if new_error:
tiernoa2143262020-03-27 16:20:40 +00003362 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00003363 if nsr_id: # update also nsr
tiernoa2143262020-03-27 16:20:40 +00003364 self.update_db_2("nsrs", nsr_id, {"errorDescription": "Error at: " + ", ".join(error_list),
3365 "errorDetail": ". ".join(error_detail_list)})
tiernoe876f672020-02-13 14:34:48 +00003366 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00003367 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00003368
tiernoda1ff8c2020-10-22 14:12:46 +00003369 @staticmethod
3370 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00003371 """
3372 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
3373 The default-value is used. If it is between < > it look for a value at instantiation_params
3374 :param primitive_desc: portion of VNFD/NSD that describes primitive
3375 :param params: Params provided by user
3376 :param instantiation_params: Instantiation params provided by user
3377 :return: a dictionary with the calculated params
3378 """
3379 calculated_params = {}
3380 for parameter in primitive_desc.get("parameter", ()):
3381 param_name = parameter["name"]
3382 if param_name in params:
3383 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00003384 elif "default-value" in parameter or "value" in parameter:
3385 if "value" in parameter:
3386 calculated_params[param_name] = parameter["value"]
3387 else:
3388 calculated_params[param_name] = parameter["default-value"]
3389 if isinstance(calculated_params[param_name], str) and calculated_params[param_name].startswith("<") \
3390 and calculated_params[param_name].endswith(">"):
3391 if calculated_params[param_name][1:-1] in instantiation_params:
3392 calculated_params[param_name] = instantiation_params[calculated_params[param_name][1:-1]]
tiernoda964822019-01-14 15:53:47 +00003393 else:
3394 raise LcmException("Parameter {} needed to execute primitive {} not provided".
tiernod8323042019-08-09 11:32:23 +00003395 format(calculated_params[param_name], primitive_desc["name"]))
tiernoda964822019-01-14 15:53:47 +00003396 else:
3397 raise LcmException("Parameter {} needed to execute primitive {} not provided".
3398 format(param_name, primitive_desc["name"]))
tierno59d22d22018-09-25 18:10:19 +02003399
tiernoda964822019-01-14 15:53:47 +00003400 if isinstance(calculated_params[param_name], (dict, list, tuple)):
bravof922c4172020-11-24 21:21:43 -03003401 calculated_params[param_name] = yaml.safe_dump(calculated_params[param_name],
3402 default_flow_style=True, width=256)
tiernoda964822019-01-14 15:53:47 +00003403 elif isinstance(calculated_params[param_name], str) and calculated_params[param_name].startswith("!!yaml "):
3404 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00003405 if parameter.get("data-type") == "INTEGER":
3406 try:
3407 calculated_params[param_name] = int(calculated_params[param_name])
3408 except ValueError: # error converting string to int
3409 raise LcmException(
3410 "Parameter {} of primitive {} must be integer".format(param_name, primitive_desc["name"]))
3411 elif parameter.get("data-type") == "BOOLEAN":
3412 calculated_params[param_name] = not ((str(calculated_params[param_name])).lower() == 'false')
tiernoc3f2a822019-11-05 13:45:04 +00003413
3414 # add always ns_config_info if primitive name is config
3415 if primitive_desc["name"] == "config":
3416 if "ns_config_info" in instantiation_params:
3417 calculated_params["ns_config_info"] = instantiation_params["ns_config_info"]
tiernoda964822019-01-14 15:53:47 +00003418 return calculated_params
3419
tiernoa278b842020-07-08 15:33:55 +00003420 def _look_for_deployed_vca(self, deployed_vca, member_vnf_index, vdu_id, vdu_count_index, kdu_name=None,
3421 ee_descriptor_id=None):
tiernoe876f672020-02-13 14:34:48 +00003422 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
3423 for vca in deployed_vca:
3424 if not vca:
3425 continue
3426 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
3427 continue
tiernoe876f672020-02-13 14:34:48 +00003428 if vdu_count_index is not None and vdu_count_index != vca["vdu_count_index"]:
3429 continue
3430 if kdu_name and kdu_name != vca["kdu_name"]:
3431 continue
tiernoa278b842020-07-08 15:33:55 +00003432 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
3433 continue
tiernoe876f672020-02-13 14:34:48 +00003434 break
3435 else:
3436 # vca_deployed not found
tiernoa278b842020-07-08 15:33:55 +00003437 raise LcmException("charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
3438 " is not deployed".format(member_vnf_index, vdu_id, vdu_count_index, kdu_name,
3439 ee_descriptor_id))
tiernoe876f672020-02-13 14:34:48 +00003440 # get ee_id
3441 ee_id = vca.get("ee_id")
tierno588547c2020-07-01 15:30:20 +00003442 vca_type = vca.get("type", "lxc_proxy_charm") # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00003443 if not ee_id:
tierno067e04a2020-03-31 12:53:13 +00003444 raise LcmException("charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
tiernoe876f672020-02-13 14:34:48 +00003445 "execution environment"
tierno067e04a2020-03-31 12:53:13 +00003446 .format(member_vnf_index, vdu_id, kdu_name, vdu_count_index))
tierno588547c2020-07-01 15:30:20 +00003447 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00003448
David Garciac1fe90a2021-03-31 19:12:02 +02003449 async def _ns_execute_primitive(
3450 self,
3451 ee_id,
3452 primitive,
3453 primitive_params,
3454 retries=0,
3455 retries_interval=30,
3456 timeout=None,
3457 vca_type=None,
3458 db_dict=None,
3459 vca_id: str = None,
3460 ) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00003461 try:
tierno98ad6ea2019-05-30 17:16:28 +00003462 if primitive == "config":
3463 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00003464
tierno588547c2020-07-01 15:30:20 +00003465 vca_type = vca_type or "lxc_proxy_charm"
3466
quilesj7e13aeb2019-10-08 13:34:55 +02003467 while retries >= 0:
3468 try:
tierno067e04a2020-03-31 12:53:13 +00003469 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00003470 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00003471 ee_id=ee_id,
3472 primitive_name=primitive,
3473 params_dict=primitive_params,
3474 progress_timeout=self.timeout_progress_primitive,
tierno588547c2020-07-01 15:30:20 +00003475 total_timeout=self.timeout_primitive,
David Garciac1fe90a2021-03-31 19:12:02 +02003476 db_dict=db_dict,
3477 vca_id=vca_id,
3478 ),
tierno067e04a2020-03-31 12:53:13 +00003479 timeout=timeout or self.timeout_primitive)
quilesj7e13aeb2019-10-08 13:34:55 +02003480 # execution was OK
3481 break
tierno067e04a2020-03-31 12:53:13 +00003482 except asyncio.CancelledError:
3483 raise
3484 except Exception as e: # asyncio.TimeoutError
3485 if isinstance(e, asyncio.TimeoutError):
3486 e = "Timeout"
quilesj7e13aeb2019-10-08 13:34:55 +02003487 retries -= 1
3488 if retries >= 0:
tierno73d8bd02019-11-18 17:33:27 +00003489 self.logger.debug('Error executing action {} on {} -> {}'.format(primitive, ee_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +02003490 # wait and retry
3491 await asyncio.sleep(retries_interval, loop=self.loop)
tierno73d8bd02019-11-18 17:33:27 +00003492 else:
tierno067e04a2020-03-31 12:53:13 +00003493 return 'FAILED', str(e)
quilesj7e13aeb2019-10-08 13:34:55 +02003494
tiernoe876f672020-02-13 14:34:48 +00003495 return 'COMPLETED', output
quilesj7e13aeb2019-10-08 13:34:55 +02003496
tierno067e04a2020-03-31 12:53:13 +00003497 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003498 raise
quilesj7e13aeb2019-10-08 13:34:55 +02003499 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003500 return 'FAIL', 'Error executing action {}: {}'.format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02003501
ksaikiranr3fde2c72021-03-15 10:39:06 +05303502 async def vca_status_refresh(self, nsr_id, nslcmop_id):
3503 """
3504 Updating the vca_status with latest juju information in nsrs record
3505 :param: nsr_id: Id of the nsr
3506 :param: nslcmop_id: Id of the nslcmop
3507 :return: None
3508 """
3509
3510 self.logger.debug("Task ns={} action={} Enter".format(nsr_id, nslcmop_id))
3511 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garciac1fe90a2021-03-31 19:12:02 +02003512 vca_id = self.get_vca_id({}, db_nsr)
ksaikiranr656b6dd2021-02-19 10:25:18 +05303513 if db_nsr['_admin']['deployed']['K8s']:
3514 for k8s_index, k8s in enumerate(db_nsr['_admin']['deployed']['K8s']):
3515 cluster_uuid, kdu_instance = k8s["k8scluster-uuid"], k8s["kdu-instance"]
David Garciac1fe90a2021-03-31 19:12:02 +02003516 await self._on_update_k8s_db(cluster_uuid, kdu_instance, filter={'_id': nsr_id}, vca_id=vca_id)
ksaikiranr656b6dd2021-02-19 10:25:18 +05303517 else:
3518 for vca_index, _ in enumerate(db_nsr['_admin']['deployed']['VCA']):
3519 table, filter = "nsrs", {"_id": nsr_id}
3520 path = "_admin.deployed.VCA.{}.".format(vca_index)
3521 await self._on_update_n2vc_db(table, filter, path, {})
ksaikiranr3fde2c72021-03-15 10:39:06 +05303522
3523 self.logger.debug("Task ns={} action={} Exit".format(nsr_id, nslcmop_id))
3524 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_vca_status_refresh")
3525
tierno59d22d22018-09-25 18:10:19 +02003526 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003527 # Try to lock HA task here
3528 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3529 if not task_is_locked_by_me:
3530 return
3531
tierno59d22d22018-09-25 18:10:19 +02003532 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
3533 self.logger.debug(logging_text + "Enter")
3534 # get all needed from database
3535 db_nsr = None
3536 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00003537 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02003538 db_nslcmop_update = {}
3539 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00003540 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02003541 exc = None
3542 try:
kuused124bfe2019-06-18 12:09:24 +02003543 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00003544 step = "Waiting for previous operations to terminate"
kuused124bfe2019-06-18 12:09:24 +02003545 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
3546
quilesj4cda56b2019-12-05 10:02:20 +00003547 self._write_ns_status(
3548 nsr_id=nsr_id,
3549 ns_state=None,
3550 current_operation="RUNNING ACTION",
3551 current_operation_id=nslcmop_id
3552 )
3553
tierno59d22d22018-09-25 18:10:19 +02003554 step = "Getting information from database"
3555 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
3556 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernoda964822019-01-14 15:53:47 +00003557
tiernoe4f7e6c2018-11-27 14:55:30 +00003558 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00003559 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02003560 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003561 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00003562 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00003563 primitive = db_nslcmop["operationParams"]["primitive"]
3564 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
3565 timeout_ns_action = db_nslcmop["operationParams"].get("timeout_ns_action", self.timeout_primitive)
tierno59d22d22018-09-25 18:10:19 +02003566
tierno1b633412019-02-25 16:48:23 +00003567 if vnf_index:
3568 step = "Getting vnfr from database"
3569 db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id})
3570 step = "Getting vnfd from database"
3571 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
3572 else:
tierno067e04a2020-03-31 12:53:13 +00003573 step = "Getting nsd from database"
3574 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00003575
David Garciac1fe90a2021-03-31 19:12:02 +02003576 vca_id = self.get_vca_id(db_vnfr, db_nsr)
tierno82974b22018-11-27 21:55:36 +00003577 # for backward compatibility
3578 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
3579 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
3580 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
3581 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3582
tiernoda964822019-01-14 15:53:47 +00003583 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00003584 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00003585 if vdu_id:
bravofe5a31bc2021-02-17 19:09:12 -03003586 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003587 elif kdu_name:
bravofe5a31bc2021-02-17 19:09:12 -03003588 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00003589 elif vnf_index:
bravofe5a31bc2021-02-17 19:09:12 -03003590 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00003591 else:
tiernoa278b842020-07-08 15:33:55 +00003592 descriptor_configuration = db_nsd.get("ns-configuration")
3593
3594 if descriptor_configuration and descriptor_configuration.get("config-primitive"):
3595 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00003596 if config_primitive["name"] == primitive:
3597 config_primitive_desc = config_primitive
3598 break
tiernoda964822019-01-14 15:53:47 +00003599
garciadeblas6bed6b32020-07-20 11:05:42 +00003600 if not config_primitive_desc:
3601 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
3602 raise LcmException("Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".
3603 format(primitive))
3604 primitive_name = primitive
3605 ee_descriptor_id = None
3606 else:
3607 primitive_name = config_primitive_desc.get("execution-environment-primitive", primitive)
3608 ee_descriptor_id = config_primitive_desc.get("execution-environment-ref")
tierno1b633412019-02-25 16:48:23 +00003609
tierno1b633412019-02-25 16:48:23 +00003610 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00003611 if vdu_id:
3612 vdur = next((x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None)
bravof922c4172020-11-24 21:21:43 -03003613 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00003614 elif kdu_name:
3615 kdur = next((x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None)
bravof922c4172020-11-24 21:21:43 -03003616 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00003617 else:
bravof922c4172020-11-24 21:21:43 -03003618 desc_params = parse_yaml_strings(db_vnfr.get("additionalParamsForVnf"))
tierno1b633412019-02-25 16:48:23 +00003619 else:
bravof922c4172020-11-24 21:21:43 -03003620 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
bravofe5a31bc2021-02-17 19:09:12 -03003621 if kdu_name and get_configuration(db_vnfd, kdu_name):
3622 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01003623 actions = set()
David Garciaa1003662021-02-16 21:07:58 +01003624 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01003625 actions.add(primitive["name"])
David Garciaa1003662021-02-16 21:07:58 +01003626 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01003627 actions.add(primitive["name"])
3628 kdu_action = True if primitive_name in actions else False
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003629
tiernoda964822019-01-14 15:53:47 +00003630 # TODO check if ns is in a proper status
tiernoa278b842020-07-08 15:33:55 +00003631 if kdu_name and (primitive_name in ("upgrade", "rollback", "status") or kdu_action):
tierno067e04a2020-03-31 12:53:13 +00003632 # kdur and desc_params already set from before
3633 if primitive_params:
3634 desc_params.update(primitive_params)
3635 # TODO Check if we will need something at vnf level
3636 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
3637 if kdu_name == kdu["kdu-name"] and kdu["member-vnf-index"] == vnf_index:
3638 break
3639 else:
3640 raise LcmException("KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index))
quilesj7e13aeb2019-10-08 13:34:55 +02003641
tierno067e04a2020-03-31 12:53:13 +00003642 if kdu.get("k8scluster-type") not in self.k8scluster_map:
3643 msg = "unknown k8scluster-type '{}'".format(kdu.get("k8scluster-type"))
3644 raise LcmException(msg)
3645
3646 db_dict = {"collection": "nsrs",
3647 "filter": {"_id": nsr_id},
3648 "path": "_admin.deployed.K8s.{}".format(index)}
tiernoa278b842020-07-08 15:33:55 +00003649 self.logger.debug(logging_text + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name))
3650 step = "Executing kdu {}".format(primitive_name)
3651 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00003652 if desc_params.get("kdu_model"):
3653 kdu_model = desc_params.get("kdu_model")
3654 del desc_params["kdu_model"]
3655 else:
3656 kdu_model = kdu.get("kdu-model")
3657 parts = kdu_model.split(sep=":")
3658 if len(parts) == 2:
3659 kdu_model = parts[0]
3660
3661 detailed_status = await asyncio.wait_for(
3662 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
3663 cluster_uuid=kdu.get("k8scluster-uuid"),
3664 kdu_instance=kdu.get("kdu-instance"),
3665 atomic=True, kdu_model=kdu_model,
3666 params=desc_params, db_dict=db_dict,
3667 timeout=timeout_ns_action),
3668 timeout=timeout_ns_action + 10)
3669 self.logger.debug(logging_text + " Upgrade of kdu {} done".format(detailed_status))
tiernoa278b842020-07-08 15:33:55 +00003670 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00003671 detailed_status = await asyncio.wait_for(
3672 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
3673 cluster_uuid=kdu.get("k8scluster-uuid"),
3674 kdu_instance=kdu.get("kdu-instance"),
3675 db_dict=db_dict),
3676 timeout=timeout_ns_action)
tiernoa278b842020-07-08 15:33:55 +00003677 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00003678 detailed_status = await asyncio.wait_for(
3679 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
3680 cluster_uuid=kdu.get("k8scluster-uuid"),
David Garciac1fe90a2021-03-31 19:12:02 +02003681 kdu_instance=kdu.get("kdu-instance"),
3682 vca_id=vca_id,
3683 ),
3684 timeout=timeout_ns_action
3685 )
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003686 else:
3687 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(kdu["kdu-name"], nsr_id)
3688 params = self._map_primitive_params(config_primitive_desc, primitive_params, desc_params)
3689
3690 detailed_status = await asyncio.wait_for(
3691 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
3692 cluster_uuid=kdu.get("k8scluster-uuid"),
3693 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00003694 primitive_name=primitive_name,
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003695 params=params, db_dict=db_dict,
David Garciac1fe90a2021-03-31 19:12:02 +02003696 timeout=timeout_ns_action,
3697 vca_id=vca_id,
3698 ),
3699 timeout=timeout_ns_action
3700 )
tierno067e04a2020-03-31 12:53:13 +00003701
3702 if detailed_status:
3703 nslcmop_operation_state = 'COMPLETED'
3704 else:
3705 detailed_status = ''
3706 nslcmop_operation_state = 'FAILED'
tierno067e04a2020-03-31 12:53:13 +00003707 else:
bravof922c4172020-11-24 21:21:43 -03003708 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"], member_vnf_index=vnf_index,
3709 vdu_id=vdu_id, vdu_count_index=vdu_count_index,
tiernoa278b842020-07-08 15:33:55 +00003710 ee_descriptor_id=ee_descriptor_id)
ksaikiranrb1c9f372021-03-15 11:07:29 +05303711 for vca_index, vca_deployed in enumerate(db_nsr['_admin']['deployed']['VCA']):
3712 if vca_deployed.get("member-vnf-index") == vnf_index:
3713 db_dict = {"collection": "nsrs",
3714 "filter": {"_id": nsr_id},
3715 "path": "_admin.deployed.VCA.{}.".format(vca_index)}
3716 break
tierno067e04a2020-03-31 12:53:13 +00003717 nslcmop_operation_state, detailed_status = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00003718 ee_id,
tiernoa278b842020-07-08 15:33:55 +00003719 primitive=primitive_name,
tierno067e04a2020-03-31 12:53:13 +00003720 primitive_params=self._map_primitive_params(config_primitive_desc, primitive_params, desc_params),
tierno588547c2020-07-01 15:30:20 +00003721 timeout=timeout_ns_action,
3722 vca_type=vca_type,
David Garciac1fe90a2021-03-31 19:12:02 +02003723 db_dict=db_dict,
3724 vca_id=vca_id,
3725 )
tierno067e04a2020-03-31 12:53:13 +00003726
3727 db_nslcmop_update["detailed-status"] = detailed_status
3728 error_description_nslcmop = detailed_status if nslcmop_operation_state == "FAILED" else ""
3729 self.logger.debug(logging_text + " task Done with result {} {}".format(nslcmop_operation_state,
3730 detailed_status))
tierno59d22d22018-09-25 18:10:19 +02003731 return # database update is called inside finally
3732
tiernof59ad6c2020-04-08 12:50:52 +00003733 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02003734 self.logger.error(logging_text + "Exit Exception {}".format(e))
3735 exc = e
3736 except asyncio.CancelledError:
3737 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(step))
3738 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00003739 except asyncio.TimeoutError:
3740 self.logger.error(logging_text + "Timeout while '{}'".format(step))
3741 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02003742 except Exception as e:
3743 exc = traceback.format_exc()
3744 self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
3745 finally:
tierno067e04a2020-03-31 12:53:13 +00003746 if exc:
3747 db_nslcmop_update["detailed-status"] = detailed_status = error_description_nslcmop = \
kuuse0ca67472019-05-13 15:59:27 +02003748 "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00003749 nslcmop_operation_state = "FAILED"
3750 if db_nsr:
3751 self._write_ns_status(
3752 nsr_id=nsr_id,
3753 ns_state=db_nsr["nsState"], # TODO check if degraded. For the moment use previous status
3754 current_operation="IDLE",
3755 current_operation_id=None,
3756 # error_description=error_description_nsr,
3757 # error_detail=error_detail,
3758 other_update=db_nsr_update
3759 )
3760
bravof922c4172020-11-24 21:21:43 -03003761 self._write_op_status(op_id=nslcmop_id, stage="", error_message=error_description_nslcmop,
3762 operation_state=nslcmop_operation_state, other_update=db_nslcmop_update)
tierno067e04a2020-03-31 12:53:13 +00003763
tierno59d22d22018-09-25 18:10:19 +02003764 if nslcmop_operation_state:
3765 try:
3766 await self.msg.aiowrite("ns", "actioned", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tierno8a518872018-12-21 13:42:14 +00003767 "operationState": nslcmop_operation_state},
3768 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003769 except Exception as e:
3770 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
3771 self.logger.debug(logging_text + "Exit")
3772 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00003773 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02003774
3775 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003776 # Try to lock HA task here
3777 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3778 if not task_is_locked_by_me:
3779 return
3780
tierno59d22d22018-09-25 18:10:19 +02003781 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
tierno2357f4e2020-10-19 16:38:59 +00003782 stage = ['', '', '']
aktas13251562021-02-12 22:19:10 +03003783 tasks_dict_info = {}
tierno2357f4e2020-10-19 16:38:59 +00003784 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02003785 self.logger.debug(logging_text + "Enter")
3786 # get all needed from database
3787 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02003788 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00003789 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02003790 exc = None
tierno9ab95942018-10-10 16:44:22 +02003791 # in case of error, indicates what part of scale was failed to put nsr at error status
3792 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02003793 old_operational_status = ""
3794 old_config_status = ""
aktas13251562021-02-12 22:19:10 +03003795 nsi_id = None
tierno59d22d22018-09-25 18:10:19 +02003796 try:
kuused124bfe2019-06-18 12:09:24 +02003797 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00003798 step = "Waiting for previous operations to terminate"
kuused124bfe2019-06-18 12:09:24 +02003799 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
bravof922c4172020-11-24 21:21:43 -03003800 self._write_ns_status(nsr_id=nsr_id, ns_state=None,
3801 current_operation="SCALING", current_operation_id=nslcmop_id)
quilesj4cda56b2019-12-05 10:02:20 +00003802
ikalyvas02d9e7b2019-05-27 18:16:01 +03003803 step = "Getting nslcmop from database"
ikalyvas02d9e7b2019-05-27 18:16:01 +03003804 self.logger.debug(step + " after having waited for previous tasks to be completed")
3805 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03003806
ikalyvas02d9e7b2019-05-27 18:16:01 +03003807 step = "Getting nsr from database"
3808 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03003809 old_operational_status = db_nsr["operational-status"]
3810 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03003811
tierno59d22d22018-09-25 18:10:19 +02003812 step = "Parsing scaling parameters"
3813 db_nsr_update["operational-status"] = "scaling"
3814 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00003815 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003816
3817 #######
3818 nsr_deployed = db_nsr["_admin"].get("deployed")
3819 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tiernoda6fb102019-11-23 00:36:52 +00003820 # vdu_id = db_nslcmop["operationParams"].get("vdu_id")
3821 # vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
3822 # vdu_name = db_nslcmop["operationParams"].get("vdu_name")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003823 #######
3824
tierno59d22d22018-09-25 18:10:19 +02003825 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["member-vnf-index"]
3826 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"]
3827 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00003828 # for backward compatibility
3829 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
3830 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
3831 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
3832 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3833
tierno59d22d22018-09-25 18:10:19 +02003834 step = "Getting vnfr from database"
3835 db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id})
bravof922c4172020-11-24 21:21:43 -03003836
David Garciac1fe90a2021-03-31 19:12:02 +02003837 vca_id = self.get_vca_id(db_vnfr, db_nsr)
3838
tierno59d22d22018-09-25 18:10:19 +02003839 step = "Getting vnfd from database"
3840 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03003841
aktas13251562021-02-12 22:19:10 +03003842 base_folder = db_vnfd["_admin"]["storage"]
3843
tierno59d22d22018-09-25 18:10:19 +02003844 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03003845 scaling_descriptor = find_in_list(
3846 get_scaling_aspect(
3847 db_vnfd
3848 ),
3849 lambda scale_desc: scale_desc["name"] == scaling_group
3850 )
3851 if not scaling_descriptor:
tierno59d22d22018-09-25 18:10:19 +02003852 raise LcmException("input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
3853 "at vnfd:scaling-group-descriptor".format(scaling_group))
ikalyvas02d9e7b2019-05-27 18:16:01 +03003854
tierno15b1cf12019-08-29 13:21:40 +00003855 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03003856 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02003857 nb_scale_op = 0
3858 if not db_nsr["_admin"].get("scaling-group"):
3859 self.update_db_2("nsrs", nsr_id, {"_admin.scaling-group": [{"name": scaling_group, "nb-scale-op": 0}]})
3860 admin_scale_index = 0
3861 else:
3862 for admin_scale_index, admin_scale_info in enumerate(db_nsr["_admin"]["scaling-group"]):
3863 if admin_scale_info["name"] == scaling_group:
3864 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
3865 break
tierno9ab95942018-10-10 16:44:22 +02003866 else: # not found, set index one plus last element and add new entry with the name
3867 admin_scale_index += 1
3868 db_nsr_update["_admin.scaling-group.{}.name".format(admin_scale_index)] = scaling_group
tierno59d22d22018-09-25 18:10:19 +02003869 RO_scaling_info = []
aktas13251562021-02-12 22:19:10 +03003870 VCA_scaling_info = []
tierno59d22d22018-09-25 18:10:19 +02003871 vdu_scaling_info = {"scaling_group_name": scaling_group, "vdu": []}
3872 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03003873 if "aspect-delta-details" not in scaling_descriptor:
3874 raise LcmException(
3875 "Aspect delta details not fount in scaling descriptor {}".format(
3876 scaling_descriptor["name"]
3877 )
3878 )
tierno59d22d22018-09-25 18:10:19 +02003879 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03003880 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02003881
tierno59d22d22018-09-25 18:10:19 +02003882 vdu_scaling_info["scaling_direction"] = "OUT"
3883 vdu_scaling_info["vdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03003884 for delta in deltas:
3885 for vdu_delta in delta["vdu-delta"]:
3886 vdud = get_vdu(db_vnfd, vdu_delta["id"])
aktas13251562021-02-12 22:19:10 +03003887 vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03003888 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
tierno72ef84f2020-10-06 08:22:07 +00003889 if cloud_init_text:
bravof832f8992020-12-07 12:57:31 -03003890 additional_params = self._get_vdu_additional_params(db_vnfr, vdud["id"]) or {}
3891 cloud_init_list = []
3892
3893 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
3894 max_instance_count = 10
3895 if vdu_profile and "max-number-of-instances" in vdu_profile:
3896 max_instance_count = vdu_profile.get("max-number-of-instances", 10)
3897
aktas13251562021-02-12 22:19:10 +03003898 default_instance_num = get_number_of_instances(db_vnfd, vdud["id"])
bravof832f8992020-12-07 12:57:31 -03003899
3900 nb_scale_op += vdu_delta.get("number-of-instances", 1)
3901
aktas13251562021-02-12 22:19:10 +03003902 if nb_scale_op + default_instance_num > max_instance_count:
bravof832f8992020-12-07 12:57:31 -03003903 raise LcmException(
3904 "reached the limit of {} (max-instance-count) "
3905 "scaling-out operations for the "
3906 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
bravof922c4172020-11-24 21:21:43 -03003907 )
bravof832f8992020-12-07 12:57:31 -03003908 for x in range(vdu_delta.get("number-of-instances", 1)):
3909 if cloud_init_text:
3910 # TODO Information of its own ip is not available because db_vnfr is not updated.
3911 additional_params["OSM"] = get_osm_params(
3912 db_vnfr,
3913 vdu_delta["id"],
3914 vdu_index + x
bravof922c4172020-11-24 21:21:43 -03003915 )
bravof832f8992020-12-07 12:57:31 -03003916 cloud_init_list.append(
3917 self._parse_cloud_init(
3918 cloud_init_text,
3919 additional_params,
3920 db_vnfd["id"],
3921 vdud["id"]
3922 )
3923 )
aktas13251562021-02-12 22:19:10 +03003924 VCA_scaling_info.append(
3925 {
3926 "osm_vdu_id": vdu_delta["id"],
3927 "member-vnf-index": vnf_index,
3928 "type": "create",
3929 "vdu_index": vdu_index + x
3930 }
3931 )
bravof832f8992020-12-07 12:57:31 -03003932 RO_scaling_info.append(
3933 {
3934 "osm_vdu_id": vdu_delta["id"],
3935 "member-vnf-index": vnf_index,
3936 "type": "create",
3937 "count": vdu_delta.get("number-of-instances", 1)
3938 }
3939 )
3940 if cloud_init_list:
3941 RO_scaling_info[-1]["cloud_init"] = cloud_init_list
3942 vdu_scaling_info["vdu-create"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
ikalyvas02d9e7b2019-05-27 18:16:01 +03003943
tierno59d22d22018-09-25 18:10:19 +02003944 elif scaling_type == "SCALE_IN":
tierno59d22d22018-09-25 18:10:19 +02003945 if "min-instance-count" in scaling_descriptor and scaling_descriptor["min-instance-count"] is not None:
3946 min_instance_count = int(scaling_descriptor["min-instance-count"])
bravof832f8992020-12-07 12:57:31 -03003947
tierno59d22d22018-09-25 18:10:19 +02003948 vdu_scaling_info["scaling_direction"] = "IN"
3949 vdu_scaling_info["vdu-delete"] = {}
bravof832f8992020-12-07 12:57:31 -03003950 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
3951 for delta in deltas:
3952 for vdu_delta in delta["vdu-delta"]:
aktas13251562021-02-12 22:19:10 +03003953 vdu_index = get_vdur_index(db_vnfr, vdu_delta)
bravof832f8992020-12-07 12:57:31 -03003954 min_instance_count = 0
3955 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
3956 if vdu_profile and "min-number-of-instances" in vdu_profile:
3957 min_instance_count = vdu_profile["min-number-of-instances"]
3958
aktas13251562021-02-12 22:19:10 +03003959 default_instance_num = get_number_of_instances(db_vnfd, vdu_delta["id"])
bravof832f8992020-12-07 12:57:31 -03003960
3961 nb_scale_op -= vdu_delta.get("number-of-instances", 1)
aktas13251562021-02-12 22:19:10 +03003962 if nb_scale_op + default_instance_num < min_instance_count:
bravof832f8992020-12-07 12:57:31 -03003963 raise LcmException(
3964 "reached the limit of {} (min-instance-count) scaling-in operations for the "
3965 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
3966 )
3967 RO_scaling_info.append({"osm_vdu_id": vdu_delta["id"], "member-vnf-index": vnf_index,
aktas13251562021-02-12 22:19:10 +03003968 "type": "delete", "count": vdu_delta.get("number-of-instances", 1),
3969 "vdu_index": vdu_index - 1})
3970 for x in range(vdu_delta.get("number-of-instances", 1)):
3971 VCA_scaling_info.append(
3972 {
3973 "osm_vdu_id": vdu_delta["id"],
3974 "member-vnf-index": vnf_index,
3975 "type": "delete",
3976 "vdu_index": vdu_index - 1 - x
3977 }
3978 )
bravof832f8992020-12-07 12:57:31 -03003979 vdu_scaling_info["vdu-delete"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
tierno59d22d22018-09-25 18:10:19 +02003980
3981 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
tierno27246d82018-09-27 15:59:09 +02003982 vdu_delete = copy(vdu_scaling_info.get("vdu-delete"))
tierno59d22d22018-09-25 18:10:19 +02003983 if vdu_scaling_info["scaling_direction"] == "IN":
3984 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02003985 if vdu_delete.get(vdur["vdu-id-ref"]):
3986 vdu_delete[vdur["vdu-id-ref"]] -= 1
tierno59d22d22018-09-25 18:10:19 +02003987 vdu_scaling_info["vdu"].append({
tierno2357f4e2020-10-19 16:38:59 +00003988 "name": vdur.get("name") or vdur.get("vdu-name"),
tierno59d22d22018-09-25 18:10:19 +02003989 "vdu_id": vdur["vdu-id-ref"],
3990 "interface": []
3991 })
3992 for interface in vdur["interfaces"]:
3993 vdu_scaling_info["vdu"][-1]["interface"].append({
3994 "name": interface["name"],
3995 "ip_address": interface["ip-address"],
3996 "mac_address": interface.get("mac-address"),
3997 })
tierno2357f4e2020-10-19 16:38:59 +00003998 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02003999
kuuseac3a8882019-10-03 10:48:06 +02004000 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02004001 step = "Executing pre-scale vnf-config-primitive"
4002 if scaling_descriptor.get("scaling-config-action"):
4003 for scaling_config_action in scaling_descriptor["scaling-config-action"]:
kuuseac3a8882019-10-03 10:48:06 +02004004 if (scaling_config_action.get("trigger") == "pre-scale-in" and scaling_type == "SCALE_IN") \
4005 or (scaling_config_action.get("trigger") == "pre-scale-out" and scaling_type == "SCALE_OUT"):
tierno59d22d22018-09-25 18:10:19 +02004006 vnf_config_primitive = scaling_config_action["vnf-config-primitive-name-ref"]
4007 step = db_nslcmop_update["detailed-status"] = \
4008 "executing pre-scale scaling-config-action '{}'".format(vnf_config_primitive)
tiernoda964822019-01-14 15:53:47 +00004009
tierno59d22d22018-09-25 18:10:19 +02004010 # look for primitive
bravofe5a31bc2021-02-17 19:09:12 -03004011 for config_primitive in (get_configuration(
4012 db_vnfd, db_vnfd["id"]
4013 ) or {}).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02004014 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02004015 break
4016 else:
4017 raise LcmException(
4018 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00004019 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
tiernoa278b842020-07-08 15:33:55 +00004020 "primitive".format(scaling_group, vnf_config_primitive))
tiernoda964822019-01-14 15:53:47 +00004021
tierno16fedf52019-05-24 08:38:26 +00004022 vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
tiernoda964822019-01-14 15:53:47 +00004023 if db_vnfr.get("additionalParamsForVnf"):
4024 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02004025
tierno9ab95942018-10-10 16:44:22 +02004026 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02004027 db_nsr_update["config-status"] = "configuring pre-scaling"
kuuseac3a8882019-10-03 10:48:06 +02004028 primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params)
4029
tierno7c4e24c2020-05-13 08:41:35 +00004030 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02004031 op_index = self._check_or_add_scale_suboperation(
4032 db_nslcmop, nslcmop_id, vnf_index, vnf_config_primitive, primitive_params, 'PRE-SCALE')
tierno7c4e24c2020-05-13 08:41:35 +00004033 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02004034 # Skip sub-operation
4035 result = 'COMPLETED'
4036 result_detail = 'Done'
4037 self.logger.debug(logging_text +
4038 "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
4039 vnf_config_primitive, result, result_detail))
4040 else:
tierno7c4e24c2020-05-13 08:41:35 +00004041 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02004042 # New sub-operation: Get index of this sub-operation
4043 op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
4044 self.logger.debug(logging_text + "vnf_config_primitive={} New sub-operation".
4045 format(vnf_config_primitive))
4046 else:
tierno7c4e24c2020-05-13 08:41:35 +00004047 # retry: Get registered params for this existing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004048 op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
4049 vnf_index = op.get('member_vnf_index')
4050 vnf_config_primitive = op.get('primitive')
4051 primitive_params = op.get('primitive_params')
tierno7c4e24c2020-05-13 08:41:35 +00004052 self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry".
kuuseac3a8882019-10-03 10:48:06 +02004053 format(vnf_config_primitive))
tierno588547c2020-07-01 15:30:20 +00004054 # Execute the primitive, either with new (first-time) or registered (reintent) args
tiernoa278b842020-07-08 15:33:55 +00004055 ee_descriptor_id = config_primitive.get("execution-environment-ref")
4056 primitive_name = config_primitive.get("execution-environment-primitive",
4057 vnf_config_primitive)
tierno588547c2020-07-01 15:30:20 +00004058 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"],
4059 member_vnf_index=vnf_index,
4060 vdu_id=None,
tiernoa278b842020-07-08 15:33:55 +00004061 vdu_count_index=None,
4062 ee_descriptor_id=ee_descriptor_id)
kuuseac3a8882019-10-03 10:48:06 +02004063 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02004064 ee_id, primitive_name,
4065 primitive_params,
4066 vca_type=vca_type,
4067 vca_id=vca_id,
4068 )
kuuseac3a8882019-10-03 10:48:06 +02004069 self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format(
4070 vnf_config_primitive, result, result_detail))
4071 # Update operationState = COMPLETED | FAILED
4072 self._update_suboperation_status(
4073 db_nslcmop, op_index, result, result_detail)
4074
tierno59d22d22018-09-25 18:10:19 +02004075 if result == "FAILED":
4076 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02004077 db_nsr_update["config-status"] = old_config_status
4078 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02004079 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02004080
tierno2357f4e2020-10-19 16:38:59 +00004081 db_nsr_update["_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)] = nb_scale_op
4082 db_nsr_update["_admin.scaling-group.{}.time".format(admin_scale_index)] = time()
4083
aktas13251562021-02-12 22:19:10 +03004084 # SCALE-IN VCA - BEGIN
4085 if VCA_scaling_info:
4086 step = db_nslcmop_update["detailed-status"] = \
4087 "Deleting the execution environments"
4088 scale_process = "VCA"
4089 for vdu_info in VCA_scaling_info:
4090 if vdu_info["type"] == "delete":
4091 member_vnf_index = str(vdu_info["member-vnf-index"])
4092 self.logger.debug(logging_text + "vdu info: {}".format(vdu_info))
4093 vdu_id = vdu_info["osm_vdu_id"]
4094 vdu_index = int(vdu_info["vdu_index"])
4095 stage[1] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
4096 member_vnf_index, vdu_id, vdu_index)
4097 stage[2] = step = "Scaling in VCA"
4098 self._write_op_status(
4099 op_id=nslcmop_id,
4100 stage=stage
4101 )
4102 vca_update = db_nsr["_admin"]["deployed"]["VCA"]
4103 config_update = db_nsr["configurationStatus"]
4104 for vca_index, vca in enumerate(vca_update):
4105 if (vca or vca.get("ee_id")) and vca["member-vnf-index"] == member_vnf_index and \
4106 vca["vdu_count_index"] == vdu_index:
4107 if vca.get("vdu_id"):
4108 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
4109 elif vca.get("kdu_name"):
4110 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
4111 else:
4112 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
4113 operation_params = db_nslcmop.get("operationParams") or {}
4114 exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and
4115 vca.get("needed_terminate"))
David Garciac1fe90a2021-03-31 19:12:02 +02004116 task = asyncio.ensure_future(
4117 asyncio.wait_for(
4118 self.destroy_N2VC(
4119 logging_text,
4120 db_nslcmop,
4121 vca,
4122 config_descriptor,
4123 vca_index,
4124 destroy_ee=True,
4125 exec_primitives=exec_terminate_primitives,
4126 scaling_in=True,
4127 vca_id=vca_id,
4128 ),
4129 timeout=self.timeout_charm_delete
4130 )
4131 )
aktas13251562021-02-12 22:19:10 +03004132 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
4133 del vca_update[vca_index]
4134 del config_update[vca_index]
4135 # wait for pending tasks of terminate primitives
4136 if tasks_dict_info:
4137 self.logger.debug(logging_text +
4138 'Waiting for tasks {}'.format(list(tasks_dict_info.keys())))
4139 error_list = await self._wait_for_tasks(logging_text, tasks_dict_info,
4140 min(self.timeout_charm_delete,
4141 self.timeout_ns_terminate),
4142 stage, nslcmop_id)
4143 tasks_dict_info.clear()
4144 if error_list:
4145 raise LcmException("; ".join(error_list))
4146
4147 db_vca_and_config_update = {
4148 "_admin.deployed.VCA": vca_update,
4149 "configurationStatus": config_update
4150 }
4151 self.update_db_2("nsrs", db_nsr["_id"], db_vca_and_config_update)
4152 scale_process = None
4153 # SCALE-IN VCA - END
4154
kuuseac3a8882019-10-03 10:48:06 +02004155 # SCALE RO - BEGIN
tierno59d22d22018-09-25 18:10:19 +02004156 if RO_scaling_info:
tierno9ab95942018-10-10 16:44:22 +02004157 scale_process = "RO"
tierno2357f4e2020-10-19 16:38:59 +00004158 if self.ro_config.get("ng"):
4159 await self._scale_ng_ro(logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage)
tierno2357f4e2020-10-19 16:38:59 +00004160 vdu_scaling_info.pop("vdu-create", None)
4161 vdu_scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02004162
tierno9ab95942018-10-10 16:44:22 +02004163 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02004164 if db_nsr_update:
4165 self.update_db_2("nsrs", nsr_id, db_nsr_update)
aktas13251562021-02-12 22:19:10 +03004166 # SCALE RO - END
4167
4168 # SCALE-UP VCA - BEGIN
4169 if VCA_scaling_info:
4170 step = db_nslcmop_update["detailed-status"] = \
4171 "Creating new execution environments"
4172 scale_process = "VCA"
4173 for vdu_info in VCA_scaling_info:
4174 if vdu_info["type"] == "create":
4175 member_vnf_index = str(vdu_info["member-vnf-index"])
4176 self.logger.debug(logging_text + "vdu info: {}".format(vdu_info))
4177 vnfd_id = db_vnfr["vnfd-ref"]
4178 vdu_index = int(vdu_info["vdu_index"])
4179 deploy_params = {"OSM": get_osm_params(db_vnfr)}
4180 if db_vnfr.get("additionalParamsForVnf"):
4181 deploy_params.update(parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy()))
4182 descriptor_config = get_configuration(db_vnfd, db_vnfd["id"])
4183 if descriptor_config:
4184 vdu_id = None
4185 vdu_name = None
4186 kdu_name = None
4187 self._deploy_n2vc(
4188 logging_text=logging_text + "member_vnf_index={} ".format(member_vnf_index),
4189 db_nsr=db_nsr,
4190 db_vnfr=db_vnfr,
4191 nslcmop_id=nslcmop_id,
4192 nsr_id=nsr_id,
4193 nsi_id=nsi_id,
4194 vnfd_id=vnfd_id,
4195 vdu_id=vdu_id,
4196 kdu_name=kdu_name,
4197 member_vnf_index=member_vnf_index,
4198 vdu_index=vdu_index,
4199 vdu_name=vdu_name,
4200 deploy_params=deploy_params,
4201 descriptor_config=descriptor_config,
4202 base_folder=base_folder,
4203 task_instantiation_info=tasks_dict_info,
4204 stage=stage
4205 )
4206 vdu_id = vdu_info["osm_vdu_id"]
4207 vdur = find_in_list(db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id)
4208 descriptor_config = get_configuration(db_vnfd, vdu_id)
4209 if vdur.get("additionalParams"):
4210 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
4211 else:
4212 deploy_params_vdu = deploy_params
4213 deploy_params_vdu["OSM"] = get_osm_params(db_vnfr, vdu_id, vdu_count_index=vdu_index)
4214 if descriptor_config:
4215 vdu_name = None
4216 kdu_name = None
4217 stage[1] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
4218 member_vnf_index, vdu_id, vdu_index)
4219 stage[2] = step = "Scaling out VCA"
4220 self._write_op_status(
4221 op_id=nslcmop_id,
4222 stage=stage
4223 )
4224 self._deploy_n2vc(
4225 logging_text=logging_text + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
4226 member_vnf_index, vdu_id, vdu_index),
4227 db_nsr=db_nsr,
4228 db_vnfr=db_vnfr,
4229 nslcmop_id=nslcmop_id,
4230 nsr_id=nsr_id,
4231 nsi_id=nsi_id,
4232 vnfd_id=vnfd_id,
4233 vdu_id=vdu_id,
4234 kdu_name=kdu_name,
4235 member_vnf_index=member_vnf_index,
4236 vdu_index=vdu_index,
4237 vdu_name=vdu_name,
4238 deploy_params=deploy_params_vdu,
4239 descriptor_config=descriptor_config,
4240 base_folder=base_folder,
4241 task_instantiation_info=tasks_dict_info,
4242 stage=stage
4243 )
aktas13251562021-02-12 22:19:10 +03004244 # SCALE-UP VCA - END
4245 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02004246
kuuseac3a8882019-10-03 10:48:06 +02004247 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02004248 # execute primitive service POST-SCALING
4249 step = "Executing post-scale vnf-config-primitive"
4250 if scaling_descriptor.get("scaling-config-action"):
4251 for scaling_config_action in scaling_descriptor["scaling-config-action"]:
kuuseac3a8882019-10-03 10:48:06 +02004252 if (scaling_config_action.get("trigger") == "post-scale-in" and scaling_type == "SCALE_IN") \
4253 or (scaling_config_action.get("trigger") == "post-scale-out" and scaling_type == "SCALE_OUT"):
tierno59d22d22018-09-25 18:10:19 +02004254 vnf_config_primitive = scaling_config_action["vnf-config-primitive-name-ref"]
4255 step = db_nslcmop_update["detailed-status"] = \
4256 "executing post-scale scaling-config-action '{}'".format(vnf_config_primitive)
tiernoda964822019-01-14 15:53:47 +00004257
tierno589befb2019-05-29 07:06:23 +00004258 vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
tiernoda964822019-01-14 15:53:47 +00004259 if db_vnfr.get("additionalParamsForVnf"):
4260 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
4261
tierno59d22d22018-09-25 18:10:19 +02004262 # look for primitive
bravof9a256db2021-02-22 18:02:07 -03004263 for config_primitive in (
4264 get_configuration(db_vnfd, db_vnfd["id"]) or {}
4265 ).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02004266 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02004267 break
4268 else:
tiernoa278b842020-07-08 15:33:55 +00004269 raise LcmException(
4270 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
4271 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
4272 "config-primitive".format(scaling_group, vnf_config_primitive))
tierno9ab95942018-10-10 16:44:22 +02004273 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02004274 db_nsr_update["config-status"] = "configuring post-scaling"
kuuseac3a8882019-10-03 10:48:06 +02004275 primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params)
tiernod6de1992018-10-11 13:05:52 +02004276
tierno7c4e24c2020-05-13 08:41:35 +00004277 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02004278 op_index = self._check_or_add_scale_suboperation(
4279 db_nslcmop, nslcmop_id, vnf_index, vnf_config_primitive, primitive_params, 'POST-SCALE')
quilesj4cda56b2019-12-05 10:02:20 +00004280 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02004281 # Skip sub-operation
4282 result = 'COMPLETED'
4283 result_detail = 'Done'
4284 self.logger.debug(logging_text +
4285 "vnf_config_primitive={} Skipped sub-operation, result {} {}".
4286 format(vnf_config_primitive, result, result_detail))
4287 else:
quilesj4cda56b2019-12-05 10:02:20 +00004288 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02004289 # New sub-operation: Get index of this sub-operation
4290 op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
4291 self.logger.debug(logging_text + "vnf_config_primitive={} New sub-operation".
4292 format(vnf_config_primitive))
4293 else:
tierno7c4e24c2020-05-13 08:41:35 +00004294 # retry: Get registered params for this existing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02004295 op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
4296 vnf_index = op.get('member_vnf_index')
4297 vnf_config_primitive = op.get('primitive')
4298 primitive_params = op.get('primitive_params')
tierno7c4e24c2020-05-13 08:41:35 +00004299 self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry".
kuuseac3a8882019-10-03 10:48:06 +02004300 format(vnf_config_primitive))
tierno588547c2020-07-01 15:30:20 +00004301 # Execute the primitive, either with new (first-time) or registered (reintent) args
tiernoa278b842020-07-08 15:33:55 +00004302 ee_descriptor_id = config_primitive.get("execution-environment-ref")
4303 primitive_name = config_primitive.get("execution-environment-primitive",
4304 vnf_config_primitive)
tierno588547c2020-07-01 15:30:20 +00004305 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"],
4306 member_vnf_index=vnf_index,
4307 vdu_id=None,
tiernoa278b842020-07-08 15:33:55 +00004308 vdu_count_index=None,
4309 ee_descriptor_id=ee_descriptor_id)
kuuseac3a8882019-10-03 10:48:06 +02004310 result, result_detail = await self._ns_execute_primitive(
David Garciac1fe90a2021-03-31 19:12:02 +02004311 ee_id,
4312 primitive_name,
4313 primitive_params,
4314 vca_type=vca_type,
4315 vca_id=vca_id,
4316 )
kuuseac3a8882019-10-03 10:48:06 +02004317 self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format(
4318 vnf_config_primitive, result, result_detail))
4319 # Update operationState = COMPLETED | FAILED
4320 self._update_suboperation_status(
4321 db_nslcmop, op_index, result, result_detail)
4322
tierno59d22d22018-09-25 18:10:19 +02004323 if result == "FAILED":
4324 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02004325 db_nsr_update["config-status"] = old_config_status
4326 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02004327 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02004328
tiernod6de1992018-10-11 13:05:52 +02004329 db_nsr_update["detailed-status"] = "" # "scaled {} {}".format(scaling_group, scaling_type)
ikalyvas02d9e7b2019-05-27 18:16:01 +03004330 db_nsr_update["operational-status"] = "running" if old_operational_status == "failed" \
4331 else old_operational_status
tiernod6de1992018-10-11 13:05:52 +02004332 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02004333 return
tierno2357f4e2020-10-19 16:38:59 +00004334 except (ROclient.ROClientException, DbException, LcmException, NgRoException) as e:
tierno59d22d22018-09-25 18:10:19 +02004335 self.logger.error(logging_text + "Exit Exception {}".format(e))
4336 exc = e
4337 except asyncio.CancelledError:
4338 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(step))
4339 exc = "Operation was cancelled"
4340 except Exception as e:
4341 exc = traceback.format_exc()
4342 self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
4343 finally:
bravof922c4172020-11-24 21:21:43 -03004344 self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE", current_operation_id=None)
aktas13251562021-02-12 22:19:10 +03004345 if tasks_dict_info:
4346 stage[1] = "Waiting for instantiate pending tasks."
4347 self.logger.debug(logging_text + stage[1])
4348 exc = await self._wait_for_tasks(logging_text, tasks_dict_info, self.timeout_ns_deploy,
4349 stage, nslcmop_id, nsr_id=nsr_id)
tierno59d22d22018-09-25 18:10:19 +02004350 if exc:
tiernoa17d4f42020-04-28 09:59:23 +00004351 db_nslcmop_update["detailed-status"] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
4352 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02004353 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02004354 db_nsr_update["operational-status"] = old_operational_status
4355 db_nsr_update["config-status"] = old_config_status
4356 db_nsr_update["detailed-status"] = ""
4357 if scale_process:
4358 if "VCA" in scale_process:
4359 db_nsr_update["config-status"] = "failed"
4360 if "RO" in scale_process:
4361 db_nsr_update["operational-status"] = "failed"
4362 db_nsr_update["detailed-status"] = "FAILED scaling nslcmop={} {}: {}".format(nslcmop_id, step,
4363 exc)
tiernoa17d4f42020-04-28 09:59:23 +00004364 else:
4365 error_description_nslcmop = None
4366 nslcmop_operation_state = "COMPLETED"
4367 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00004368
bravof922c4172020-11-24 21:21:43 -03004369 self._write_op_status(op_id=nslcmop_id, stage="", error_message=error_description_nslcmop,
4370 operation_state=nslcmop_operation_state, other_update=db_nslcmop_update)
tiernoa17d4f42020-04-28 09:59:23 +00004371 if db_nsr:
bravof922c4172020-11-24 21:21:43 -03004372 self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE",
4373 current_operation_id=None, other_update=db_nsr_update)
tiernoa17d4f42020-04-28 09:59:23 +00004374
tierno59d22d22018-09-25 18:10:19 +02004375 if nslcmop_operation_state:
4376 try:
bravof922c4172020-11-24 21:21:43 -03004377 msg = {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id, "operationState": nslcmop_operation_state}
4378 await self.msg.aiowrite("ns", "scaled", msg, loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02004379 except Exception as e:
4380 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
4381 self.logger.debug(logging_text + "Exit")
4382 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00004383
tierno2357f4e2020-10-19 16:38:59 +00004384 async def _scale_ng_ro(self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage):
4385 nsr_id = db_nslcmop["nsInstanceId"]
4386 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
4387 db_vnfrs = {}
4388
4389 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03004390 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00004391
4392 # for each vnf in ns, read vnfd
4393 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
4394 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
4395 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00004396 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03004397 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00004398 # read from db
4399 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03004400 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00004401 n2vc_key = self.n2vc.get_public_key()
4402 n2vc_key_list = [n2vc_key]
4403 self.scale_vnfr(db_vnfr, vdu_scaling_info.get("vdu-create"), vdu_scaling_info.get("vdu-delete"),
4404 mark_delete=True)
4405 # db_vnfr has been updated, update db_vnfrs to use it
4406 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
4407 await self._instantiate_ng_ro(logging_text, nsr_id, db_nsd, db_nsr, db_nslcmop, db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03004408 db_vnfds, n2vc_key_list, stage=stage, start_deploy=time(),
tierno2357f4e2020-10-19 16:38:59 +00004409 timeout_ns_deploy=self.timeout_ns_deploy)
4410 if vdu_scaling_info.get("vdu-delete"):
4411 self.scale_vnfr(db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False)
4412
tiernob996d942020-07-03 14:52:28 +00004413 async def add_prometheus_metrics(self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip):
4414 if not self.prometheus:
4415 return
4416 # look if exist a file called 'prometheus*.j2' and
4417 artifact_content = self.fs.dir_ls(artifact_path)
4418 job_file = next((f for f in artifact_content if f.startswith("prometheus") and f.endswith(".j2")), None)
4419 if not job_file:
4420 return
4421 with self.fs.file_open((artifact_path, job_file), "r") as f:
4422 job_data = f.read()
4423
4424 # TODO get_service
4425 _, _, service = ee_id.partition(".") # remove prefix "namespace."
4426 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
4427 host_port = "80"
4428 vnfr_id = vnfr_id.replace("-", "")
4429 variables = {
4430 "JOB_NAME": vnfr_id,
4431 "TARGET_IP": target_ip,
4432 "EXPORTER_POD_IP": host_name,
4433 "EXPORTER_POD_PORT": host_port,
4434 }
4435 job_list = self.prometheus.parse_job(job_data, variables)
4436 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
4437 for job in job_list:
4438 if not isinstance(job.get("job_name"), str) or vnfr_id not in job["job_name"]:
4439 job["job_name"] = vnfr_id + "_" + str(randint(1, 10000))
4440 job["nsr_id"] = nsr_id
4441 job_dict = {jl["job_name"]: jl for jl in job_list}
4442 if await self.prometheus.update(job_dict):
4443 return list(job_dict.keys())
David Garciaaae391f2020-11-09 11:12:54 +01004444
4445 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
4446 """
4447 Get VCA Cloud and VCA Cloud Credentials for the VIM account
4448
4449 :param: vim_account_id: VIM Account ID
4450
4451 :return: (cloud_name, cloud_credential)
4452 """
bravof922c4172020-11-24 21:21:43 -03004453 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01004454 return config.get("vca_cloud"), config.get("vca_cloud_credential")
4455
4456 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
4457 """
4458 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
4459
4460 :param: vim_account_id: VIM Account ID
4461
4462 :return: (cloud_name, cloud_credential)
4463 """
bravof922c4172020-11-24 21:21:43 -03004464 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01004465 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")