blob: ed8112bb425217e50ecfa4b898c4fd5fb851b404 [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
garciaalea77ced72021-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, \
garciaalea77ced72021-02-17 19:09:12 -030033 get_kdu_list, get_virtual_link_profiles, get_vdu, get_configuration, \
bravof832f8992020-12-07 12:57:31 -030034 get_vdu_index, get_scaling_aspect, get_number_of_instances
bravof922c4172020-11-24 21:21:43 -030035from osm_lcm.data_utils.list_utils import find_in_list
36from osm_lcm.data_utils.vnfr import get_osm_params
37from 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,
100 url='{}:{}'.format(self.vca_config['host'], self.vca_config['port']),
101 username=self.vca_config.get('user', None),
102 vca_config=self.vca_config,
bravof922c4172020-11-24 21:21:43 -0300103 on_update_db=self._on_update_n2vc_db,
104 fs=self.fs,
105 db=self.db
tierno59d22d22018-09-25 18:10:19 +0200106 )
quilesj7e13aeb2019-10-08 13:34:55 +0200107
tierno588547c2020-07-01 15:30:20 +0000108 self.conn_helm_ee = LCMHelmConn(
tierno588547c2020-07-01 15:30:20 +0000109 log=self.logger,
110 loop=self.loop,
111 url=None,
112 username=None,
113 vca_config=self.vca_config,
114 on_update_db=self._on_update_n2vc_db
115 )
116
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000117 self.k8sclusterhelm2 = K8sHelmConnector(
calvinosanch9f9c6f22019-11-04 13:37:39 +0100118 kubectl_command=self.vca_config.get("kubectlpath"),
119 helm_command=self.vca_config.get("helmpath"),
calvinosanch9f9c6f22019-11-04 13:37:39 +0100120 log=self.logger,
calvinosanch9f9c6f22019-11-04 13:37:39 +0100121 on_update_db=None,
bravof922c4172020-11-24 21:21:43 -0300122 fs=self.fs,
123 db=self.db
calvinosanch9f9c6f22019-11-04 13:37:39 +0100124 )
125
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000126 self.k8sclusterhelm3 = K8sHelm3Connector(
127 kubectl_command=self.vca_config.get("kubectlpath"),
128 helm_command=self.vca_config.get("helm3path"),
129 fs=self.fs,
130 log=self.logger,
131 db=self.db,
132 on_update_db=None,
133 )
134
Adam Israelbaacc302019-12-01 12:41:39 -0500135 self.k8sclusterjuju = K8sJujuConnector(
136 kubectl_command=self.vca_config.get("kubectlpath"),
137 juju_command=self.vca_config.get("jujupath"),
Adam Israelbaacc302019-12-01 12:41:39 -0500138 log=self.logger,
David Garciaba89cbb2020-10-16 13:05:34 +0200139 loop=self.loop,
Adam Israelbaacc302019-12-01 12:41:39 -0500140 on_update_db=None,
David Garciaba89cbb2020-10-16 13:05:34 +0200141 vca_config=self.vca_config,
bravof922c4172020-11-24 21:21:43 -0300142 fs=self.fs,
143 db=self.db
Adam Israelbaacc302019-12-01 12:41:39 -0500144 )
145
tiernoa2143262020-03-27 16:20:40 +0000146 self.k8scluster_map = {
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000147 "helm-chart": self.k8sclusterhelm2,
148 "helm-chart-v3": self.k8sclusterhelm3,
149 "chart": self.k8sclusterhelm3,
tiernoa2143262020-03-27 16:20:40 +0000150 "juju-bundle": self.k8sclusterjuju,
151 "juju": self.k8sclusterjuju,
152 }
tierno588547c2020-07-01 15:30:20 +0000153
154 self.vca_map = {
155 "lxc_proxy_charm": self.n2vc,
156 "native_charm": self.n2vc,
157 "k8s_proxy_charm": self.n2vc,
lloretgalleg18ebc3a2020-10-22 09:54:51 +0000158 "helm": self.conn_helm_ee,
159 "helm-v3": self.conn_helm_ee
tierno588547c2020-07-01 15:30:20 +0000160 }
161
tiernob996d942020-07-03 14:52:28 +0000162 self.prometheus = prometheus
163
quilesj7e13aeb2019-10-08 13:34:55 +0200164 # create RO client
bravof922c4172020-11-24 21:21:43 -0300165 self.RO = NgRoClient(self.loop, **self.ro_config)
tierno59d22d22018-09-25 18:10:19 +0200166
tierno2357f4e2020-10-19 16:38:59 +0000167 @staticmethod
168 def increment_ip_mac(ip_mac, vm_index=1):
169 if not isinstance(ip_mac, str):
170 return ip_mac
171 try:
172 # try with ipv4 look for last dot
173 i = ip_mac.rfind(".")
174 if i > 0:
175 i += 1
176 return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
177 # try with ipv6 or mac look for last colon. Operate in hex
178 i = ip_mac.rfind(":")
179 if i > 0:
180 i += 1
181 # format in hex, len can be 2 for mac or 4 for ipv6
182 return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(ip_mac[:i], int(ip_mac[i:], 16) + vm_index)
183 except Exception:
184 pass
185 return None
186
quilesj3655ae02019-12-12 16:08:35 +0000187 def _on_update_ro_db(self, nsrs_id, ro_descriptor):
quilesj7e13aeb2019-10-08 13:34:55 +0200188
quilesj3655ae02019-12-12 16:08:35 +0000189 # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
190
191 try:
192 # TODO filter RO descriptor fields...
193
194 # write to database
195 db_dict = dict()
196 # db_dict['deploymentStatus'] = yaml.dump(ro_descriptor, default_flow_style=False, indent=2)
197 db_dict['deploymentStatus'] = ro_descriptor
198 self.update_db_2("nsrs", nsrs_id, db_dict)
199
200 except Exception as e:
201 self.logger.warn('Cannot write database RO deployment for ns={} -> {}'.format(nsrs_id, e))
202
203 async def _on_update_n2vc_db(self, table, filter, path, updated_data):
204
quilesj69a722c2020-01-09 08:30:17 +0000205 # remove last dot from path (if exists)
206 if path.endswith('.'):
207 path = path[:-1]
208
quilesj3655ae02019-12-12 16:08:35 +0000209 # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
210 # .format(table, filter, path, updated_data))
211
212 try:
213
214 nsr_id = filter.get('_id')
215
216 # read ns record from database
217 nsr = self.db.get_one(table='nsrs', q_filter=filter)
218 current_ns_status = nsr.get('nsState')
219
220 # get vca status for NS
quilesj69a722c2020-01-09 08:30:17 +0000221 status_dict = await self.n2vc.get_status(namespace='.' + nsr_id, yaml_format=False)
quilesj3655ae02019-12-12 16:08:35 +0000222
223 # vcaStatus
224 db_dict = dict()
225 db_dict['vcaStatus'] = status_dict
226
227 # update configurationStatus for this VCA
228 try:
229 vca_index = int(path[path.rfind(".")+1:])
230
231 vca_list = deep_get(target_dict=nsr, key_list=('_admin', 'deployed', 'VCA'))
232 vca_status = vca_list[vca_index].get('status')
233
234 configuration_status_list = nsr.get('configurationStatus')
235 config_status = configuration_status_list[vca_index].get('status')
236
237 if config_status == 'BROKEN' and vca_status != 'failed':
238 db_dict['configurationStatus'][vca_index] = 'READY'
239 elif config_status != 'BROKEN' and vca_status == 'failed':
240 db_dict['configurationStatus'][vca_index] = 'BROKEN'
241 except Exception as e:
242 # not update configurationStatus
243 self.logger.debug('Error updating vca_index (ignore): {}'.format(e))
244
245 # if nsState = 'READY' check if juju is reporting some error => nsState = 'DEGRADED'
246 # if nsState = 'DEGRADED' check if all is OK
247 is_degraded = False
248 if current_ns_status in ('READY', 'DEGRADED'):
249 error_description = ''
250 # check machines
251 if status_dict.get('machines'):
252 for machine_id in status_dict.get('machines'):
253 machine = status_dict.get('machines').get(machine_id)
254 # check machine agent-status
255 if machine.get('agent-status'):
256 s = machine.get('agent-status').get('status')
257 if s != 'started':
258 is_degraded = True
259 error_description += 'machine {} agent-status={} ; '.format(machine_id, s)
260 # check machine instance status
261 if machine.get('instance-status'):
262 s = machine.get('instance-status').get('status')
263 if s != 'running':
264 is_degraded = True
265 error_description += 'machine {} instance-status={} ; '.format(machine_id, s)
266 # check applications
267 if status_dict.get('applications'):
268 for app_id in status_dict.get('applications'):
269 app = status_dict.get('applications').get(app_id)
270 # check application status
271 if app.get('status'):
272 s = app.get('status').get('status')
273 if s != 'active':
274 is_degraded = True
275 error_description += 'application {} status={} ; '.format(app_id, s)
276
277 if error_description:
278 db_dict['errorDescription'] = error_description
279 if current_ns_status == 'READY' and is_degraded:
280 db_dict['nsState'] = 'DEGRADED'
281 if current_ns_status == 'DEGRADED' and not is_degraded:
282 db_dict['nsState'] = 'READY'
283
284 # write to database
285 self.update_db_2("nsrs", nsr_id, db_dict)
286
tierno51183952020-04-03 15:48:18 +0000287 except (asyncio.CancelledError, asyncio.TimeoutError):
288 raise
quilesj3655ae02019-12-12 16:08:35 +0000289 except Exception as e:
290 self.logger.warn('Error updating NS state for ns={}: {}'.format(nsr_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +0200291
tierno72ef84f2020-10-06 08:22:07 +0000292 @staticmethod
293 def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
294 try:
295 env = Environment(undefined=StrictUndefined)
296 template = env.from_string(cloud_init_text)
297 return template.render(additional_params or {})
298 except UndefinedError as e:
299 raise LcmException("Variable {} at vnfd[id={}]:vdu[id={}]:cloud-init/cloud-init-"
300 "file, must be provided in the instantiation parameters inside the "
301 "'additionalParamsForVnf/Vdu' block".format(e, vnfd_id, vdu_id))
302 except (TemplateError, TemplateNotFound) as e:
303 raise LcmException("Error parsing Jinja2 to cloud-init content at vnfd[id={}]:vdu[id={}]: {}".
304 format(vnfd_id, vdu_id, e))
305
bravof922c4172020-11-24 21:21:43 -0300306 def _get_vdu_cloud_init_content(self, vdu, vnfd):
307 cloud_init_content = cloud_init_file = None
tierno72ef84f2020-10-06 08:22:07 +0000308 try:
tierno72ef84f2020-10-06 08:22:07 +0000309 if vdu.get("cloud-init-file"):
310 base_folder = vnfd["_admin"]["storage"]
311 cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"],
312 vdu["cloud-init-file"])
313 with self.fs.file_open(cloud_init_file, "r") as ci_file:
314 cloud_init_content = ci_file.read()
315 elif vdu.get("cloud-init"):
316 cloud_init_content = vdu["cloud-init"]
317
318 return cloud_init_content
319 except FsException as e:
320 raise LcmException("Error reading vnfd[id={}]:vdu[id={}]:cloud-init-file={}: {}".
321 format(vnfd["id"], vdu["id"], cloud_init_file, e))
322
tierno72ef84f2020-10-06 08:22:07 +0000323 def _get_vdu_additional_params(self, db_vnfr, vdu_id):
324 vdur = next(vdur for vdur in db_vnfr.get("vdur") if vdu_id == vdur["vdu-id-ref"])
325 additional_params = vdur.get("additionalParams")
bravof922c4172020-11-24 21:21:43 -0300326 return parse_yaml_strings(additional_params)
tierno72ef84f2020-10-06 08:22:07 +0000327
gcalvino35be9152018-12-20 09:33:12 +0100328 def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
tierno59d22d22018-09-25 18:10:19 +0200329 """
330 Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
331 :param vnfd: input vnfd
332 :param new_id: overrides vnf id if provided
tierno8a518872018-12-21 13:42:14 +0000333 :param additionalParams: Instantiation params for VNFs provided
gcalvino35be9152018-12-20 09:33:12 +0100334 :param nsrId: Id of the NSR
tierno59d22d22018-09-25 18:10:19 +0200335 :return: copy of vnfd
336 """
tierno72ef84f2020-10-06 08:22:07 +0000337 vnfd_RO = deepcopy(vnfd)
338 # remove unused by RO configuration, monitoring, scaling and internal keys
339 vnfd_RO.pop("_id", None)
340 vnfd_RO.pop("_admin", None)
tierno72ef84f2020-10-06 08:22:07 +0000341 vnfd_RO.pop("monitoring-param", None)
342 vnfd_RO.pop("scaling-group-descriptor", None)
343 vnfd_RO.pop("kdu", None)
344 vnfd_RO.pop("k8s-cluster", None)
345 if new_id:
346 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000347
tierno72ef84f2020-10-06 08:22:07 +0000348 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
349 for vdu in get_iterable(vnfd_RO, "vdu"):
350 vdu.pop("cloud-init-file", None)
351 vdu.pop("cloud-init", None)
352 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200353
tierno2357f4e2020-10-19 16:38:59 +0000354 @staticmethod
355 def ip_profile_2_RO(ip_profile):
356 RO_ip_profile = deepcopy(ip_profile)
357 if "dns-server" in RO_ip_profile:
358 if isinstance(RO_ip_profile["dns-server"], list):
359 RO_ip_profile["dns-address"] = []
360 for ds in RO_ip_profile.pop("dns-server"):
361 RO_ip_profile["dns-address"].append(ds['address'])
362 else:
363 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
364 if RO_ip_profile.get("ip-version") == "ipv4":
365 RO_ip_profile["ip-version"] = "IPv4"
366 if RO_ip_profile.get("ip-version") == "ipv6":
367 RO_ip_profile["ip-version"] = "IPv6"
368 if "dhcp-params" in RO_ip_profile:
369 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
370 return RO_ip_profile
371
bravof922c4172020-11-24 21:21:43 -0300372 def _get_ro_vim_id_for_vim_account(self, vim_account):
373 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
374 if db_vim["_admin"]["operationalState"] != "ENABLED":
375 raise LcmException("VIM={} is not available. operationalState={}".format(
376 vim_account, db_vim["_admin"]["operationalState"]))
377 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
378 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200379
bravof922c4172020-11-24 21:21:43 -0300380 def get_ro_wim_id_for_wim_account(self, wim_account):
381 if isinstance(wim_account, str):
382 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
383 if db_wim["_admin"]["operationalState"] != "ENABLED":
384 raise LcmException("WIM={} is not available. operationalState={}".format(
385 wim_account, db_wim["_admin"]["operationalState"]))
386 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
387 return RO_wim_id
388 else:
389 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200390
tierno2357f4e2020-10-19 16:38:59 +0000391 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno27246d82018-09-27 15:59:09 +0200392
tierno2357f4e2020-10-19 16:38:59 +0000393 db_vdu_push_list = []
394 db_update = {"_admin.modified": time()}
395 if vdu_create:
396 for vdu_id, vdu_count in vdu_create.items():
397 vdur = next((vdur for vdur in reversed(db_vnfr["vdur"]) if vdur["vdu-id-ref"] == vdu_id), None)
398 if not vdur:
399 raise LcmException("Error scaling OUT VNFR for {}. There is not any existing vnfr. Scaled to 0?".
400 format(vdu_id))
401
402 for count in range(vdu_count):
403 vdur_copy = deepcopy(vdur)
404 vdur_copy["status"] = "BUILD"
405 vdur_copy["status-detailed"] = None
406 vdur_copy["ip-address"]: None
tierno683eb392020-09-25 12:33:15 +0000407 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000408 vdur_copy["count-index"] += count + 1
409 vdur_copy["id"] = "{}-{}".format(vdur_copy["vdu-id-ref"], vdur_copy["count-index"])
410 vdur_copy.pop("vim_info", None)
411 for iface in vdur_copy["interfaces"]:
412 if iface.get("fixed-ip"):
413 iface["ip-address"] = self.increment_ip_mac(iface["ip-address"], count+1)
414 else:
415 iface.pop("ip-address", None)
416 if iface.get("fixed-mac"):
417 iface["mac-address"] = self.increment_ip_mac(iface["mac-address"], count+1)
418 else:
419 iface.pop("mac-address", None)
420 iface.pop("mgmt_vnf", None) # only first vdu can be managment of vnf
421 db_vdu_push_list.append(vdur_copy)
422 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200423 if vdu_delete:
tierno2357f4e2020-10-19 16:38:59 +0000424 for vdu_id, vdu_count in vdu_delete.items():
425 if mark_delete:
426 indexes_to_delete = [iv[0] for iv in enumerate(db_vnfr["vdur"]) if iv[1]["vdu-id-ref"] == vdu_id]
427 db_update.update({"vdur.{}.status".format(i): "DELETING" for i in indexes_to_delete[-vdu_count:]})
428 else:
429 # it must be deleted one by one because common.db does not allow otherwise
430 vdus_to_delete = [v for v in reversed(db_vnfr["vdur"]) if v["vdu-id-ref"] == vdu_id]
431 for vdu in vdus_to_delete[:vdu_count]:
432 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, None, pull={"vdur": {"_id": vdu["_id"]}})
433 db_push = {"vdur": db_vdu_push_list} if db_vdu_push_list else None
434 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
435 # modify passed dictionary db_vnfr
436 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
437 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200438
tiernof578e552018-11-08 19:07:20 +0100439 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
440 """
441 Updates database nsr with the RO info for the created vld
442 :param ns_update_nsr: dictionary to be filled with the updated info
443 :param db_nsr: content of db_nsr. This is also modified
444 :param nsr_desc_RO: nsr descriptor from RO
445 :return: Nothing, LcmException is raised on errors
446 """
447
448 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
449 for net_RO in get_iterable(nsr_desc_RO, "nets"):
450 if vld["id"] != net_RO.get("ns_net_osm_id"):
451 continue
452 vld["vim-id"] = net_RO.get("vim_net_id")
453 vld["name"] = net_RO.get("vim_name")
454 vld["status"] = net_RO.get("status")
455 vld["status-detailed"] = net_RO.get("error_msg")
456 ns_update_nsr["vld.{}".format(vld_index)] = vld
457 break
458 else:
459 raise LcmException("ns_update_nsr: Not found vld={} at RO info".format(vld["id"]))
460
tiernoe876f672020-02-13 14:34:48 +0000461 def set_vnfr_at_error(self, db_vnfrs, error_text):
462 try:
463 for db_vnfr in db_vnfrs.values():
464 vnfr_update = {"status": "ERROR"}
465 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
466 if "status" not in vdur:
467 vdur["status"] = "ERROR"
468 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
469 if error_text:
470 vdur["status-detailed"] = str(error_text)
471 vnfr_update["vdur.{}.status-detailed".format(vdu_index)] = "ERROR"
472 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
473 except DbException as e:
474 self.logger.error("Cannot update vnf. {}".format(e))
475
tierno59d22d22018-09-25 18:10:19 +0200476 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
477 """
478 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 +0200479 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
480 :param nsr_desc_RO: nsr descriptor from RO
481 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200482 """
483 for vnf_index, db_vnfr in db_vnfrs.items():
484 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200485 if vnf_RO["member_vnf_index"] != vnf_index:
486 continue
487 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100488 if vnf_RO.get("ip_address"):
tierno1674de82019-04-09 13:03:14 +0000489 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO["ip_address"].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100490 elif not db_vnfr.get("ip-address"):
tierno0ec0c272020-02-19 17:43:01 +0000491 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
492 raise LcmExceptionNoMgmtIP("ns member_vnf_index '{}' has no IP address".format(vnf_index))
tierno59d22d22018-09-25 18:10:19 +0200493
tierno27246d82018-09-27 15:59:09 +0200494 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
495 vdur_RO_count_index = 0
496 if vdur.get("pdu-type"):
497 continue
498 for vdur_RO in get_iterable(vnf_RO, "vms"):
499 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
500 continue
501 if vdur["count-index"] != vdur_RO_count_index:
502 vdur_RO_count_index += 1
503 continue
504 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000505 if vdur_RO.get("ip_address"):
506 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000507 else:
508 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200509 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
510 vdur["name"] = vdur_RO.get("vim_name")
511 vdur["status"] = vdur_RO.get("status")
512 vdur["status-detailed"] = vdur_RO.get("error_msg")
513 for ifacer in get_iterable(vdur, "interfaces"):
514 for interface_RO in get_iterable(vdur_RO, "interfaces"):
515 if ifacer["name"] == interface_RO.get("internal_name"):
516 ifacer["ip-address"] = interface_RO.get("ip_address")
517 ifacer["mac-address"] = interface_RO.get("mac_address")
518 break
519 else:
520 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
quilesj7e13aeb2019-10-08 13:34:55 +0200521 "from VIM info"
522 .format(vnf_index, vdur["vdu-id-ref"], ifacer["name"]))
tierno27246d82018-09-27 15:59:09 +0200523 vnfr_update["vdur.{}".format(vdu_index)] = vdur
524 break
525 else:
tierno15b1cf12019-08-29 13:21:40 +0000526 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
527 "VIM info".format(vnf_index, vdur["vdu-id-ref"], vdur["count-index"]))
tiernof578e552018-11-08 19:07:20 +0100528
529 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
530 for net_RO in get_iterable(nsr_desc_RO, "nets"):
531 if vld["id"] != net_RO.get("vnf_net_osm_id"):
532 continue
533 vld["vim-id"] = net_RO.get("vim_net_id")
534 vld["name"] = net_RO.get("vim_name")
535 vld["status"] = net_RO.get("status")
536 vld["status-detailed"] = net_RO.get("error_msg")
537 vnfr_update["vld.{}".format(vld_index)] = vld
538 break
539 else:
tierno15b1cf12019-08-29 13:21:40 +0000540 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
tiernof578e552018-11-08 19:07:20 +0100541 vnf_index, vld["id"]))
542
tierno27246d82018-09-27 15:59:09 +0200543 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
544 break
tierno59d22d22018-09-25 18:10:19 +0200545
546 else:
tierno15b1cf12019-08-29 13:21:40 +0000547 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(vnf_index))
tierno59d22d22018-09-25 18:10:19 +0200548
tierno5ee02052019-12-05 19:55:02 +0000549 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000550 """
551 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000552 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000553 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
554 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
555 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
556 """
tierno5ee02052019-12-05 19:55:02 +0000557 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
558 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000559 mapping = {}
560 ns_config_info = {"osm-config-mapping": mapping}
561 for vca in vca_deployed_list:
562 if not vca["member-vnf-index"]:
563 continue
564 if not vca["vdu_id"]:
565 mapping[vca["member-vnf-index"]] = vca["application"]
566 else:
567 mapping["{}.{}.{}".format(vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"])] =\
568 vca["application"]
569 return ns_config_info
570
bravof922c4172020-11-24 21:21:43 -0300571 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 +0000572 n2vc_key_list, stage, start_deploy, timeout_ns_deploy):
tierno2357f4e2020-10-19 16:38:59 +0000573
574 db_vims = {}
575
576 def get_vim_account(vim_account_id):
577 nonlocal db_vims
578 if vim_account_id in db_vims:
579 return db_vims[vim_account_id]
580 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
581 db_vims[vim_account_id] = db_vim
582 return db_vim
583
584 # modify target_vld info with instantiation parameters
585 def parse_vld_instantiation_params(target_vim, target_vld, vld_params, target_sdn):
586 if vld_params.get("ip-profile"):
587 target_vld["vim_info"][target_vim]["ip_profile"] = vld_params["ip-profile"]
588 if vld_params.get("provider-network"):
589 target_vld["vim_info"][target_vim]["provider_network"] = vld_params["provider-network"]
590 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
591 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params["provider-network"]["sdn-ports"]
592 if vld_params.get("wimAccountId"):
593 target_wim = "wim:{}".format(vld_params["wimAccountId"])
594 target_vld["vim_info"][target_wim] = {}
595 for param in ("vim-network-name", "vim-network-id"):
596 if vld_params.get(param):
597 if isinstance(vld_params[param], dict):
bravof922c4172020-11-24 21:21:43 -0300598 for vim, vim_net in vld_params[param]:
599 other_target_vim = "vim:" + vim
600 populate_dict(target_vld["vim_info"], (other_target_vim, param.replace("-", "_")), vim_net)
tierno2357f4e2020-10-19 16:38:59 +0000601 else: # isinstance str
602 target_vld["vim_info"][target_vim][param.replace("-", "_")] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300603 if vld_params.get("common_id"):
604 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000605
tierno69f0d382020-05-07 13:08:09 +0000606 nslcmop_id = db_nslcmop["_id"]
607 target = {
608 "name": db_nsr["name"],
609 "ns": {"vld": []},
610 "vnf": [],
611 "image": deepcopy(db_nsr["image"]),
612 "flavor": deepcopy(db_nsr["flavor"]),
613 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000614 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000615 }
616 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000617 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000618 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000619 flavor["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000620
tierno2357f4e2020-10-19 16:38:59 +0000621 if db_nslcmop.get("lcmOperationType") != "instantiate":
622 # get parameters of instantiation:
623 db_nslcmop_instantiate = self.db.get_list("nslcmops", {"nsInstanceId": db_nslcmop["nsInstanceId"],
624 "lcmOperationType": "instantiate"})[-1]
625 ns_params = db_nslcmop_instantiate.get("operationParams")
626 else:
627 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300628 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
629 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000630
631 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000632 for vld_index, vld in enumerate(db_nsr.get("vld")):
633 target_vim = "vim:{}".format(ns_params["vimAccountId"])
634 target_vld = {
635 "id": vld["id"],
636 "name": vld["name"],
637 "mgmt-network": vld.get("mgmt-network", False),
638 "type": vld.get("type"),
639 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300640 target_vim: {
641 "vim_network_name": vld.get("vim-network-name"),
642 "vim_account_id": ns_params["vimAccountId"]
643 }
tierno2357f4e2020-10-19 16:38:59 +0000644 }
645 }
646 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000647 if vld.get("pci-interfaces"):
garciaale6be14002021-02-12 11:26:46 +0000648 db_vim = get_vim_account(ns_params["vimAccountId"])
tierno2357f4e2020-10-19 16:38:59 +0000649 sdnc_id = db_vim["config"].get("sdn-controller")
650 if sdnc_id:
garciaale6be14002021-02-12 11:26:46 +0000651 sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
652 target_sdn = "sdn:{}".format(sdnc_id)
653 target_vld["vim_info"][target_sdn] = {
654 "sdn": True, "target_vim": target_vim, "vlds": [sdn_vld], "type": vld.get("type")}
tierno2357f4e2020-10-19 16:38:59 +0000655
bravof922c4172020-11-24 21:21:43 -0300656 nsd_vnf_profiles = get_vnf_profiles(nsd)
657 for nsd_vnf_profile in nsd_vnf_profiles:
658 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
659 if cp["virtual-link-profile-id"] == vld["id"]:
660 cp2target["member_vnf:{}.{}".format(
661 cp["constituent-cpd-id"][0]["constituent-base-element-id"],
662 cp["constituent-cpd-id"][0]["constituent-cpd-id"]
663 )] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000664
665 # check at nsd descriptor, if there is an ip-profile
666 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300667 virtual_link_profiles = get_virtual_link_profiles(nsd)
668
669 for vlp in virtual_link_profiles:
670 ip_profile = find_in_list(nsd["ip-profiles"],
671 lambda profile: profile["name"] == vlp["ip-profile-ref"])
tierno2357f4e2020-10-19 16:38:59 +0000672 vld_params["ip-profile"] = ip_profile["ip-profile-params"]
673 # update vld_params with instantiation params
bravof922c4172020-11-24 21:21:43 -0300674 vld_instantiation_params = find_in_list(get_iterable(ns_params, "vld"),
675 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]))
tierno2357f4e2020-10-19 16:38:59 +0000676 if vld_instantiation_params:
677 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300678 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000679 target["ns"]["vld"].append(target_vld)
bravof922c4172020-11-24 21:21:43 -0300680
tierno69f0d382020-05-07 13:08:09 +0000681 for vnfr in db_vnfrs.values():
bravof922c4172020-11-24 21:21:43 -0300682 vnfd = find_in_list(db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"])
683 vnf_params = find_in_list(get_iterable(ns_params, "vnf"),
684 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"])
tierno69f0d382020-05-07 13:08:09 +0000685 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000686 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000687 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000688 # check if connected to a ns.vld, to fill target'
bravof922c4172020-11-24 21:21:43 -0300689 vnf_cp = find_in_list(vnfd.get("int-virtual-link-desc", ()),
690 lambda cpd: cpd.get("id") == vld["id"])
tierno69f0d382020-05-07 13:08:09 +0000691 if vnf_cp:
692 ns_cp = "member_vnf:{}.{}".format(vnfr["member-vnf-index-ref"], vnf_cp["id"])
693 if cp2target.get(ns_cp):
694 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300695
696 vld["vim_info"] = {target_vim: {"vim_network_name": vld.get("vim-network-name")}}
tierno2357f4e2020-10-19 16:38:59 +0000697 # check if this network needs SDN assist
698 target_sdn = None
699 if vld.get("pci-interfaces"):
700 db_vim = get_vim_account(vnfr["vim-account-id"])
701 sdnc_id = db_vim["config"].get("sdn-controller")
702 if sdnc_id:
703 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
704 target_sdn = "sdn:{}".format(sdnc_id)
705 vld["vim_info"][target_sdn] = {
706 "sdn": True, "target_vim": target_vim, "vlds": [sdn_vld], "type": vld.get("type")}
tierno69f0d382020-05-07 13:08:09 +0000707
tierno2357f4e2020-10-19 16:38:59 +0000708 # check at vnfd descriptor, if there is an ip-profile
709 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300710 vnfd_vlp = find_in_list(
711 get_virtual_link_profiles(vnfd),
712 lambda a_link_profile: a_link_profile["id"] == vld["id"]
713 )
714 if vnfd_vlp and vnfd_vlp.get("virtual-link-protocol-data") and \
715 vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data"):
716 ip_profile_source_data = vnfd_vlp["virtual-link-protocol-data"]["l3-protocol-data"]
717 ip_profile_dest_data = {}
718 if "ip-version" in ip_profile_source_data:
719 ip_profile_dest_data["ip-version"] = ip_profile_source_data["ip-version"]
720 if "cidr" in ip_profile_source_data:
721 ip_profile_dest_data["subnet-address"] = ip_profile_source_data["cidr"]
722 if "gateway-ip" in ip_profile_source_data:
723 ip_profile_dest_data["gateway-address"] = ip_profile_source_data["gateway-ip"]
724 if "dhcp-enabled" in ip_profile_source_data:
725 ip_profile_dest_data["dhcp-params"] = {
726 "enabled": ip_profile_source_data["dhcp-enabled"]
727 }
728
729 vld_params["ip-profile"] = ip_profile_dest_data
tierno2357f4e2020-10-19 16:38:59 +0000730 # update vld_params with instantiation params
731 if vnf_params:
bravof922c4172020-11-24 21:21:43 -0300732 vld_instantiation_params = find_in_list(get_iterable(vnf_params, "internal-vld"),
733 lambda i_vld: i_vld["name"] == vld["id"])
tierno2357f4e2020-10-19 16:38:59 +0000734 if vld_instantiation_params:
735 vld_params.update(vld_instantiation_params)
736 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
737
738 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +0000739 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +0000740 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
741 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -0300742 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +0000743
bravof922c4172020-11-24 21:21:43 -0300744 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
745
746 if ssh_keys_all:
garciaalea77ced72021-02-17 19:09:12 -0300747 vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
748 vnf_configuration = get_configuration(vnfd, vnfd["id"])
bravof922c4172020-11-24 21:21:43 -0300749 if vdu_configuration and vdu_configuration.get("config-access") and \
750 vdu_configuration.get("config-access").get("ssh-access"):
751 vdur["ssh-keys"] = ssh_keys_all
752 vdur["ssh-access-required"] = vdu_configuration["config-access"]["ssh-access"]["required"]
753 elif vnf_configuration and vnf_configuration.get("config-access") and \
754 vnf_configuration.get("config-access").get("ssh-access") and \
tierno69f0d382020-05-07 13:08:09 +0000755 any(iface.get("mgmt-vnf") for iface in vdur["interfaces"]):
bravof922c4172020-11-24 21:21:43 -0300756 vdur["ssh-keys"] = ssh_keys_all
757 vdur["ssh-access-required"] = vnf_configuration["config-access"]["ssh-access"]["required"]
758 elif ssh_keys_instantiation and \
759 find_in_list(vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")):
760 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +0000761
bravof922c4172020-11-24 21:21:43 -0300762 self.logger.debug("NS > vdur > {}".format(vdur))
763
764 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +0000765 # cloud-init
766 if vdud.get("cloud-init-file"):
767 vdur["cloud-init"] = "{}:file:{}".format(vnfd["_id"], vdud.get("cloud-init-file"))
tierno2357f4e2020-10-19 16:38:59 +0000768 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
769 if vdur["cloud-init"] not in target["cloud_init_content"]:
770 base_folder = vnfd["_admin"]["storage"]
771 cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"],
772 vdud.get("cloud-init-file"))
773 with self.fs.file_open(cloud_init_file, "r") as ci_file:
774 target["cloud_init_content"][vdur["cloud-init"]] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +0000775 elif vdud.get("cloud-init"):
bravof922c4172020-11-24 21:21:43 -0300776 vdur["cloud-init"] = "{}:vdu:{}".format(vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"]))
tierno2357f4e2020-10-19 16:38:59 +0000777 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
778 target["cloud_init_content"][vdur["cloud-init"]] = vdud["cloud-init"]
779 vdur["additionalParams"] = vdur.get("additionalParams") or {}
780 deploy_params_vdu = self._format_additional_params(vdur.get("additionalParams") or {})
bravof922c4172020-11-24 21:21:43 -0300781 deploy_params_vdu["OSM"] = get_osm_params(vnfr, vdur["vdu-id-ref"], vdur["count-index"])
tierno2357f4e2020-10-19 16:38:59 +0000782 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +0000783
784 # flavor
785 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +0000786 if target_vim not in ns_flavor["vim_info"]:
787 ns_flavor["vim_info"][target_vim] = {}
lloretgalleg46ab4d82021-02-08 11:49:50 +0000788
789 # deal with images
790 # in case alternative images are provided we must check if they should be applied
791 # for the vim_type, modify the vim_type taking into account
792 ns_image_id = int(vdur["ns-image-id"])
793 if vdur.get("alt-image-ids"):
794 db_vim = get_vim_account(vnfr["vim-account-id"])
795 vim_type = db_vim["vim_type"]
796 for alt_image_id in vdur.get("alt-image-ids"):
797 ns_alt_image = target["image"][int(alt_image_id)]
798 if vim_type == ns_alt_image.get("vim-type"):
799 # must use alternative image
800 self.logger.debug("use alternative image id: {}".format(alt_image_id))
801 ns_image_id = alt_image_id
802 vdur["ns-image-id"] = ns_image_id
803 break
804 ns_image = target["image"][int(ns_image_id)]
tierno2357f4e2020-10-19 16:38:59 +0000805 if target_vim not in ns_image["vim_info"]:
806 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +0000807
tierno2357f4e2020-10-19 16:38:59 +0000808 vdur["vim_info"] = {target_vim: {}}
809 # instantiation parameters
810 # if vnf_params:
811 # vdu_instantiation_params = next((v for v in get_iterable(vnf_params, "vdu") if v["id"] ==
812 # vdud["id"]), None)
813 vdur_list.append(vdur)
814 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +0000815 target["vnf"].append(target_vnf)
816
817 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -0300818 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +0000819 action_id = desc["action_id"]
tierno2357f4e2020-10-19 16:38:59 +0000820 await self._wait_ng_ro(nsr_id, action_id, nslcmop_id, start_deploy, timeout_ns_deploy, stage)
tierno69f0d382020-05-07 13:08:09 +0000821
822 # Updating NSR
823 db_nsr_update = {
824 "_admin.deployed.RO.operational-status": "running",
825 "detailed-status": " ".join(stage)
826 }
827 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
828 self.update_db_2("nsrs", nsr_id, db_nsr_update)
829 self._write_op_status(nslcmop_id, stage)
830 self.logger.debug(logging_text + "ns deployed at RO. RO_id={}".format(action_id))
831 return
832
tierno2357f4e2020-10-19 16:38:59 +0000833 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 +0000834 detailed_status_old = None
835 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +0000836 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +0000837 while time() <= start_time + timeout:
838 desc_status = await self.RO.status(nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -0300839 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +0000840 if desc_status["status"] == "FAILED":
841 raise NgRoException(desc_status["details"])
842 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +0000843 if stage:
844 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +0000845 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +0000846 if stage:
847 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +0000848 break
849 else:
850 assert False, "ROclient.check_ns_status returns unknown {}".format(desc_status["status"])
tierno2357f4e2020-10-19 16:38:59 +0000851 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +0000852 detailed_status_old = stage[2]
853 db_nsr_update["detailed-status"] = " ".join(stage)
854 self.update_db_2("nsrs", nsr_id, db_nsr_update)
855 self._write_op_status(nslcmop_id, stage)
bravof922c4172020-11-24 21:21:43 -0300856 await asyncio.sleep(15, loop=self.loop)
tierno69f0d382020-05-07 13:08:09 +0000857 else: # timeout_ns_deploy
858 raise NgRoException("Timeout waiting ns to deploy")
859
860 async def _terminate_ng_ro(self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage):
861 db_nsr_update = {}
862 failed_detail = []
863 action_id = None
864 start_deploy = time()
865 try:
866 target = {
867 "ns": {"vld": []},
868 "vnf": [],
869 "image": [],
870 "flavor": [],
tierno2357f4e2020-10-19 16:38:59 +0000871 "action_id": nslcmop_id
tierno69f0d382020-05-07 13:08:09 +0000872 }
873 desc = await self.RO.deploy(nsr_id, target)
874 action_id = desc["action_id"]
875 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = action_id
876 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
877 self.logger.debug(logging_text + "ns terminate action at RO. action_id={}".format(action_id))
878
879 # wait until done
880 delete_timeout = 20 * 60 # 20 minutes
tierno2357f4e2020-10-19 16:38:59 +0000881 await self._wait_ng_ro(nsr_id, action_id, nslcmop_id, start_deploy, delete_timeout, stage)
tierno69f0d382020-05-07 13:08:09 +0000882
883 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
884 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
885 # delete all nsr
886 await self.RO.delete(nsr_id)
887 except Exception as e:
888 if isinstance(e, NgRoException) and e.http_code == 404: # not found
889 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
890 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
891 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
892 self.logger.debug(logging_text + "RO_action_id={} already deleted".format(action_id))
893 elif isinstance(e, NgRoException) and e.http_code == 409: # conflict
894 failed_detail.append("delete conflict: {}".format(e))
895 self.logger.debug(logging_text + "RO_action_id={} delete conflict: {}".format(action_id, e))
896 else:
897 failed_detail.append("delete error: {}".format(e))
898 self.logger.error(logging_text + "RO_action_id={} delete error: {}".format(action_id, e))
899
900 if failed_detail:
901 stage[2] = "Error deleting from VIM"
902 else:
903 stage[2] = "Deleted from VIM"
904 db_nsr_update["detailed-status"] = " ".join(stage)
905 self.update_db_2("nsrs", nsr_id, db_nsr_update)
906 self._write_op_status(nslcmop_id, stage)
907
908 if failed_detail:
909 raise LcmException("; ".join(failed_detail))
910 return
911
bravof922c4172020-11-24 21:21:43 -0300912 async def instantiate_RO(self, logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs, db_vnfds,
tiernoe876f672020-02-13 14:34:48 +0000913 n2vc_key_list, stage):
tiernoe95ed362020-04-23 08:24:57 +0000914 """
915 Instantiate at RO
916 :param logging_text: preffix text to use at logging
917 :param nsr_id: nsr identity
918 :param nsd: database content of ns descriptor
919 :param db_nsr: database content of ns record
920 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
921 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -0300922 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +0000923 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
924 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
925 :return: None or exception
926 """
tiernoe876f672020-02-13 14:34:48 +0000927 try:
tiernoe876f672020-02-13 14:34:48 +0000928 start_deploy = time()
929 ns_params = db_nslcmop.get("operationParams")
930 if ns_params and ns_params.get("timeout_ns_deploy"):
931 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
932 else:
933 timeout_ns_deploy = self.timeout.get("ns_deploy", self.timeout_ns_deploy)
quilesj7e13aeb2019-10-08 13:34:55 +0200934
tiernoe876f672020-02-13 14:34:48 +0000935 # Check for and optionally request placement optimization. Database will be updated if placement activated
936 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +0000937 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
938 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
939 for vnfr in db_vnfrs.values():
940 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
941 break
942 else:
943 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +0200944
bravof922c4172020-11-24 21:21:43 -0300945 return await self._instantiate_ng_ro(logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs,
946 db_vnfds, n2vc_key_list, stage, start_deploy, timeout_ns_deploy)
tierno2357f4e2020-10-19 16:38:59 +0000947 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +0000948 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +0000949 self.set_vnfr_at_error(db_vnfrs, str(e))
tierno2357f4e2020-10-19 16:38:59 +0000950 self.logger.error("Error deploying at VIM {}".format(e),
951 exc_info=not isinstance(e, (ROclient.ROClientException, LcmException, DbException,
952 NgRoException)))
tiernoe876f672020-02-13 14:34:48 +0000953 raise
quilesj7e13aeb2019-10-08 13:34:55 +0200954
tierno7ecbc342020-09-21 14:05:39 +0000955 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
956 """
957 Wait for kdu to be up, get ip address
958 :param logging_text: prefix use for logging
959 :param nsr_id:
960 :param vnfr_id:
961 :param kdu_name:
962 :return: IP address
963 """
964
965 # self.logger.debug(logging_text + "Starting wait_kdu_up")
966 nb_tries = 0
967
968 while nb_tries < 360:
969 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
tiernoe5d05972020-10-09 12:03:24 +0000970 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 +0000971 if not kdur:
972 raise LcmException("Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name))
973 if kdur.get("status"):
974 if kdur["status"] in ("READY", "ENABLED"):
975 return kdur.get("ip-address")
976 else:
977 raise LcmException("target KDU={} is in error state".format(kdu_name))
978
979 await asyncio.sleep(10, loop=self.loop)
980 nb_tries += 1
981 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
982
tiernoa5088192019-11-26 16:12:53 +0000983 async def wait_vm_up_insert_key_ro(self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None):
984 """
985 Wait for ip addres at RO, and optionally, insert public key in virtual machine
986 :param logging_text: prefix use for logging
987 :param nsr_id:
988 :param vnfr_id:
989 :param vdu_id:
990 :param vdu_index:
991 :param pub_key: public ssh key to inject, None to skip
992 :param user: user to apply the public ssh key
993 :return: IP address
994 """
quilesj7e13aeb2019-10-08 13:34:55 +0200995
tierno2357f4e2020-10-19 16:38:59 +0000996 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +0000997 ro_nsr_id = None
998 ip_address = None
999 nb_tries = 0
1000 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +00001001 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +02001002
tiernod8323042019-08-09 11:32:23 +00001003 while True:
quilesj7e13aeb2019-10-08 13:34:55 +02001004
quilesj3149f262019-12-03 10:58:10 +00001005 ro_retries += 1
1006 if ro_retries >= 360: # 1 hour
1007 raise LcmException("Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id))
1008
tiernod8323042019-08-09 11:32:23 +00001009 await asyncio.sleep(10, loop=self.loop)
quilesj7e13aeb2019-10-08 13:34:55 +02001010
1011 # get ip address
tiernod8323042019-08-09 11:32:23 +00001012 if not target_vdu_id:
1013 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +00001014
1015 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +00001016 if db_vnfr.get("status") == "ERROR":
1017 raise LcmException("Cannot inject ssh-key because target VNF is in error state")
tiernod8323042019-08-09 11:32:23 +00001018 ip_address = db_vnfr.get("ip-address")
1019 if not ip_address:
1020 continue
quilesj3149f262019-12-03 10:58:10 +00001021 vdur = next((x for x in get_iterable(db_vnfr, "vdur") if x.get("ip-address") == ip_address), None)
1022 else: # VDU case
1023 vdur = next((x for x in get_iterable(db_vnfr, "vdur")
1024 if x.get("vdu-id-ref") == vdu_id and x.get("count-index") == vdu_index), None)
1025
tierno0e8c3f02020-03-12 17:18:21 +00001026 if not vdur and len(db_vnfr.get("vdur", ())) == 1: # If only one, this should be the target vdu
1027 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001028 if not vdur:
tierno0e8c3f02020-03-12 17:18:21 +00001029 raise LcmException("Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(vnfr_id, vdu_id,
1030 vdu_index))
tierno2357f4e2020-10-19 16:38:59 +00001031 # New generation RO stores information at "vim_info"
1032 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001033 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001034 if vdur.get("vim_info"):
1035 target_vim = next(t for t in vdur["vim_info"]) # there should be only one key
1036 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
1037 if vdur.get("pdu-type") or vdur.get("status") == "ACTIVE" or ng_ro_status == "ACTIVE":
quilesj3149f262019-12-03 10:58:10 +00001038 ip_address = vdur.get("ip-address")
1039 if not ip_address:
1040 continue
1041 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001042 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
quilesj3149f262019-12-03 10:58:10 +00001043 raise LcmException("Cannot inject ssh-key because target VM is in error state")
1044
tiernod8323042019-08-09 11:32:23 +00001045 if not target_vdu_id:
1046 continue
tiernod8323042019-08-09 11:32:23 +00001047
quilesj7e13aeb2019-10-08 13:34:55 +02001048 # inject public key into machine
1049 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001050 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001051 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001052 if vdur.get("pdu-type"):
1053 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1054 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001055 try:
1056 ro_vm_id = "{}-{}".format(db_vnfr["member-vnf-index-ref"], target_vdu_id) # TODO add vdu_index
tierno69f0d382020-05-07 13:08:09 +00001057 if self.ng_ro:
bravof922c4172020-11-24 21:21:43 -03001058 target = {"action": {"action": "inject_ssh_key", "key": pub_key, "user": user},
tierno2357f4e2020-10-19 16:38:59 +00001059 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
tierno69f0d382020-05-07 13:08:09 +00001060 }
tierno2357f4e2020-10-19 16:38:59 +00001061 desc = await self.RO.deploy(nsr_id, target)
1062 action_id = desc["action_id"]
1063 await self._wait_ng_ro(nsr_id, action_id, timeout=600)
1064 break
tierno69f0d382020-05-07 13:08:09 +00001065 else:
tierno2357f4e2020-10-19 16:38:59 +00001066 # wait until NS is deployed at RO
1067 if not ro_nsr_id:
1068 db_nsrs = self.db.get_one("nsrs", {"_id": nsr_id})
1069 ro_nsr_id = deep_get(db_nsrs, ("_admin", "deployed", "RO", "nsr_id"))
1070 if not ro_nsr_id:
1071 continue
tierno69f0d382020-05-07 13:08:09 +00001072 result_dict = await self.RO.create_action(
1073 item="ns",
1074 item_id_name=ro_nsr_id,
1075 descriptor={"add_public_key": pub_key, "vms": [ro_vm_id], "user": user}
1076 )
1077 # result_dict contains the format {VM-id: {vim_result: 200, description: text}}
1078 if not result_dict or not isinstance(result_dict, dict):
1079 raise LcmException("Unknown response from RO when injecting key")
1080 for result in result_dict.values():
1081 if result.get("vim_result") == 200:
1082 break
1083 else:
1084 raise ROclient.ROClientException("error injecting key: {}".format(
1085 result.get("description")))
1086 break
1087 except NgRoException as e:
1088 raise LcmException("Reaching max tries injecting key. Error: {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02001089 except ROclient.ROClientException as e:
tiernoa5088192019-11-26 16:12:53 +00001090 if not nb_tries:
1091 self.logger.debug(logging_text + "error injecting key: {}. Retrying until {} seconds".
1092 format(e, 20*10))
quilesj7e13aeb2019-10-08 13:34:55 +02001093 nb_tries += 1
tiernoa5088192019-11-26 16:12:53 +00001094 if nb_tries >= 20:
quilesj7e13aeb2019-10-08 13:34:55 +02001095 raise LcmException("Reaching max tries injecting key. Error: {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02001096 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001097 break
1098
1099 return ip_address
1100
tierno5ee02052019-12-05 19:55:02 +00001101 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1102 """
1103 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1104 """
1105 my_vca = vca_deployed_list[vca_index]
1106 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001107 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001108 return
1109 timeout = 300
1110 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001111 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1112 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1113 configuration_status_list = db_nsr["configurationStatus"]
1114 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001115 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001116 # myself
tierno5ee02052019-12-05 19:55:02 +00001117 continue
1118 if not my_vca.get("member-vnf-index") or \
1119 (vca_deployed.get("member-vnf-index") == my_vca.get("member-vnf-index")):
quilesj3655ae02019-12-12 16:08:35 +00001120 internal_status = configuration_status_list[index].get("status")
1121 if internal_status == 'READY':
1122 continue
1123 elif internal_status == 'BROKEN':
tierno5ee02052019-12-05 19:55:02 +00001124 raise LcmException("Configuration aborted because dependent charm/s has failed")
quilesj3655ae02019-12-12 16:08:35 +00001125 else:
1126 break
tierno5ee02052019-12-05 19:55:02 +00001127 else:
quilesj3655ae02019-12-12 16:08:35 +00001128 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001129 return
1130 await asyncio.sleep(10)
1131 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001132
1133 raise LcmException("Configuration aborted because dependent charm/s timeout")
1134
tiernoe876f672020-02-13 14:34:48 +00001135 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 +00001136 config_descriptor, deploy_params, base_folder, nslcmop_id, stage, vca_type, vca_name,
1137 ee_config_descriptor):
tiernod8323042019-08-09 11:32:23 +00001138 nsr_id = db_nsr["_id"]
1139 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001140 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001141 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001142 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001143 db_dict = {
1144 'collection': 'nsrs',
1145 'filter': {'_id': nsr_id},
1146 'path': db_update_entry
1147 }
tiernod8323042019-08-09 11:32:23 +00001148 step = ""
1149 try:
quilesj3655ae02019-12-12 16:08:35 +00001150
1151 element_type = 'NS'
1152 element_under_configuration = nsr_id
1153
tiernod8323042019-08-09 11:32:23 +00001154 vnfr_id = None
1155 if db_vnfr:
1156 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001157 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001158
1159 namespace = "{nsi}.{ns}".format(
1160 nsi=nsi_id if nsi_id else "",
1161 ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001162
tiernod8323042019-08-09 11:32:23 +00001163 if vnfr_id:
quilesj3655ae02019-12-12 16:08:35 +00001164 element_type = 'VNF'
1165 element_under_configuration = vnfr_id
quilesjb8a35dd2020-01-09 15:10:14 +00001166 namespace += ".{}".format(vnfr_id)
tiernod8323042019-08-09 11:32:23 +00001167 if vdu_id:
1168 namespace += ".{}-{}".format(vdu_id, vdu_index or 0)
quilesj3655ae02019-12-12 16:08:35 +00001169 element_type = 'VDU'
quilesjb8a35dd2020-01-09 15:10:14 +00001170 element_under_configuration = "{}-{}".format(vdu_id, vdu_index or 0)
tiernob996d942020-07-03 14:52:28 +00001171 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001172 elif kdu_name:
1173 namespace += ".{}".format(kdu_name)
1174 element_type = 'KDU'
1175 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001176 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001177
1178 # Get artifact path
tierno588547c2020-07-01 15:30:20 +00001179 artifact_path = "{}/{}/{}/{}".format(
tiernod8323042019-08-09 11:32:23 +00001180 base_folder["folder"],
1181 base_folder["pkg-dir"],
tierno588547c2020-07-01 15:30:20 +00001182 "charms" if vca_type in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm") else "helm-charts",
1183 vca_name
tiernod8323042019-08-09 11:32:23 +00001184 )
bravof922c4172020-11-24 21:21:43 -03001185
1186 self.logger.debug("Artifact path > {}".format(artifact_path))
1187
tiernoa278b842020-07-08 15:33:55 +00001188 # get initial_config_primitive_list that applies to this element
1189 initial_config_primitive_list = config_descriptor.get('initial-config-primitive')
1190
bravof922c4172020-11-24 21:21:43 -03001191 self.logger.debug("Initial config primitive list > {}".format(initial_config_primitive_list))
1192
tiernoa278b842020-07-08 15:33:55 +00001193 # add config if not present for NS charm
1194 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001195 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
1196 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(initial_config_primitive_list,
1197 vca_deployed, ee_descriptor_id)
tiernod8323042019-08-09 11:32:23 +00001198
bravof922c4172020-11-24 21:21:43 -03001199 self.logger.debug("Initial config primitive list #2 > {}".format(initial_config_primitive_list))
tierno588547c2020-07-01 15:30:20 +00001200 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001201 # find old ee_id if exists
1202 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001203
David Garciaaae391f2020-11-09 11:12:54 +01001204 vim_account_id = (
1205 deep_get(db_vnfr, ("vim-account-id",)) or
1206 deep_get(deploy_params, ("OSM", "vim_account_id"))
1207 )
1208 vca_cloud, vca_cloud_credential = self.get_vca_cloud_and_credentials(vim_account_id)
1209 vca_k8s_cloud, vca_k8s_cloud_credential = self.get_vca_k8s_cloud_and_credentials(vim_account_id)
tierno588547c2020-07-01 15:30:20 +00001210 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001211 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
quilesj7e13aeb2019-10-08 13:34:55 +02001212
tierno588547c2020-07-01 15:30:20 +00001213 self._write_configuration_status(
1214 nsr_id=nsr_id,
1215 vca_index=vca_index,
1216 status='CREATING',
1217 element_under_configuration=element_under_configuration,
1218 element_type=element_type
1219 )
tiernod8323042019-08-09 11:32:23 +00001220
tierno588547c2020-07-01 15:30:20 +00001221 step = "create execution environment"
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001222 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001223
1224 ee_id = None
1225 credentials = None
1226 if vca_type == "k8s_proxy_charm":
1227 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
1228 charm_name=artifact_path[artifact_path.rfind("/") + 1:],
1229 namespace=namespace,
1230 artifact_path=artifact_path,
1231 db_dict=db_dict,
1232 cloud_name=vca_k8s_cloud,
1233 credential_name=vca_k8s_cloud_credential,
1234 )
David Garciaffbf6ed2021-02-25 20:19:18 +01001235 elif vca_type == "helm" or vca_type == "helm-v3":
bravof922c4172020-11-24 21:21:43 -03001236 ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
1237 namespace=namespace,
1238 reuse_ee_id=ee_id,
1239 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001240 config=osm_config,
1241 artifact_path=artifact_path,
1242 vca_type=vca_type
bravof922c4172020-11-24 21:21:43 -03001243 )
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001244 else:
David Garciaaae391f2020-11-09 11:12:54 +01001245 ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
1246 namespace=namespace,
1247 reuse_ee_id=ee_id,
1248 db_dict=db_dict,
David Garciaaae391f2020-11-09 11:12:54 +01001249 cloud_name=vca_cloud,
1250 credential_name=vca_cloud_credential,
1251 )
quilesj3655ae02019-12-12 16:08:35 +00001252
tierno588547c2020-07-01 15:30:20 +00001253 elif vca_type == "native_charm":
1254 step = "Waiting to VM being up and getting IP address"
1255 self.logger.debug(logging_text + step)
1256 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(logging_text, nsr_id, vnfr_id, vdu_id, vdu_index,
1257 user=None, pub_key=None)
1258 credentials = {"hostname": rw_mgmt_ip}
1259 # get username
1260 username = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user"))
1261 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1262 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001263 if not username and initial_config_primitive_list:
1264 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001265 for param in config_primitive.get("parameter", ()):
1266 if param["name"] == "ssh-username":
1267 username = param["value"]
1268 break
1269 if not username:
tiernoa278b842020-07-08 15:33:55 +00001270 raise LcmException("Cannot determine the username neither with 'initial-config-primitive' nor with "
tierno588547c2020-07-01 15:30:20 +00001271 "'config-access.ssh-access.default-user'")
1272 credentials["username"] = username
1273 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001274
tierno588547c2020-07-01 15:30:20 +00001275 self._write_configuration_status(
1276 nsr_id=nsr_id,
1277 vca_index=vca_index,
1278 status='REGISTERING',
1279 element_under_configuration=element_under_configuration,
1280 element_type=element_type
1281 )
quilesj3655ae02019-12-12 16:08:35 +00001282
tierno588547c2020-07-01 15:30:20 +00001283 step = "register execution environment {}".format(credentials)
1284 self.logger.debug(logging_text + step)
1285 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001286 credentials=credentials,
1287 namespace=namespace,
1288 db_dict=db_dict,
1289 cloud_name=vca_cloud,
1290 credential_name=vca_cloud_credential,
1291 )
tierno3bedc9b2019-11-27 15:46:57 +00001292
tierno588547c2020-07-01 15:30:20 +00001293 # for compatibility with MON/POL modules, the need model and application name at database
1294 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
1295 ee_id_parts = ee_id.split('.')
1296 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1297 if len(ee_id_parts) >= 2:
1298 model_name = ee_id_parts[0]
1299 application_name = ee_id_parts[1]
1300 db_nsr_update[db_update_entry + "model"] = model_name
1301 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001302
1303 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001304 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001305
tiernoc231a872020-01-21 08:49:05 +00001306 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001307 nsr_id=nsr_id,
1308 vca_index=vca_index,
1309 status='INSTALLING SW',
1310 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001311 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001312 other_update=db_nsr_update
quilesj3655ae02019-12-12 16:08:35 +00001313 )
1314
tierno3bedc9b2019-11-27 15:46:57 +00001315 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001316 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001317 config = None
tierno588547c2020-07-01 15:30:20 +00001318 if vca_type == "native_charm":
tiernoa278b842020-07-08 15:33:55 +00001319 config_primitive = next((p for p in initial_config_primitive_list if p["name"] == "config"), None)
1320 if config_primitive:
1321 config = self._map_primitive_params(
1322 config_primitive,
1323 {},
1324 deploy_params
1325 )
tierno588547c2020-07-01 15:30:20 +00001326 num_units = 1
1327 if vca_type == "lxc_proxy_charm":
1328 if element_type == "NS":
1329 num_units = db_nsr.get("config-units") or 1
1330 elif element_type == "VNF":
1331 num_units = db_vnfr.get("config-units") or 1
1332 elif element_type == "VDU":
1333 for v in db_vnfr["vdur"]:
1334 if vdu_id == v["vdu-id-ref"]:
1335 num_units = v.get("config-units") or 1
1336 break
David Garciaaae391f2020-11-09 11:12:54 +01001337 if vca_type != "k8s_proxy_charm":
1338 await self.vca_map[vca_type].install_configuration_sw(
1339 ee_id=ee_id,
1340 artifact_path=artifact_path,
1341 db_dict=db_dict,
1342 config=config,
1343 num_units=num_units,
1344 )
quilesj7e13aeb2019-10-08 13:34:55 +02001345
quilesj63f90042020-01-17 09:53:55 +00001346 # write in db flag of configuration_sw already installed
1347 self.update_db_2("nsrs", nsr_id, {db_update_entry + "config_sw_installed": True})
1348
1349 # add relations for this VCA (wait for other peers related with this VCA)
tierno588547c2020-07-01 15:30:20 +00001350 await self._add_vca_relations(logging_text=logging_text, nsr_id=nsr_id,
1351 vca_index=vca_index, vca_type=vca_type)
quilesj63f90042020-01-17 09:53:55 +00001352
quilesj7e13aeb2019-10-08 13:34:55 +02001353 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001354 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001355 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001356 pub_key = None
1357 user = None
tierno588547c2020-07-01 15:30:20 +00001358 # self.logger.debug("get ssh key block")
tierno3bedc9b2019-11-27 15:46:57 +00001359 if deep_get(config_descriptor, ("config-access", "ssh-access", "required")):
tierno588547c2020-07-01 15:30:20 +00001360 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001361 # Needed to inject a ssh key
1362 user = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user"))
1363 step = "Install configuration Software, getting public ssh key"
tierno588547c2020-07-01 15:30:20 +00001364 pub_key = await self.vca_map[vca_type].get_ee_ssh_public__key(ee_id=ee_id, db_dict=db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02001365
tiernoacc90452019-12-10 11:06:54 +00001366 step = "Insert public key into VM user={} ssh_key={}".format(user, pub_key)
tierno3bedc9b2019-11-27 15:46:57 +00001367 else:
tierno588547c2020-07-01 15:30:20 +00001368 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001369 step = "Waiting to VM being up and getting IP address"
1370 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001371
tierno3bedc9b2019-11-27 15:46:57 +00001372 # n2vc_redesign STEP 5.1
1373 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001374 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001375 if kdu_name:
1376 rw_mgmt_ip = await self.wait_kdu_up(logging_text, nsr_id, vnfr_id, kdu_name)
1377 else:
1378 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(logging_text, nsr_id, vnfr_id, vdu_id,
1379 vdu_index, user=user, pub_key=pub_key)
tierno5ee02052019-12-05 19:55:02 +00001380 else:
1381 rw_mgmt_ip = None # This is for a NS configuration
tierno3bedc9b2019-11-27 15:46:57 +00001382
1383 self.logger.debug(logging_text + ' VM_ip_address={}'.format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001384
tiernoa5088192019-11-26 16:12:53 +00001385 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001386 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001387
1388 # n2vc_redesign STEP 6 Execute initial config primitive
quilesj7e13aeb2019-10-08 13:34:55 +02001389 step = 'execute initial config primitive'
quilesj3655ae02019-12-12 16:08:35 +00001390
1391 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001392 if initial_config_primitive_list:
1393 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001394
1395 # stage, in function of element type: vdu, kdu, vnf or ns
1396 my_vca = vca_deployed_list[vca_index]
1397 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1398 # VDU or KDU
tiernoe876f672020-02-13 14:34:48 +00001399 stage[0] = 'Stage 3/5: running Day-1 primitives for VDU.'
quilesj3655ae02019-12-12 16:08:35 +00001400 elif my_vca.get("member-vnf-index"):
1401 # VNF
tiernoe876f672020-02-13 14:34:48 +00001402 stage[0] = 'Stage 4/5: running Day-1 primitives for VNF.'
quilesj3655ae02019-12-12 16:08:35 +00001403 else:
1404 # NS
tiernoe876f672020-02-13 14:34:48 +00001405 stage[0] = 'Stage 5/5: running Day-1 primitives for NS.'
quilesj3655ae02019-12-12 16:08:35 +00001406
tiernoc231a872020-01-21 08:49:05 +00001407 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001408 nsr_id=nsr_id,
1409 vca_index=vca_index,
1410 status='EXECUTING PRIMITIVE'
1411 )
1412
1413 self._write_op_status(
1414 op_id=nslcmop_id,
1415 stage=stage
1416 )
1417
tiernoe876f672020-02-13 14:34:48 +00001418 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001419 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001420 # adding information on the vca_deployed if it is a NS execution environment
1421 if not vca_deployed["member-vnf-index"]:
David Garciad4816682019-12-09 14:57:43 +01001422 deploy_params["ns_config_info"] = json.dumps(self._get_ns_config_info(nsr_id))
tiernod8323042019-08-09 11:32:23 +00001423 # TODO check if already done
1424 primitive_params_ = self._map_primitive_params(initial_config_primitive, {}, deploy_params)
tierno3bedc9b2019-11-27 15:46:57 +00001425
tiernod8323042019-08-09 11:32:23 +00001426 step = "execute primitive '{}' params '{}'".format(initial_config_primitive["name"], primitive_params_)
1427 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001428 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001429 ee_id=ee_id,
1430 primitive_name=initial_config_primitive["name"],
1431 params_dict=primitive_params_,
1432 db_dict=db_dict
1433 )
tiernoe876f672020-02-13 14:34:48 +00001434 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1435 if check_if_terminated_needed:
1436 if config_descriptor.get('terminate-config-primitive'):
1437 self.update_db_2("nsrs", nsr_id, {db_update_entry + "needed_terminate": True})
1438 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001439
tiernod8323042019-08-09 11:32:23 +00001440 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001441
tiernob996d942020-07-03 14:52:28 +00001442 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001443 if vca_type == "helm" or vca_type == "helm-v3":
tiernob996d942020-07-03 14:52:28 +00001444 prometheus_jobs = await self.add_prometheus_metrics(
1445 ee_id=ee_id,
1446 artifact_path=artifact_path,
1447 ee_config_descriptor=ee_config_descriptor,
1448 vnfr_id=vnfr_id,
1449 nsr_id=nsr_id,
1450 target_ip=rw_mgmt_ip,
1451 )
1452 if prometheus_jobs:
1453 self.update_db_2("nsrs", nsr_id, {db_update_entry + "prometheus_jobs": prometheus_jobs})
1454
quilesj7e13aeb2019-10-08 13:34:55 +02001455 step = "instantiated at VCA"
1456 self.logger.debug(logging_text + step)
1457
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='READY'
1462 )
1463
tiernod8323042019-08-09 11:32:23 +00001464 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00001465 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
tiernoe876f672020-02-13 14:34:48 +00001466 if not isinstance(e, (DbException, N2VCException, LcmException, asyncio.CancelledError)):
1467 self.logger.error("Exception while {} : {}".format(step, e), exc_info=True)
tiernoc231a872020-01-21 08:49:05 +00001468 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001469 nsr_id=nsr_id,
1470 vca_index=vca_index,
1471 status='BROKEN'
1472 )
tiernoe876f672020-02-13 14:34:48 +00001473 raise LcmException("{} {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00001474
quilesj4cda56b2019-12-05 10:02:20 +00001475 def _write_ns_status(self, nsr_id: str, ns_state: str, current_operation: str, current_operation_id: str,
tiernoa2143262020-03-27 16:20:40 +00001476 error_description: str = None, error_detail: str = None, other_update: dict = None):
tiernoe876f672020-02-13 14:34:48 +00001477 """
1478 Update db_nsr fields.
1479 :param nsr_id:
1480 :param ns_state:
1481 :param current_operation:
1482 :param current_operation_id:
1483 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00001484 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00001485 :param other_update: Other required changes at database if provided, will be cleared
1486 :return:
1487 """
quilesj4cda56b2019-12-05 10:02:20 +00001488 try:
tiernoe876f672020-02-13 14:34:48 +00001489 db_dict = other_update or {}
1490 db_dict["_admin.nslcmop"] = current_operation_id # for backward compatibility
1491 db_dict["_admin.current-operation"] = current_operation_id
1492 db_dict["_admin.operation-type"] = current_operation if current_operation != "IDLE" else None
quilesj4cda56b2019-12-05 10:02:20 +00001493 db_dict["currentOperation"] = current_operation
1494 db_dict["currentOperationID"] = current_operation_id
1495 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00001496 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00001497
1498 if ns_state:
1499 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00001500 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001501 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001502 self.logger.warn('Error writing NS status, ns={}: {}'.format(nsr_id, e))
1503
tiernoe876f672020-02-13 14:34:48 +00001504 def _write_op_status(self, op_id: str, stage: list = None, error_message: str = None, queuePosition: int = 0,
1505 operation_state: str = None, other_update: dict = None):
quilesj3655ae02019-12-12 16:08:35 +00001506 try:
tiernoe876f672020-02-13 14:34:48 +00001507 db_dict = other_update or {}
quilesj3655ae02019-12-12 16:08:35 +00001508 db_dict['queuePosition'] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00001509 if isinstance(stage, list):
1510 db_dict['stage'] = stage[0]
1511 db_dict['detailed-status'] = " ".join(stage)
1512 elif stage is not None:
1513 db_dict['stage'] = str(stage)
1514
1515 if error_message is not None:
quilesj3655ae02019-12-12 16:08:35 +00001516 db_dict['errorMessage'] = error_message
tiernoe876f672020-02-13 14:34:48 +00001517 if operation_state is not None:
1518 db_dict['operationState'] = operation_state
1519 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00001520 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001521 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001522 self.logger.warn('Error writing OPERATION status for op_id: {} -> {}'.format(op_id, e))
1523
tierno51183952020-04-03 15:48:18 +00001524 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00001525 try:
tierno51183952020-04-03 15:48:18 +00001526 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00001527 # configurationStatus
1528 config_status = db_nsr.get('configurationStatus')
1529 if config_status:
tierno51183952020-04-03 15:48:18 +00001530 db_nsr_update = {"configurationStatus.{}.status".format(index): status for index, v in
1531 enumerate(config_status) if v}
quilesj3655ae02019-12-12 16:08:35 +00001532 # update status
tierno51183952020-04-03 15:48:18 +00001533 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00001534
tiernoe876f672020-02-13 14:34:48 +00001535 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001536 self.logger.warn('Error writing all configuration status, ns={}: {}'.format(nsr_id, e))
1537
quilesj63f90042020-01-17 09:53:55 +00001538 def _write_configuration_status(self, nsr_id: str, vca_index: int, status: str = None,
tierno51183952020-04-03 15:48:18 +00001539 element_under_configuration: str = None, element_type: str = None,
1540 other_update: dict = None):
quilesj3655ae02019-12-12 16:08:35 +00001541
1542 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
1543 # .format(vca_index, status))
1544
1545 try:
1546 db_path = 'configurationStatus.{}.'.format(vca_index)
tierno51183952020-04-03 15:48:18 +00001547 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00001548 if status:
1549 db_dict[db_path + 'status'] = status
quilesj3655ae02019-12-12 16:08:35 +00001550 if element_under_configuration:
1551 db_dict[db_path + 'elementUnderConfiguration'] = element_under_configuration
1552 if element_type:
1553 db_dict[db_path + 'elementType'] = element_type
1554 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001555 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001556 self.logger.warn('Error writing configuration status={}, ns={}, vca_index={}: {}'
1557 .format(status, nsr_id, vca_index, e))
quilesj4cda56b2019-12-05 10:02:20 +00001558
tierno38089af2020-04-16 07:56:58 +00001559 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
1560 """
1561 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
1562 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
1563 Database is used because the result can be obtained from a different LCM worker in case of HA.
1564 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
1565 :param db_nslcmop: database content of nslcmop
1566 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00001567 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
1568 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00001569 """
tierno8790a3d2020-04-23 22:49:52 +00001570 modified = False
tierno38089af2020-04-16 07:56:58 +00001571 nslcmop_id = db_nslcmop['_id']
magnussonle9198bb2020-01-21 13:00:51 +01001572 placement_engine = deep_get(db_nslcmop, ('operationParams', 'placement-engine'))
1573 if placement_engine == "PLA":
tierno38089af2020-04-16 07:56:58 +00001574 self.logger.debug(logging_text + "Invoke and wait for placement optimization")
1575 await self.msg.aiowrite("pla", "get_placement", {'nslcmopId': nslcmop_id}, loop=self.loop)
magnussonle9198bb2020-01-21 13:00:51 +01001576 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00001577 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01001578 pla_result = None
1579 while not pla_result and wait >= 0:
1580 await asyncio.sleep(db_poll_interval)
1581 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00001582 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01001583 pla_result = deep_get(db_nslcmop, ('_admin', 'pla'))
1584
1585 if not pla_result:
tierno38089af2020-04-16 07:56:58 +00001586 raise LcmException("Placement timeout for nslcmopId={}".format(nslcmop_id))
magnussonle9198bb2020-01-21 13:00:51 +01001587
1588 for pla_vnf in pla_result['vnf']:
1589 vnfr = db_vnfrs.get(pla_vnf['member-vnf-index'])
1590 if not pla_vnf.get('vimAccountId') or not vnfr:
1591 continue
tierno8790a3d2020-04-23 22:49:52 +00001592 modified = True
magnussonle9198bb2020-01-21 13:00:51 +01001593 self.db.set_one("vnfrs", {"_id": vnfr["_id"]}, {"vim-account-id": pla_vnf['vimAccountId']})
tierno38089af2020-04-16 07:56:58 +00001594 # Modifies db_vnfrs
1595 vnfr["vim-account-id"] = pla_vnf['vimAccountId']
tierno8790a3d2020-04-23 22:49:52 +00001596 return modified
magnussonle9198bb2020-01-21 13:00:51 +01001597
1598 def update_nsrs_with_pla_result(self, params):
1599 try:
1600 nslcmop_id = deep_get(params, ('placement', 'nslcmopId'))
1601 self.update_db_2("nslcmops", nslcmop_id, {"_admin.pla": params.get('placement')})
1602 except Exception as e:
1603 self.logger.warn('Update failed for nslcmop_id={}:{}'.format(nslcmop_id, e))
1604
tierno59d22d22018-09-25 18:10:19 +02001605 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02001606 """
1607
1608 :param nsr_id: ns instance to deploy
1609 :param nslcmop_id: operation to run
1610 :return:
1611 """
kuused124bfe2019-06-18 12:09:24 +02001612
1613 # Try to lock HA task here
1614 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
1615 if not task_is_locked_by_me:
quilesj3655ae02019-12-12 16:08:35 +00001616 self.logger.debug('instantiate() task is not locked by me, ns={}'.format(nsr_id))
kuused124bfe2019-06-18 12:09:24 +02001617 return
1618
tierno59d22d22018-09-25 18:10:19 +02001619 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
1620 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02001621
tierno59d22d22018-09-25 18:10:19 +02001622 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02001623
1624 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02001625 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02001626
1627 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02001628 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02001629
1630 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00001631 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02001632 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02001633 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02001634
tierno59d22d22018-09-25 18:10:19 +02001635 nslcmop_operation_state = None
quilesj7e13aeb2019-10-08 13:34:55 +02001636 db_vnfrs = {} # vnf's info indexed by member-index
1637 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00001638 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02001639 exc = None
tiernoe876f672020-02-13 14:34:48 +00001640 error_list = []
1641 stage = ['Stage 1/5: preparation of the environment.', "Waiting for previous operations to terminate.", ""]
1642 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02001643 try:
kuused124bfe2019-06-18 12:09:24 +02001644 # wait for any previous tasks in process
1645 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
1646
tiernob5203912020-08-11 11:20:13 +00001647 stage[1] = "Sync filesystem from database."
tierno21e42212020-07-09 13:51:20 +00001648 self.fs.sync() # TODO, make use of partial sync, only for the needed packages
1649
quilesj7e13aeb2019-10-08 13:34:55 +02001650 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00001651 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00001652 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00001653 db_nsr_update["detailed-status"] = "creating"
1654 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00001655 self._write_ns_status(
1656 nsr_id=nsr_id,
1657 ns_state="BUILDING",
1658 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00001659 current_operation_id=nslcmop_id,
1660 other_update=db_nsr_update
1661 )
1662 self._write_op_status(
1663 op_id=nslcmop_id,
1664 stage=stage,
1665 queuePosition=0
quilesj4cda56b2019-12-05 10:02:20 +00001666 )
1667
quilesj7e13aeb2019-10-08 13:34:55 +02001668 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00001669 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02001670 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
tierno744303e2020-01-13 16:46:31 +00001671 ns_params = db_nslcmop.get("operationParams")
1672 if ns_params and ns_params.get("timeout_ns_deploy"):
1673 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1674 else:
1675 timeout_ns_deploy = self.timeout.get("ns_deploy", self.timeout_ns_deploy)
quilesj7e13aeb2019-10-08 13:34:55 +02001676
1677 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00001678 stage[1] = "Getting nsr={} from db.".format(nsr_id)
tierno59d22d22018-09-25 18:10:19 +02001679 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00001680 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00001681 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
1682 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00001683 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02001684
quilesj7e13aeb2019-10-08 13:34:55 +02001685 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00001686 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00001687 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02001688 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02001689
quilesj7e13aeb2019-10-08 13:34:55 +02001690 # read from db: vnfd's for every vnf
bravof922c4172020-11-24 21:21:43 -03001691 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02001692
1693 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02001694 for vnfr in db_vnfrs_list:
bravof922c4172020-11-24 21:21:43 -03001695 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
1696 vnfd_id = vnfr["vnfd-id"]
1697 vnfd_ref = vnfr["vnfd-ref"]
lloretgalleg6d488782020-07-22 10:13:46 +00001698
quilesj7e13aeb2019-10-08 13:34:55 +02001699 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02001700 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00001701 # read from db
tiernob5203912020-08-11 11:20:13 +00001702 stage[1] = "Getting vnfd={} id='{}' from db.".format(vnfd_id, vnfd_ref)
tiernoe876f672020-02-13 14:34:48 +00001703 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02001704 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02001705
quilesj7e13aeb2019-10-08 13:34:55 +02001706 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01001707 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02001708
1709 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00001710 vca_deployed_list = None
1711 if db_nsr["_admin"].get("deployed"):
1712 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
1713 if vca_deployed_list is None:
1714 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00001715 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00001716 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00001717 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02001718 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00001719 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00001720 elif isinstance(vca_deployed_list, dict):
1721 # maintain backward compatibility. Change a dict to list at database
1722 vca_deployed_list = list(vca_deployed_list.values())
1723 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00001724 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00001725
tierno6cf25f52019-09-12 09:33:40 +00001726 if not isinstance(deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list):
tiernoa009e552019-01-30 16:45:44 +00001727 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
1728 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02001729
tiernobaa51102018-12-14 13:16:18 +00001730 # set state to INSTANTIATED. When instantiated NBI will not delete directly
1731 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
1732 self.update_db_2("nsrs", nsr_id, db_nsr_update)
lloretgalleg6d488782020-07-22 10:13:46 +00001733 self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"})
quilesj3655ae02019-12-12 16:08:35 +00001734
1735 # n2vc_redesign STEP 2 Deploy Network Scenario
tiernoe876f672020-02-13 14:34:48 +00001736 stage[0] = 'Stage 2/5: deployment of KDUs, VMs and execution environments.'
quilesj3655ae02019-12-12 16:08:35 +00001737 self._write_op_status(
1738 op_id=nslcmop_id,
tiernoe876f672020-02-13 14:34:48 +00001739 stage=stage
quilesj3655ae02019-12-12 16:08:35 +00001740 )
1741
tiernob5203912020-08-11 11:20:13 +00001742 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00001743 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01001744 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00001745 await self.deploy_kdus(
1746 logging_text=logging_text,
1747 nsr_id=nsr_id,
1748 nslcmop_id=nslcmop_id,
1749 db_vnfrs=db_vnfrs,
1750 db_vnfds=db_vnfds,
1751 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001752 )
tiernoe876f672020-02-13 14:34:48 +00001753
1754 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00001755 # n2vc_redesign STEP 1 Get VCA public ssh-key
1756 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00001757 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00001758 n2vc_key_list = [n2vc_key]
1759 if self.vca_config.get("public_key"):
1760 n2vc_key_list.append(self.vca_config["public_key"])
tierno98ad6ea2019-05-30 17:16:28 +00001761
tiernoe876f672020-02-13 14:34:48 +00001762 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00001763 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02001764 self.instantiate_RO(
1765 logging_text=logging_text,
1766 nsr_id=nsr_id,
1767 nsd=nsd,
1768 db_nsr=db_nsr,
1769 db_nslcmop=db_nslcmop,
1770 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03001771 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00001772 n2vc_key_list=n2vc_key_list,
1773 stage=stage
tierno98ad6ea2019-05-30 17:16:28 +00001774 )
tiernod8323042019-08-09 11:32:23 +00001775 )
1776 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00001777 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00001778
tiernod8323042019-08-09 11:32:23 +00001779 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00001780 stage[1] = "Deploying Execution Environments."
1781 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00001782
tiernod8323042019-08-09 11:32:23 +00001783 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03001784 for vnf_profile in get_vnf_profiles(nsd):
1785 vnfd_id = vnf_profile["vnfd-id"]
1786 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
1787 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00001788 db_vnfr = db_vnfrs[member_vnf_index]
1789 base_folder = vnfd["_admin"]["storage"]
1790 vdu_id = None
1791 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00001792 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001793 kdu_name = None
tierno59d22d22018-09-25 18:10:19 +02001794
tierno8a518872018-12-21 13:42:14 +00001795 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03001796 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00001797 if db_vnfr.get("additionalParamsForVnf"):
bravof922c4172020-11-24 21:21:43 -03001798 deploy_params.update(parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy()))
tierno8a518872018-12-21 13:42:14 +00001799
garciaalea77ced72021-02-17 19:09:12 -03001800 descriptor_config = get_configuration(vnfd, vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00001801 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02001802 self._deploy_n2vc(
tiernoa54150d2019-12-05 17:15:10 +00001803 logging_text=logging_text + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02001804 db_nsr=db_nsr,
1805 db_vnfr=db_vnfr,
1806 nslcmop_id=nslcmop_id,
1807 nsr_id=nsr_id,
1808 nsi_id=nsi_id,
1809 vnfd_id=vnfd_id,
1810 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001811 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001812 member_vnf_index=member_vnf_index,
1813 vdu_index=vdu_index,
1814 vdu_name=vdu_name,
1815 deploy_params=deploy_params,
1816 descriptor_config=descriptor_config,
1817 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00001818 task_instantiation_info=tasks_dict_info,
1819 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001820 )
tierno59d22d22018-09-25 18:10:19 +02001821
1822 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03001823 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00001824 vdu_id = vdud["id"]
garciaalea77ced72021-02-17 19:09:12 -03001825 descriptor_config = get_configuration(vnfd, vdu_id)
bravof922c4172020-11-24 21:21:43 -03001826 vdur = find_in_list(db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id)
1827
tierno626e0152019-11-29 14:16:16 +00001828 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03001829 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00001830 else:
1831 deploy_params_vdu = deploy_params
bravof922c4172020-11-24 21:21:43 -03001832 deploy_params_vdu["OSM"] = get_osm_params(db_vnfr, vdu_id, vdu_count_index=0)
1833 vdud_count = get_vdu_profile(vnfd, vdu_id).get("max-number-of-instances", 1)
1834
1835 self.logger.debug("VDUD > {}".format(vdud))
1836 self.logger.debug("Descriptor config > {}".format(descriptor_config))
tierno588547c2020-07-01 15:30:20 +00001837 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00001838 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001839 kdu_name = None
bravof922c4172020-11-24 21:21:43 -03001840 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00001841 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02001842 self._deploy_n2vc(
tiernoa54150d2019-12-05 17:15:10 +00001843 logging_text=logging_text + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
1844 member_vnf_index, vdu_id, vdu_index),
quilesj7e13aeb2019-10-08 13:34:55 +02001845 db_nsr=db_nsr,
1846 db_vnfr=db_vnfr,
1847 nslcmop_id=nslcmop_id,
1848 nsr_id=nsr_id,
1849 nsi_id=nsi_id,
1850 vnfd_id=vnfd_id,
1851 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001852 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001853 member_vnf_index=member_vnf_index,
1854 vdu_index=vdu_index,
1855 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00001856 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02001857 descriptor_config=descriptor_config,
1858 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001859 task_instantiation_info=tasks_dict_info,
1860 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001861 )
bravof922c4172020-11-24 21:21:43 -03001862 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01001863 kdu_name = kdud["name"]
garciaalea77ced72021-02-17 19:09:12 -03001864 descriptor_config = get_configuration(vnfd, kdu_name)
tierno588547c2020-07-01 15:30:20 +00001865 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01001866 vdu_id = None
1867 vdu_index = 0
1868 vdu_name = None
tierno72ef84f2020-10-06 08:22:07 +00001869 kdur = next(x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name)
bravof922c4172020-11-24 21:21:43 -03001870 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00001871 if kdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03001872 deploy_params_kdu = parse_yaml_strings(kdur["additionalParams"])
tierno59d22d22018-09-25 18:10:19 +02001873
calvinosanch9f9c6f22019-11-04 13:37:39 +01001874 self._deploy_n2vc(
1875 logging_text=logging_text,
1876 db_nsr=db_nsr,
1877 db_vnfr=db_vnfr,
1878 nslcmop_id=nslcmop_id,
1879 nsr_id=nsr_id,
1880 nsi_id=nsi_id,
1881 vnfd_id=vnfd_id,
1882 vdu_id=vdu_id,
1883 kdu_name=kdu_name,
1884 member_vnf_index=member_vnf_index,
1885 vdu_index=vdu_index,
1886 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00001887 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001888 descriptor_config=descriptor_config,
1889 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001890 task_instantiation_info=tasks_dict_info,
1891 stage=stage
calvinosanch9f9c6f22019-11-04 13:37:39 +01001892 )
tierno59d22d22018-09-25 18:10:19 +02001893
tierno1b633412019-02-25 16:48:23 +00001894 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00001895 descriptor_config = nsd.get("ns-configuration")
1896 if descriptor_config and descriptor_config.get("juju"):
1897 vnfd_id = None
1898 db_vnfr = None
1899 member_vnf_index = None
1900 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001901 kdu_name = None
tiernod8323042019-08-09 11:32:23 +00001902 vdu_index = 0
1903 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00001904
tiernod8323042019-08-09 11:32:23 +00001905 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01001906 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00001907 if db_nsr.get("additionalParamsForNs"):
bravof922c4172020-11-24 21:21:43 -03001908 deploy_params.update(parse_yaml_strings(db_nsr["additionalParamsForNs"].copy()))
tiernod8323042019-08-09 11:32:23 +00001909 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02001910 self._deploy_n2vc(
1911 logging_text=logging_text,
1912 db_nsr=db_nsr,
1913 db_vnfr=db_vnfr,
1914 nslcmop_id=nslcmop_id,
1915 nsr_id=nsr_id,
1916 nsi_id=nsi_id,
1917 vnfd_id=vnfd_id,
1918 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001919 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001920 member_vnf_index=member_vnf_index,
1921 vdu_index=vdu_index,
1922 vdu_name=vdu_name,
1923 deploy_params=deploy_params,
1924 descriptor_config=descriptor_config,
1925 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001926 task_instantiation_info=tasks_dict_info,
1927 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001928 )
tierno1b633412019-02-25 16:48:23 +00001929
tiernoe876f672020-02-13 14:34:48 +00001930 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00001931
tiernoe876f672020-02-13 14:34:48 +00001932 except (ROclient.ROClientException, DbException, LcmException, N2VCException) as e:
1933 self.logger.error(logging_text + "Exit Exception while '{}': {}".format(stage[1], e))
tierno59d22d22018-09-25 18:10:19 +02001934 exc = e
1935 except asyncio.CancelledError:
tiernoe876f672020-02-13 14:34:48 +00001936 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(stage[1]))
tierno59d22d22018-09-25 18:10:19 +02001937 exc = "Operation was cancelled"
1938 except Exception as e:
1939 exc = traceback.format_exc()
tiernoe876f672020-02-13 14:34:48 +00001940 self.logger.critical(logging_text + "Exit Exception while '{}': {}".format(stage[1], e), exc_info=True)
tierno59d22d22018-09-25 18:10:19 +02001941 finally:
1942 if exc:
tiernoe876f672020-02-13 14:34:48 +00001943 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00001944 try:
tiernoe876f672020-02-13 14:34:48 +00001945 # wait for pending tasks
1946 if tasks_dict_info:
1947 stage[1] = "Waiting for instantiate pending tasks."
1948 self.logger.debug(logging_text + stage[1])
1949 error_list += await self._wait_for_tasks(logging_text, tasks_dict_info, timeout_ns_deploy,
1950 stage, nslcmop_id, nsr_id=nsr_id)
1951 stage[1] = stage[2] = ""
1952 except asyncio.CancelledError:
1953 error_list.append("Cancelled")
1954 # TODO cancel all tasks
1955 except Exception as exc:
1956 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00001957
tiernoe876f672020-02-13 14:34:48 +00001958 # update operation-status
1959 db_nsr_update["operational-status"] = "running"
1960 # let's begin with VCA 'configured' status (later we can change it)
1961 db_nsr_update["config-status"] = "configured"
1962 for task, task_name in tasks_dict_info.items():
1963 if not task.done() or task.cancelled() or task.exception():
1964 if task_name.startswith(self.task_name_deploy_vca):
1965 # A N2VC task is pending
1966 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00001967 else:
tiernoe876f672020-02-13 14:34:48 +00001968 # RO or KDU task is pending
1969 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00001970
tiernoe876f672020-02-13 14:34:48 +00001971 # update status at database
1972 if error_list:
tiernoa2143262020-03-27 16:20:40 +00001973 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00001974 self.logger.error(logging_text + error_detail)
tiernob5203912020-08-11 11:20:13 +00001975 error_description_nslcmop = '{} Detail: {}'.format(stage[0], error_detail)
1976 error_description_nsr = 'Operation: INSTANTIATING.{}, {}'.format(nslcmop_id, stage[0])
quilesj3655ae02019-12-12 16:08:35 +00001977
tiernoa2143262020-03-27 16:20:40 +00001978 db_nsr_update["detailed-status"] = error_description_nsr + " Detail: " + error_detail
tiernoe876f672020-02-13 14:34:48 +00001979 db_nslcmop_update["detailed-status"] = error_detail
1980 nslcmop_operation_state = "FAILED"
1981 ns_state = "BROKEN"
1982 else:
tiernoa2143262020-03-27 16:20:40 +00001983 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00001984 error_description_nsr = error_description_nslcmop = None
1985 ns_state = "READY"
1986 db_nsr_update["detailed-status"] = "Done"
1987 db_nslcmop_update["detailed-status"] = "Done"
1988 nslcmop_operation_state = "COMPLETED"
quilesj4cda56b2019-12-05 10:02:20 +00001989
tiernoe876f672020-02-13 14:34:48 +00001990 if db_nsr:
1991 self._write_ns_status(
1992 nsr_id=nsr_id,
1993 ns_state=ns_state,
1994 current_operation="IDLE",
1995 current_operation_id=None,
1996 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00001997 error_detail=error_detail,
tiernoe876f672020-02-13 14:34:48 +00001998 other_update=db_nsr_update
1999 )
tiernoa17d4f42020-04-28 09:59:23 +00002000 self._write_op_status(
2001 op_id=nslcmop_id,
2002 stage="",
2003 error_message=error_description_nslcmop,
2004 operation_state=nslcmop_operation_state,
2005 other_update=db_nslcmop_update,
2006 )
quilesj3655ae02019-12-12 16:08:35 +00002007
tierno59d22d22018-09-25 18:10:19 +02002008 if nslcmop_operation_state:
2009 try:
2010 await self.msg.aiowrite("ns", "instantiated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tierno8a518872018-12-21 13:42:14 +00002011 "operationState": nslcmop_operation_state},
2012 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02002013 except Exception as e:
2014 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
2015
2016 self.logger.debug(logging_text + "Exit")
2017 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
2018
tierno588547c2020-07-01 15:30:20 +00002019 async def _add_vca_relations(self, logging_text, nsr_id, vca_index: int,
2020 timeout: int = 3600, vca_type: str = None) -> bool:
quilesj63f90042020-01-17 09:53:55 +00002021
2022 # steps:
2023 # 1. find all relations for this VCA
2024 # 2. wait for other peers related
2025 # 3. add relations
2026
2027 try:
tierno588547c2020-07-01 15:30:20 +00002028 vca_type = vca_type or "lxc_proxy_charm"
quilesj63f90042020-01-17 09:53:55 +00002029
2030 # STEP 1: find all relations for this VCA
2031
2032 # read nsr record
2033 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garcia171f3542020-05-21 16:41:07 +02002034 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
quilesj63f90042020-01-17 09:53:55 +00002035
2036 # this VCA data
2037 my_vca = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))[vca_index]
2038
2039 # read all ns-configuration relations
2040 ns_relations = list()
David Garcia171f3542020-05-21 16:41:07 +02002041 db_ns_relations = deep_get(nsd, ('ns-configuration', 'relation'))
quilesj63f90042020-01-17 09:53:55 +00002042 if db_ns_relations:
2043 for r in db_ns_relations:
2044 # check if this VCA is in the relation
2045 if my_vca.get('member-vnf-index') in\
2046 (r.get('entities')[0].get('id'), r.get('entities')[1].get('id')):
2047 ns_relations.append(r)
2048
2049 # read all vnf-configuration relations
2050 vnf_relations = list()
2051 db_vnfd_list = db_nsr.get('vnfd-id')
2052 if db_vnfd_list:
2053 for vnfd in db_vnfd_list:
2054 db_vnfd = self.db.get_one("vnfds", {"_id": vnfd})
garciaalea77ced72021-02-17 19:09:12 -03002055 db_vnf_relations = get_configuration(db_vnfd, db_vnfd["id"]).get("relation", [])
quilesj63f90042020-01-17 09:53:55 +00002056 if db_vnf_relations:
2057 for r in db_vnf_relations:
2058 # check if this VCA is in the relation
2059 if my_vca.get('vdu_id') in (r.get('entities')[0].get('id'), r.get('entities')[1].get('id')):
2060 vnf_relations.append(r)
2061
2062 # if no relations, terminate
2063 if not ns_relations and not vnf_relations:
2064 self.logger.debug(logging_text + ' No relations')
2065 return True
2066
2067 self.logger.debug(logging_text + ' adding relations\n {}\n {}'.format(ns_relations, vnf_relations))
2068
2069 # add all relations
2070 start = time()
2071 while True:
2072 # check timeout
2073 now = time()
2074 if now - start >= timeout:
2075 self.logger.error(logging_text + ' : timeout adding relations')
2076 return False
2077
2078 # reload nsr from database (we need to update record: _admin.deloyed.VCA)
2079 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
2080
2081 # for each defined NS relation, find the VCA's related
tierno364c4572020-09-14 12:11:32 +00002082 for r in ns_relations.copy():
quilesj63f90042020-01-17 09:53:55 +00002083 from_vca_ee_id = None
2084 to_vca_ee_id = None
2085 from_vca_endpoint = None
2086 to_vca_endpoint = None
2087 vca_list = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))
2088 for vca in vca_list:
2089 if vca.get('member-vnf-index') == r.get('entities')[0].get('id') \
2090 and vca.get('config_sw_installed'):
2091 from_vca_ee_id = vca.get('ee_id')
2092 from_vca_endpoint = r.get('entities')[0].get('endpoint')
2093 if vca.get('member-vnf-index') == r.get('entities')[1].get('id') \
2094 and vca.get('config_sw_installed'):
2095 to_vca_ee_id = vca.get('ee_id')
2096 to_vca_endpoint = r.get('entities')[1].get('endpoint')
2097 if from_vca_ee_id and to_vca_ee_id:
2098 # add relation
tierno588547c2020-07-01 15:30:20 +00002099 await self.vca_map[vca_type].add_relation(
quilesj63f90042020-01-17 09:53:55 +00002100 ee_id_1=from_vca_ee_id,
2101 ee_id_2=to_vca_ee_id,
2102 endpoint_1=from_vca_endpoint,
2103 endpoint_2=to_vca_endpoint)
2104 # remove entry from relations list
2105 ns_relations.remove(r)
2106 else:
2107 # check failed peers
2108 try:
2109 vca_status_list = db_nsr.get('configurationStatus')
2110 if vca_status_list:
2111 for i in range(len(vca_list)):
2112 vca = vca_list[i]
2113 vca_status = vca_status_list[i]
2114 if vca.get('member-vnf-index') == r.get('entities')[0].get('id'):
2115 if vca_status.get('status') == 'BROKEN':
2116 # peer broken: remove relation from list
2117 ns_relations.remove(r)
2118 if vca.get('member-vnf-index') == r.get('entities')[1].get('id'):
2119 if vca_status.get('status') == 'BROKEN':
2120 # peer broken: remove relation from list
2121 ns_relations.remove(r)
2122 except Exception:
2123 # ignore
2124 pass
2125
2126 # for each defined VNF relation, find the VCA's related
tierno364c4572020-09-14 12:11:32 +00002127 for r in vnf_relations.copy():
quilesj63f90042020-01-17 09:53:55 +00002128 from_vca_ee_id = None
2129 to_vca_ee_id = None
2130 from_vca_endpoint = None
2131 to_vca_endpoint = None
2132 vca_list = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))
2133 for vca in vca_list:
David Garcia97be6832020-09-09 15:40:44 +02002134 key_to_check = "vdu_id"
2135 if vca.get("vdu_id") is None:
2136 key_to_check = "vnfd_id"
2137 if vca.get(key_to_check) == r.get('entities')[0].get('id') and vca.get('config_sw_installed'):
quilesj63f90042020-01-17 09:53:55 +00002138 from_vca_ee_id = vca.get('ee_id')
2139 from_vca_endpoint = r.get('entities')[0].get('endpoint')
David Garcia97be6832020-09-09 15:40:44 +02002140 if vca.get(key_to_check) == r.get('entities')[1].get('id') and vca.get('config_sw_installed'):
quilesj63f90042020-01-17 09:53:55 +00002141 to_vca_ee_id = vca.get('ee_id')
2142 to_vca_endpoint = r.get('entities')[1].get('endpoint')
2143 if from_vca_ee_id and to_vca_ee_id:
2144 # add relation
tierno588547c2020-07-01 15:30:20 +00002145 await self.vca_map[vca_type].add_relation(
quilesj63f90042020-01-17 09:53:55 +00002146 ee_id_1=from_vca_ee_id,
2147 ee_id_2=to_vca_ee_id,
2148 endpoint_1=from_vca_endpoint,
2149 endpoint_2=to_vca_endpoint)
2150 # remove entry from relations list
2151 vnf_relations.remove(r)
2152 else:
2153 # check failed peers
2154 try:
2155 vca_status_list = db_nsr.get('configurationStatus')
2156 if vca_status_list:
2157 for i in range(len(vca_list)):
2158 vca = vca_list[i]
2159 vca_status = vca_status_list[i]
2160 if vca.get('vdu_id') == r.get('entities')[0].get('id'):
2161 if vca_status.get('status') == 'BROKEN':
2162 # peer broken: remove relation from list
David Garcia092afbd2020-08-25 13:17:25 +02002163 vnf_relations.remove(r)
quilesj63f90042020-01-17 09:53:55 +00002164 if vca.get('vdu_id') == r.get('entities')[1].get('id'):
2165 if vca_status.get('status') == 'BROKEN':
2166 # peer broken: remove relation from list
David Garcia092afbd2020-08-25 13:17:25 +02002167 vnf_relations.remove(r)
quilesj63f90042020-01-17 09:53:55 +00002168 except Exception:
2169 # ignore
2170 pass
2171
2172 # wait for next try
2173 await asyncio.sleep(5.0)
2174
2175 if not ns_relations and not vnf_relations:
2176 self.logger.debug('Relations added')
2177 break
2178
2179 return True
2180
2181 except Exception as e:
2182 self.logger.warn(logging_text + ' ERROR adding relations: {}'.format(e))
2183 return False
2184
tierno7ecbc342020-09-21 14:05:39 +00002185 async def _install_kdu(self, nsr_id: str, nsr_db_path: str, vnfr_data: dict, kdu_index: int, kdud: dict,
lloretgalleg7c121132020-07-08 07:53:22 +00002186 vnfd: dict, k8s_instance_info: dict, k8params: dict = None, timeout: int = 600):
2187
tiernob9018152020-04-16 14:18:24 +00002188 try:
lloretgalleg7c121132020-07-08 07:53:22 +00002189 k8sclustertype = k8s_instance_info["k8scluster-type"]
2190 # Instantiate kdu
2191 db_dict_install = {"collection": "nsrs",
2192 "filter": {"_id": nsr_id},
2193 "path": nsr_db_path}
2194
David Garciaffbf6ed2021-02-25 20:19:18 +01002195 kdu_instance = self.k8scluster_map[k8sclustertype].generate_kdu_instance_name(
2196 db_dict=db_dict_install,
2197 kdu_model=k8s_instance_info["kdu-model"],
2198 )
2199 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
2200 await self.k8scluster_map[k8sclustertype].install(
lloretgalleg7c121132020-07-08 07:53:22 +00002201 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2202 kdu_model=k8s_instance_info["kdu-model"],
2203 atomic=True,
2204 params=k8params,
2205 db_dict=db_dict_install,
2206 timeout=timeout,
2207 kdu_name=k8s_instance_info["kdu-name"],
David Garciaffbf6ed2021-02-25 20:19:18 +01002208 namespace=k8s_instance_info["namespace"],
2209 kdu_instance=kdu_instance,
2210 )
lloretgalleg7c121132020-07-08 07:53:22 +00002211 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
2212
2213 # Obtain services to obtain management service ip
2214 services = await self.k8scluster_map[k8sclustertype].get_services(
2215 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2216 kdu_instance=kdu_instance,
2217 namespace=k8s_instance_info["namespace"])
2218
2219 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00002220 vnfr_update_dict = {}
lloretgalleg7c121132020-07-08 07:53:22 +00002221 if services:
tierno7ecbc342020-09-21 14:05:39 +00002222 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
lloretgalleg7c121132020-07-08 07:53:22 +00002223 mgmt_services = [service for service in kdud.get("service", []) if service.get("mgmt-service")]
2224 for mgmt_service in mgmt_services:
2225 for service in services:
2226 if service["name"].startswith(mgmt_service["name"]):
2227 # Mgmt service found, Obtain service ip
2228 ip = service.get("external_ip", service.get("cluster_ip"))
2229 if isinstance(ip, list) and len(ip) == 1:
2230 ip = ip[0]
2231
2232 vnfr_update_dict["kdur.{}.ip-address".format(kdu_index)] = ip
2233
2234 # Check if must update also mgmt ip at the vnf
2235 service_external_cp = mgmt_service.get("external-connection-point-ref")
2236 if service_external_cp:
2237 if deep_get(vnfd, ("mgmt-interface", "cp")) == service_external_cp:
2238 vnfr_update_dict["ip-address"] = ip
2239
2240 break
2241 else:
2242 self.logger.warn("Mgmt service name: {} not found".format(mgmt_service["name"]))
2243
tierno7ecbc342020-09-21 14:05:39 +00002244 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
2245 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00002246
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02002247 kdu_config = kdud.get("kdu-configuration")
2248 if kdu_config and kdu_config.get("initial-config-primitive") and kdu_config.get("juju") is None:
2249 initial_config_primitive_list = kdu_config.get("initial-config-primitive")
2250 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
2251
2252 for initial_config_primitive in initial_config_primitive_list:
2253 primitive_params_ = self._map_primitive_params(initial_config_primitive, {}, {})
2254
2255 await asyncio.wait_for(
2256 self.k8scluster_map[k8sclustertype].exec_primitive(
2257 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2258 kdu_instance=kdu_instance,
2259 primitive_name=initial_config_primitive["name"],
2260 params=primitive_params_, db_dict={}),
2261 timeout=timeout)
2262
tiernob9018152020-04-16 14:18:24 +00002263 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00002264 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00002265 try:
lloretgalleg7c121132020-07-08 07:53:22 +00002266 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)})
tierno7ecbc342020-09-21 14:05:39 +00002267 self.update_db_2("vnfrs", vnfr_data.get("_id"), {"kdur.{}.status".format(kdu_index): "ERROR"})
tiernob9018152020-04-16 14:18:24 +00002268 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00002269 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00002270 pass
lloretgalleg7c121132020-07-08 07:53:22 +00002271 # reraise original error
2272 raise
2273
2274 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00002275
tiernoe876f672020-02-13 14:34:48 +00002276 async def deploy_kdus(self, logging_text, nsr_id, nslcmop_id, db_vnfrs, db_vnfds, task_instantiation_info):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002277 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00002278
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002279 k8scluster_id_2_uuic = {"helm-chart-v3": {}, "helm-chart": {}, "juju-bundle": {}}
tierno626e0152019-11-29 14:16:16 +00002280
tierno16f4a4e2020-07-20 09:05:51 +00002281 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00002282 nonlocal k8scluster_id_2_uuic
2283 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
2284 return k8scluster_id_2_uuic[cluster_type][cluster_id]
2285
tierno16f4a4e2020-07-20 09:05:51 +00002286 # check if K8scluster is creating and wait look if previous tasks in process
2287 task_name, task_dependency = self.lcm_tasks.lookfor_related("k8scluster", cluster_id)
2288 if task_dependency:
2289 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(task_name, cluster_id)
2290 self.logger.debug(logging_text + text)
2291 await asyncio.wait(task_dependency, timeout=3600)
2292
tierno626e0152019-11-29 14:16:16 +00002293 db_k8scluster = self.db.get_one("k8sclusters", {"_id": cluster_id}, fail_on_empty=False)
2294 if not db_k8scluster:
2295 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00002296
tierno626e0152019-11-29 14:16:16 +00002297 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
2298 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002299 if cluster_type == "helm-chart-v3":
2300 try:
2301 # backward compatibility for existing clusters that have not been initialized for helm v3
2302 k8s_credentials = yaml.safe_dump(db_k8scluster.get("credentials"))
2303 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(k8s_credentials,
2304 reuse_cluster_uuid=cluster_id)
2305 db_k8scluster_update = {}
2306 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
2307 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
2308 db_k8scluster_update["_admin.helm-chart-v3.created"] = uninstall_sw
2309 db_k8scluster_update["_admin.helm-chart-v3.operationalState"] = "ENABLED"
2310 self.update_db_2("k8sclusters", cluster_id, db_k8scluster_update)
2311 except Exception as e:
2312 self.logger.error(logging_text + "error initializing helm-v3 cluster: {}".format(str(e)))
2313 raise LcmException("K8s cluster '{}' has not been initialized for '{}'".format(cluster_id,
2314 cluster_type))
2315 else:
2316 raise LcmException("K8s cluster '{}' has not been initialized for '{}'".
2317 format(cluster_id, cluster_type))
tierno626e0152019-11-29 14:16:16 +00002318 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
2319 return k8s_id
2320
2321 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00002322 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01002323 try:
tierno626e0152019-11-29 14:16:16 +00002324 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01002325 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01002326
tierno626e0152019-11-29 14:16:16 +00002327 index = 0
tiernoe876f672020-02-13 14:34:48 +00002328 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002329 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00002330
tierno626e0152019-11-29 14:16:16 +00002331 for vnfr_data in db_vnfrs.values():
lloretgalleg7c121132020-07-08 07:53:22 +00002332 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
2333 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03002334 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
quilesjacde94f2020-01-23 10:07:08 +00002335 vnfd_id = vnfr_data.get('vnfd-id')
David Garciad41dbd62020-12-10 12:52:52 +01002336 vnfd_with_id = find_in_list(db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id)
2337 kdud = next(kdud for kdud in vnfd_with_id["kdu"] if kdud["name"] == kdur["kdu-name"])
tiernode1584f2020-04-07 09:07:33 +00002338 namespace = kdur.get("k8s-namespace")
tierno626e0152019-11-29 14:16:16 +00002339 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00002340 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002341 # Default version: helm3, if helm-version is v2 assign v2
2342 k8sclustertype = "helm-chart-v3"
2343 self.logger.debug("kdur: {}".format(kdur))
2344 if kdur.get("helm-version") and kdur.get("helm-version") == "v2":
2345 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00002346 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00002347 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00002348 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00002349 else:
tiernoe876f672020-02-13 14:34:48 +00002350 raise LcmException("kdu type for kdu='{}.{}' is neither helm-chart nor "
2351 "juju-bundle. Maybe an old NBI version is running".
2352 format(vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]))
quilesjacde94f2020-01-23 10:07:08 +00002353 # check if kdumodel is a file and exists
2354 try:
David Garciad41dbd62020-12-10 12:52:52 +01002355 vnfd_with_id = find_in_list(db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id)
2356 storage = deep_get(vnfd_with_id, ('_admin', 'storage'))
tierno51183952020-04-03 15:48:18 +00002357 if storage and storage.get('pkg-dir'): # may be not present if vnfd has not artifacts
2358 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
Dominik Fleischmann010c0e72020-05-18 15:19:11 +02002359 filename = '{}/{}/{}s/{}'.format(storage["folder"], storage["pkg-dir"], k8sclustertype,
tierno51183952020-04-03 15:48:18 +00002360 kdumodel)
2361 if self.fs.file_exists(filename, mode='file') or self.fs.file_exists(filename, mode='dir'):
2362 kdumodel = self.fs.path + filename
2363 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00002364 raise
2365 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00002366 pass
lloretgallegedc5f332020-02-20 11:50:50 +01002367
tiernoe876f672020-02-13 14:34:48 +00002368 k8s_cluster_id = kdur["k8s-cluster"]["id"]
2369 step = "Synchronize repos for k8s cluster '{}'".format(k8s_cluster_id)
tierno16f4a4e2020-07-20 09:05:51 +00002370 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01002371
lloretgalleg7c121132020-07-08 07:53:22 +00002372 # Synchronize repos
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002373 if (k8sclustertype == "helm-chart" and cluster_uuid not in updated_cluster_list)\
2374 or (k8sclustertype == "helm-chart-v3" and cluster_uuid not in updated_v3_cluster_list):
tiernoe876f672020-02-13 14:34:48 +00002375 del_repo_list, added_repo_dict = await asyncio.ensure_future(
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002376 self.k8scluster_map[k8sclustertype].synchronize_repos(cluster_uuid=cluster_uuid))
tiernoe876f672020-02-13 14:34:48 +00002377 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002378 if k8sclustertype == "helm-chart":
2379 unset = {'_admin.helm_charts_added.' + item: None for item in del_repo_list}
2380 updated = {'_admin.helm_charts_added.' +
2381 item: name for item, name in added_repo_dict.items()}
2382 updated_cluster_list.append(cluster_uuid)
2383 elif k8sclustertype == "helm-chart-v3":
2384 unset = {'_admin.helm_charts_v3_added.' + item: None for item in del_repo_list}
2385 updated = {'_admin.helm_charts_v3_added.' +
2386 item: name for item, name in added_repo_dict.items()}
2387 updated_v3_cluster_list.append(cluster_uuid)
2388 self.logger.debug(logging_text + "repos synchronized on k8s cluster "
2389 "'{}' to_delete: {}, to_add: {}".
2390 format(k8s_cluster_id, del_repo_list, added_repo_dict))
tiernoe876f672020-02-13 14:34:48 +00002391 self.db.set_one("k8sclusters", {"_id": k8s_cluster_id}, updated, unset=unset)
lloretgallegedc5f332020-02-20 11:50:50 +01002392
lloretgalleg7c121132020-07-08 07:53:22 +00002393 # Instantiate kdu
tiernoe876f672020-02-13 14:34:48 +00002394 step = "Instantiating KDU {}.{} in k8s cluster {}".format(vnfr_data["member-vnf-index-ref"],
2395 kdur["kdu-name"], k8s_cluster_id)
lloretgalleg7c121132020-07-08 07:53:22 +00002396 k8s_instance_info = {"kdu-instance": None,
2397 "k8scluster-uuid": cluster_uuid,
2398 "k8scluster-type": k8sclustertype,
2399 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
2400 "kdu-name": kdur["kdu-name"],
2401 "kdu-model": kdumodel,
2402 "namespace": namespace}
tiernob9018152020-04-16 14:18:24 +00002403 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00002404 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00002405 self.update_db_2("nsrs", nsr_id, db_nsr_update)
David Garciad41dbd62020-12-10 12:52:52 +01002406 vnfd_with_id = find_in_list(db_vnfds, lambda vnf: vnf["_id"] == vnfd_id)
tiernoa2143262020-03-27 16:20:40 +00002407 task = asyncio.ensure_future(
David Garciad41dbd62020-12-10 12:52:52 +01002408 self._install_kdu(nsr_id, db_path, vnfr_data, kdu_index, kdud, vnfd_with_id,
lloretgalleg7c121132020-07-08 07:53:22 +00002409 k8s_instance_info, k8params=desc_params, timeout=600))
tiernoe876f672020-02-13 14:34:48 +00002410 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_KDU-{}".format(index), task)
tiernoa2143262020-03-27 16:20:40 +00002411 task_instantiation_info[task] = "Deploying KDU {}".format(kdur["kdu-name"])
tiernoe876f672020-02-13 14:34:48 +00002412
tierno626e0152019-11-29 14:16:16 +00002413 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00002414
tiernoe876f672020-02-13 14:34:48 +00002415 except (LcmException, asyncio.CancelledError):
2416 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01002417 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00002418 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
2419 if isinstance(e, (N2VCException, DbException)):
2420 self.logger.error(logging_text + msg)
2421 else:
2422 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00002423 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01002424 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002425 if db_nsr_update:
2426 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00002427
quilesj7e13aeb2019-10-08 13:34:55 +02002428 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 +01002429 kdu_name, member_vnf_index, vdu_index, vdu_name, deploy_params, descriptor_config,
tiernoe876f672020-02-13 14:34:48 +00002430 base_folder, task_instantiation_info, stage):
quilesj7e13aeb2019-10-08 13:34:55 +02002431 # launch instantiate_N2VC in a asyncio task and register task object
2432 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
2433 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02002434 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00002435
2436 self.logger.debug(logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id))
2437 if descriptor_config.get("juju"): # There is one execution envioronment of type juju
2438 ee_list = [descriptor_config]
2439 elif descriptor_config.get("execution-environment-list"):
2440 ee_list = descriptor_config.get("execution-environment-list")
2441 else: # other types as script are not supported
2442 ee_list = []
2443
2444 for ee_item in ee_list:
2445 self.logger.debug(logging_text + "_deploy_n2vc ee_item juju={}, helm={}".format(ee_item.get('juju'),
2446 ee_item.get("helm-chart")))
tiernoa278b842020-07-08 15:33:55 +00002447 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00002448 if ee_item.get("juju"):
2449 vca_name = ee_item['juju'].get('charm')
2450 vca_type = "lxc_proxy_charm" if ee_item['juju'].get('charm') is not None else "native_charm"
2451 if ee_item['juju'].get('cloud') == "k8s":
2452 vca_type = "k8s_proxy_charm"
2453 elif ee_item['juju'].get('proxy') is False:
2454 vca_type = "native_charm"
2455 elif ee_item.get("helm-chart"):
2456 vca_name = ee_item['helm-chart']
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002457 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
2458 vca_type = "helm"
2459 else:
2460 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00002461 else:
2462 self.logger.debug(logging_text + "skipping non juju neither charm configuration")
quilesj7e13aeb2019-10-08 13:34:55 +02002463 continue
quilesj3655ae02019-12-12 16:08:35 +00002464
tierno588547c2020-07-01 15:30:20 +00002465 vca_index = -1
2466 for vca_index, vca_deployed in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
2467 if not vca_deployed:
2468 continue
2469 if vca_deployed.get("member-vnf-index") == member_vnf_index and \
2470 vca_deployed.get("vdu_id") == vdu_id and \
2471 vca_deployed.get("kdu_name") == kdu_name and \
tiernoa278b842020-07-08 15:33:55 +00002472 vca_deployed.get("vdu_count_index", 0) == vdu_index and \
2473 vca_deployed.get("ee_descriptor_id") == ee_descriptor_id:
tierno588547c2020-07-01 15:30:20 +00002474 break
2475 else:
2476 # not found, create one.
tiernoa278b842020-07-08 15:33:55 +00002477 target = "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
2478 if vdu_id:
2479 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
2480 elif kdu_name:
2481 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00002482 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00002483 "target_element": target,
2484 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00002485 "member-vnf-index": member_vnf_index,
2486 "vdu_id": vdu_id,
2487 "kdu_name": kdu_name,
2488 "vdu_count_index": vdu_index,
2489 "operational-status": "init", # TODO revise
2490 "detailed-status": "", # TODO revise
2491 "step": "initial-deploy", # TODO revise
2492 "vnfd_id": vnfd_id,
2493 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00002494 "type": vca_type,
2495 "ee_descriptor_id": ee_descriptor_id
tierno588547c2020-07-01 15:30:20 +00002496 }
2497 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00002498
tierno588547c2020-07-01 15:30:20 +00002499 # create VCA and configurationStatus in db
2500 db_dict = {
2501 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
2502 "configurationStatus.{}".format(vca_index): dict()
2503 }
2504 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02002505
tierno588547c2020-07-01 15:30:20 +00002506 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
2507
bravof922c4172020-11-24 21:21:43 -03002508 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
2509 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
2510 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
2511
tierno588547c2020-07-01 15:30:20 +00002512 # Launch task
2513 task_n2vc = asyncio.ensure_future(
2514 self.instantiate_N2VC(
2515 logging_text=logging_text,
2516 vca_index=vca_index,
2517 nsi_id=nsi_id,
2518 db_nsr=db_nsr,
2519 db_vnfr=db_vnfr,
2520 vdu_id=vdu_id,
2521 kdu_name=kdu_name,
2522 vdu_index=vdu_index,
2523 deploy_params=deploy_params,
2524 config_descriptor=descriptor_config,
2525 base_folder=base_folder,
2526 nslcmop_id=nslcmop_id,
2527 stage=stage,
2528 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00002529 vca_name=vca_name,
2530 ee_config_descriptor=ee_item
tierno588547c2020-07-01 15:30:20 +00002531 )
quilesj7e13aeb2019-10-08 13:34:55 +02002532 )
tierno588547c2020-07-01 15:30:20 +00002533 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_N2VC-{}".format(vca_index), task_n2vc)
2534 task_instantiation_info[task_n2vc] = self.task_name_deploy_vca + " {}.{}".format(
2535 member_vnf_index or "", vdu_id or "")
tiernobaa51102018-12-14 13:16:18 +00002536
tiernoc9556972019-07-05 15:25:25 +00002537 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02002538 def _create_nslcmop(nsr_id, operation, params):
2539 """
2540 Creates a ns-lcm-opp content to be stored at database.
2541 :param nsr_id: internal id of the instance
2542 :param operation: instantiate, terminate, scale, action, ...
2543 :param params: user parameters for the operation
2544 :return: dictionary following SOL005 format
2545 """
2546 # Raise exception if invalid arguments
2547 if not (nsr_id and operation and params):
2548 raise LcmException(
2549 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided")
2550 now = time()
2551 _id = str(uuid4())
2552 nslcmop = {
2553 "id": _id,
2554 "_id": _id,
2555 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
2556 "operationState": "PROCESSING",
2557 "statusEnteredTime": now,
2558 "nsInstanceId": nsr_id,
2559 "lcmOperationType": operation,
2560 "startTime": now,
2561 "isAutomaticInvocation": False,
2562 "operationParams": params,
2563 "isCancelPending": False,
2564 "links": {
2565 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
2566 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
2567 }
2568 }
2569 return nslcmop
2570
calvinosanch9f9c6f22019-11-04 13:37:39 +01002571 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00002572 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01002573 for key, value in params.items():
2574 if str(value).startswith("!!yaml "):
2575 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01002576 return params
2577
kuuse8b998e42019-07-30 15:22:16 +02002578 def _get_terminate_primitive_params(self, seq, vnf_index):
2579 primitive = seq.get('name')
2580 primitive_params = {}
2581 params = {
2582 "member_vnf_index": vnf_index,
2583 "primitive": primitive,
2584 "primitive_params": primitive_params,
2585 }
2586 desc_params = {}
2587 return self._map_primitive_params(seq, params, desc_params)
2588
kuuseac3a8882019-10-03 10:48:06 +02002589 # sub-operations
2590
tierno51183952020-04-03 15:48:18 +00002591 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
2592 op = deep_get(db_nslcmop, ('_admin', 'operations'), [])[op_index]
2593 if op.get('operationState') == 'COMPLETED':
kuuseac3a8882019-10-03 10:48:06 +02002594 # b. Skip sub-operation
2595 # _ns_execute_primitive() or RO.create_action() will NOT be executed
2596 return self.SUBOPERATION_STATUS_SKIP
2597 else:
tierno7c4e24c2020-05-13 08:41:35 +00002598 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02002599 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00002600 # Update operationState = 'PROCESSING' to indicate a retry.
kuuseac3a8882019-10-03 10:48:06 +02002601 operationState = 'PROCESSING'
2602 detailed_status = 'In progress'
2603 self._update_suboperation_status(
2604 db_nslcmop, op_index, operationState, detailed_status)
2605 # Return the sub-operation index
2606 # _ns_execute_primitive() or RO.create_action() will be called from scale()
2607 # with arguments extracted from the sub-operation
2608 return op_index
2609
2610 # Find a sub-operation where all keys in a matching dictionary must match
2611 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
2612 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00002613 if db_nslcmop and match:
kuuseac3a8882019-10-03 10:48:06 +02002614 op_list = db_nslcmop.get('_admin', {}).get('operations', [])
2615 for i, op in enumerate(op_list):
2616 if all(op.get(k) == match[k] for k in match):
2617 return i
2618 return self.SUBOPERATION_STATUS_NOT_FOUND
2619
2620 # Update status for a sub-operation given its index
2621 def _update_suboperation_status(self, db_nslcmop, op_index, operationState, detailed_status):
2622 # Update DB for HA tasks
2623 q_filter = {'_id': db_nslcmop['_id']}
2624 update_dict = {'_admin.operations.{}.operationState'.format(op_index): operationState,
2625 '_admin.operations.{}.detailed-status'.format(op_index): detailed_status}
2626 self.db.set_one("nslcmops",
2627 q_filter=q_filter,
2628 update_dict=update_dict,
2629 fail_on_empty=False)
2630
2631 # Add sub-operation, return the index of the added sub-operation
2632 # Optionally, set operationState, detailed-status, and operationType
2633 # Status and type are currently set for 'scale' sub-operations:
2634 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
2635 # 'detailed-status' : status message
2636 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
2637 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
tierno2357f4e2020-10-19 16:38:59 +00002638 def _add_suboperation(self, db_nslcmop, vnf_index, vdu_id, vdu_count_index, vdu_name, primitive,
quilesj7e13aeb2019-10-08 13:34:55 +02002639 mapped_primitive_params, operationState=None, detailed_status=None, operationType=None,
kuuseac3a8882019-10-03 10:48:06 +02002640 RO_nsr_id=None, RO_scaling_info=None):
tiernoe876f672020-02-13 14:34:48 +00002641 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02002642 return self.SUBOPERATION_STATUS_NOT_FOUND
2643 # Get the "_admin.operations" list, if it exists
2644 db_nslcmop_admin = db_nslcmop.get('_admin', {})
2645 op_list = db_nslcmop_admin.get('operations')
2646 # Create or append to the "_admin.operations" list
kuuse8b998e42019-07-30 15:22:16 +02002647 new_op = {'member_vnf_index': vnf_index,
2648 'vdu_id': vdu_id,
2649 'vdu_count_index': vdu_count_index,
2650 'primitive': primitive,
2651 'primitive_params': mapped_primitive_params}
kuuseac3a8882019-10-03 10:48:06 +02002652 if operationState:
2653 new_op['operationState'] = operationState
2654 if detailed_status:
2655 new_op['detailed-status'] = detailed_status
2656 if operationType:
2657 new_op['lcmOperationType'] = operationType
2658 if RO_nsr_id:
2659 new_op['RO_nsr_id'] = RO_nsr_id
2660 if RO_scaling_info:
2661 new_op['RO_scaling_info'] = RO_scaling_info
2662 if not op_list:
2663 # No existing operations, create key 'operations' with current operation as first list element
2664 db_nslcmop_admin.update({'operations': [new_op]})
2665 op_list = db_nslcmop_admin.get('operations')
2666 else:
2667 # Existing operations, append operation to list
2668 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02002669
kuuseac3a8882019-10-03 10:48:06 +02002670 db_nslcmop_update = {'_admin.operations': op_list}
2671 self.update_db_2("nslcmops", db_nslcmop['_id'], db_nslcmop_update)
2672 op_index = len(op_list) - 1
2673 return op_index
2674
2675 # Helper methods for scale() sub-operations
2676
2677 # pre-scale/post-scale:
2678 # Check for 3 different cases:
2679 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
2680 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00002681 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
quilesj7e13aeb2019-10-08 13:34:55 +02002682 def _check_or_add_scale_suboperation(self, db_nslcmop, vnf_index, vnf_config_primitive, primitive_params,
2683 operationType, RO_nsr_id=None, RO_scaling_info=None):
kuuseac3a8882019-10-03 10:48:06 +02002684 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00002685 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02002686 operationType = 'SCALE-RO'
2687 match = {
2688 'member_vnf_index': vnf_index,
2689 'RO_nsr_id': RO_nsr_id,
2690 'RO_scaling_info': RO_scaling_info,
2691 }
2692 else:
2693 match = {
2694 'member_vnf_index': vnf_index,
2695 'primitive': vnf_config_primitive,
2696 'primitive_params': primitive_params,
2697 'lcmOperationType': operationType
2698 }
2699 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00002700 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02002701 # a. New sub-operation
2702 # The sub-operation does not exist, add it.
2703 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
2704 # The following parameters are set to None for all kind of scaling:
2705 vdu_id = None
2706 vdu_count_index = None
2707 vdu_name = None
tierno51183952020-04-03 15:48:18 +00002708 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02002709 vnf_config_primitive = None
2710 primitive_params = None
2711 else:
2712 RO_nsr_id = None
2713 RO_scaling_info = None
2714 # Initial status for sub-operation
2715 operationState = 'PROCESSING'
2716 detailed_status = 'In progress'
2717 # Add sub-operation for pre/post-scaling (zero or more operations)
2718 self._add_suboperation(db_nslcmop,
2719 vnf_index,
2720 vdu_id,
2721 vdu_count_index,
2722 vdu_name,
2723 vnf_config_primitive,
2724 primitive_params,
2725 operationState,
2726 detailed_status,
2727 operationType,
2728 RO_nsr_id,
2729 RO_scaling_info)
2730 return self.SUBOPERATION_STATUS_NEW
2731 else:
2732 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
2733 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00002734 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02002735
preethika.pdf7d8e02019-12-10 13:10:48 +00002736 # Function to return execution_environment id
2737
2738 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00002739 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00002740 for vca in vca_deployed_list:
2741 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
2742 return vca["ee_id"]
2743
tierno588547c2020-07-01 15:30:20 +00002744 async def destroy_N2VC(self, logging_text, db_nslcmop, vca_deployed, config_descriptor,
2745 vca_index, destroy_ee=True, exec_primitives=True):
tiernoe876f672020-02-13 14:34:48 +00002746 """
2747 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
2748 :param logging_text:
2749 :param db_nslcmop:
2750 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
2751 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
2752 :param vca_index: index in the database _admin.deployed.VCA
2753 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00002754 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
2755 not executed properly
tiernoe876f672020-02-13 14:34:48 +00002756 :return: None or exception
2757 """
tiernoe876f672020-02-13 14:34:48 +00002758
tierno588547c2020-07-01 15:30:20 +00002759 self.logger.debug(
2760 logging_text + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
2761 vca_index, vca_deployed, config_descriptor, destroy_ee
2762 )
2763 )
2764
2765 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
2766
2767 # execute terminate_primitives
2768 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03002769 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
2770 config_descriptor.get("terminate-config-primitive"), vca_deployed.get("ee_descriptor_id"))
tierno588547c2020-07-01 15:30:20 +00002771 vdu_id = vca_deployed.get("vdu_id")
2772 vdu_count_index = vca_deployed.get("vdu_count_index")
2773 vdu_name = vca_deployed.get("vdu_name")
2774 vnf_index = vca_deployed.get("member-vnf-index")
2775 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00002776 for seq in terminate_primitives:
2777 # For each sequence in list, get primitive and call _ns_execute_primitive()
2778 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
2779 vnf_index, seq.get("name"))
2780 self.logger.debug(logging_text + step)
2781 # Create the primitive for each sequence, i.e. "primitive": "touch"
2782 primitive = seq.get('name')
2783 mapped_primitive_params = self._get_terminate_primitive_params(seq, vnf_index)
tierno588547c2020-07-01 15:30:20 +00002784
2785 # Add sub-operation
2786 self._add_suboperation(db_nslcmop,
2787 vnf_index,
2788 vdu_id,
2789 vdu_count_index,
2790 vdu_name,
2791 primitive,
2792 mapped_primitive_params)
2793 # Sub-operations: Call _ns_execute_primitive() instead of action()
2794 try:
2795 result, result_detail = await self._ns_execute_primitive(vca_deployed["ee_id"], primitive,
2796 mapped_primitive_params,
2797 vca_type=vca_type)
2798 except LcmException:
2799 # this happens when VCA is not deployed. In this case it is not needed to terminate
2800 continue
2801 result_ok = ['COMPLETED', 'PARTIALLY_COMPLETED']
2802 if result not in result_ok:
2803 raise LcmException("terminate_primitive {} for vnf_member_index={} fails with "
2804 "error {}".format(seq.get("name"), vnf_index, result_detail))
2805 # set that this VCA do not need terminated
2806 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(vca_index)
2807 self.update_db_2("nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False})
tiernoe876f672020-02-13 14:34:48 +00002808
tiernob996d942020-07-03 14:52:28 +00002809 if vca_deployed.get("prometheus_jobs") and self.prometheus:
2810 await self.prometheus.update(remove_jobs=vca_deployed["prometheus_jobs"])
2811
tiernoe876f672020-02-13 14:34:48 +00002812 if destroy_ee:
tierno588547c2020-07-01 15:30:20 +00002813 await self.vca_map[vca_type].delete_execution_environment(vca_deployed["ee_id"])
kuuse0ca67472019-05-13 15:59:27 +02002814
tierno51183952020-04-03 15:48:18 +00002815 async def _delete_all_N2VC(self, db_nsr: dict):
2816 self._write_all_config_status(db_nsr=db_nsr, status='TERMINATING')
2817 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00002818 try:
2819 await self.n2vc.delete_namespace(namespace=namespace, total_timeout=self.timeout_charm_delete)
2820 except N2VCNotFound: # already deleted. Skip
2821 pass
tierno51183952020-04-03 15:48:18 +00002822 self._write_all_config_status(db_nsr=db_nsr, status='DELETED')
quilesj3655ae02019-12-12 16:08:35 +00002823
tiernoe876f672020-02-13 14:34:48 +00002824 async def _terminate_RO(self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage):
2825 """
2826 Terminates a deployment from RO
2827 :param logging_text:
2828 :param nsr_deployed: db_nsr._admin.deployed
2829 :param nsr_id:
2830 :param nslcmop_id:
2831 :param stage: list of string with the content to write on db_nslcmop.detailed-status.
2832 this method will update only the index 2, but it will write on database the concatenated content of the list
2833 :return:
2834 """
2835 db_nsr_update = {}
2836 failed_detail = []
2837 ro_nsr_id = ro_delete_action = None
2838 if nsr_deployed and nsr_deployed.get("RO"):
2839 ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
2840 ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
2841 try:
2842 if ro_nsr_id:
2843 stage[2] = "Deleting ns from VIM."
2844 db_nsr_update["detailed-status"] = " ".join(stage)
2845 self._write_op_status(nslcmop_id, stage)
2846 self.logger.debug(logging_text + stage[2])
2847 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2848 self._write_op_status(nslcmop_id, stage)
2849 desc = await self.RO.delete("ns", ro_nsr_id)
2850 ro_delete_action = desc["action_id"]
2851 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = ro_delete_action
2852 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
2853 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2854 if ro_delete_action:
2855 # wait until NS is deleted from VIM
2856 stage[2] = "Waiting ns deleted from VIM."
2857 detailed_status_old = None
2858 self.logger.debug(logging_text + stage[2] + " RO_id={} ro_delete_action={}".format(ro_nsr_id,
2859 ro_delete_action))
2860 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2861 self._write_op_status(nslcmop_id, stage)
kuused124bfe2019-06-18 12:09:24 +02002862
tiernoe876f672020-02-13 14:34:48 +00002863 delete_timeout = 20 * 60 # 20 minutes
2864 while delete_timeout > 0:
2865 desc = await self.RO.show(
2866 "ns",
2867 item_id_name=ro_nsr_id,
2868 extra_item="action",
2869 extra_item_id=ro_delete_action)
2870
2871 # deploymentStatus
2872 self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
2873
2874 ns_status, ns_status_info = self.RO.check_action_status(desc)
2875 if ns_status == "ERROR":
2876 raise ROclient.ROClientException(ns_status_info)
2877 elif ns_status == "BUILD":
2878 stage[2] = "Deleting from VIM {}".format(ns_status_info)
2879 elif ns_status == "ACTIVE":
2880 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
2881 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2882 break
2883 else:
2884 assert False, "ROclient.check_action_status returns unknown {}".format(ns_status)
2885 if stage[2] != detailed_status_old:
2886 detailed_status_old = stage[2]
2887 db_nsr_update["detailed-status"] = " ".join(stage)
2888 self._write_op_status(nslcmop_id, stage)
2889 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2890 await asyncio.sleep(5, loop=self.loop)
2891 delete_timeout -= 5
2892 else: # delete_timeout <= 0:
2893 raise ROclient.ROClientException("Timeout waiting ns deleted from VIM")
2894
2895 except Exception as e:
2896 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2897 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2898 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
2899 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2900 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
2901 self.logger.debug(logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id))
2902 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
tiernoa2143262020-03-27 16:20:40 +00002903 failed_detail.append("delete conflict: {}".format(e))
2904 self.logger.debug(logging_text + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e))
tiernoe876f672020-02-13 14:34:48 +00002905 else:
tiernoa2143262020-03-27 16:20:40 +00002906 failed_detail.append("delete error: {}".format(e))
2907 self.logger.error(logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e))
tiernoe876f672020-02-13 14:34:48 +00002908
2909 # Delete nsd
2910 if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
2911 ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
2912 try:
2913 stage[2] = "Deleting nsd from RO."
2914 db_nsr_update["detailed-status"] = " ".join(stage)
2915 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2916 self._write_op_status(nslcmop_id, stage)
2917 await self.RO.delete("nsd", ro_nsd_id)
2918 self.logger.debug(logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id))
2919 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
2920 except Exception as e:
2921 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2922 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
2923 self.logger.debug(logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id))
2924 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
2925 failed_detail.append("ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e))
2926 self.logger.debug(logging_text + failed_detail[-1])
2927 else:
2928 failed_detail.append("ro_nsd_id={} delete error: {}".format(ro_nsd_id, e))
2929 self.logger.error(logging_text + failed_detail[-1])
2930
2931 if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
2932 for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
2933 if not vnf_deployed or not vnf_deployed["id"]:
2934 continue
2935 try:
2936 ro_vnfd_id = vnf_deployed["id"]
2937 stage[2] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
2938 vnf_deployed["member-vnf-index"], ro_vnfd_id)
2939 db_nsr_update["detailed-status"] = " ".join(stage)
2940 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2941 self._write_op_status(nslcmop_id, stage)
2942 await self.RO.delete("vnfd", ro_vnfd_id)
2943 self.logger.debug(logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id))
2944 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
2945 except Exception as e:
2946 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2947 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
2948 self.logger.debug(logging_text + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id))
2949 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
2950 failed_detail.append("ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e))
2951 self.logger.debug(logging_text + failed_detail[-1])
2952 else:
2953 failed_detail.append("ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e))
2954 self.logger.error(logging_text + failed_detail[-1])
2955
tiernoa2143262020-03-27 16:20:40 +00002956 if failed_detail:
2957 stage[2] = "Error deleting from VIM"
2958 else:
2959 stage[2] = "Deleted from VIM"
tiernoe876f672020-02-13 14:34:48 +00002960 db_nsr_update["detailed-status"] = " ".join(stage)
2961 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2962 self._write_op_status(nslcmop_id, stage)
2963
2964 if failed_detail:
tiernoa2143262020-03-27 16:20:40 +00002965 raise LcmException("; ".join(failed_detail))
tiernoe876f672020-02-13 14:34:48 +00002966
2967 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02002968 # Try to lock HA task here
2969 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
2970 if not task_is_locked_by_me:
2971 return
2972
tierno59d22d22018-09-25 18:10:19 +02002973 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
2974 self.logger.debug(logging_text + "Enter")
tiernoe876f672020-02-13 14:34:48 +00002975 timeout_ns_terminate = self.timeout_ns_terminate
tierno59d22d22018-09-25 18:10:19 +02002976 db_nsr = None
2977 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00002978 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02002979 exc = None
tiernoe876f672020-02-13 14:34:48 +00002980 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02002981 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00002982 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00002983 tasks_dict_info = {}
2984 db_nsr_update = {}
2985 stage = ["Stage 1/3: Preparing task.", "Waiting for previous operations to terminate.", ""]
2986 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02002987 try:
kuused124bfe2019-06-18 12:09:24 +02002988 # wait for any previous tasks in process
2989 await self.lcm_tasks.waitfor_related_HA("ns", 'nslcmops', nslcmop_id)
2990
tiernoe876f672020-02-13 14:34:48 +00002991 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
2992 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
2993 operation_params = db_nslcmop.get("operationParams") or {}
2994 if operation_params.get("timeout_ns_terminate"):
2995 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
2996 stage[1] = "Getting nsr={} from db.".format(nsr_id)
2997 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
2998
2999 db_nsr_update["operational-status"] = "terminating"
3000 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00003001 self._write_ns_status(
3002 nsr_id=nsr_id,
3003 ns_state="TERMINATING",
3004 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00003005 current_operation_id=nslcmop_id,
3006 other_update=db_nsr_update
quilesj4cda56b2019-12-05 10:02:20 +00003007 )
quilesj3655ae02019-12-12 16:08:35 +00003008 self._write_op_status(
3009 op_id=nslcmop_id,
tiernoe876f672020-02-13 14:34:48 +00003010 queuePosition=0,
3011 stage=stage
quilesj3655ae02019-12-12 16:08:35 +00003012 )
tiernoe876f672020-02-13 14:34:48 +00003013 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02003014 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
3015 return
tierno59d22d22018-09-25 18:10:19 +02003016
tiernoe876f672020-02-13 14:34:48 +00003017 stage[1] = "Getting vnf descriptors from db."
3018 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
3019 db_vnfds_from_id = {}
3020 db_vnfds_from_member_index = {}
3021 # Loop over VNFRs
3022 for vnfr in db_vnfrs_list:
3023 vnfd_id = vnfr["vnfd-id"]
3024 if vnfd_id not in db_vnfds_from_id:
3025 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
3026 db_vnfds_from_id[vnfd_id] = vnfd
3027 db_vnfds_from_member_index[vnfr["member-vnf-index-ref"]] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01003028
tiernoe876f672020-02-13 14:34:48 +00003029 # Destroy individual execution environments when there are terminating primitives.
3030 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00003031 # TODO - check before calling _destroy_N2VC
3032 # if not operation_params.get("skip_terminate_primitives"):#
3033 # or not vca.get("needed_terminate"):
3034 stage[0] = "Stage 2/3 execute terminating primitives."
3035 self.logger.debug(logging_text + stage[0])
3036 stage[1] = "Looking execution environment that needs terminate."
3037 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03003038
tierno588547c2020-07-01 15:30:20 +00003039 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00003040 config_descriptor = None
3041 if not vca or not vca.get("ee_id"):
3042 continue
3043 if not vca.get("member-vnf-index"):
3044 # ns
3045 config_descriptor = db_nsr.get("ns-configuration")
3046 elif vca.get("vdu_id"):
3047 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
garciaalea77ced72021-02-17 19:09:12 -03003048 config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
tierno588547c2020-07-01 15:30:20 +00003049 elif vca.get("kdu_name"):
3050 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
garciaalea77ced72021-02-17 19:09:12 -03003051 config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
tierno588547c2020-07-01 15:30:20 +00003052 else:
garciaalea77ced72021-02-17 19:09:12 -03003053 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
3054 config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
tierno588547c2020-07-01 15:30:20 +00003055 vca_type = vca.get("type")
3056 exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and
3057 vca.get("needed_terminate"))
tiernoaebd7da2020-08-07 06:36:38 +00003058 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
3059 # pending native charms
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003060 destroy_ee = True if vca_type in ("helm", "helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00003061 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
3062 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00003063 task = asyncio.ensure_future(
3064 self.destroy_N2VC(logging_text, db_nslcmop, vca, config_descriptor, vca_index,
3065 destroy_ee, exec_terminate_primitives))
tierno588547c2020-07-01 15:30:20 +00003066 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02003067
tierno588547c2020-07-01 15:30:20 +00003068 # wait for pending tasks of terminate primitives
3069 if tasks_dict_info:
tierno86e33612020-09-16 14:13:06 +00003070 self.logger.debug(logging_text + 'Waiting for tasks {}'.format(list(tasks_dict_info.keys())))
tierno588547c2020-07-01 15:30:20 +00003071 error_list = await self._wait_for_tasks(logging_text, tasks_dict_info,
3072 min(self.timeout_charm_delete, timeout_ns_terminate),
3073 stage, nslcmop_id)
tierno86e33612020-09-16 14:13:06 +00003074 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00003075 if error_list:
3076 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00003077
tiernoe876f672020-02-13 14:34:48 +00003078 # remove All execution environments at once
3079 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00003080
tierno49676be2020-04-07 16:34:35 +00003081 if nsr_deployed.get("VCA"):
3082 stage[1] = "Deleting all execution environments."
3083 self.logger.debug(logging_text + stage[1])
3084 task_delete_ee = asyncio.ensure_future(asyncio.wait_for(self._delete_all_N2VC(db_nsr=db_nsr),
3085 timeout=self.timeout_charm_delete))
3086 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
3087 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02003088
tiernoe876f672020-02-13 14:34:48 +00003089 # Delete from k8scluster
3090 stage[1] = "Deleting KDUs."
3091 self.logger.debug(logging_text + stage[1])
3092 # print(nsr_deployed)
3093 for kdu in get_iterable(nsr_deployed, "K8s"):
3094 if not kdu or not kdu.get("kdu-instance"):
3095 continue
3096 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00003097 if kdu.get("k8scluster-type") in self.k8scluster_map:
tiernoe876f672020-02-13 14:34:48 +00003098 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00003099 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
3100 cluster_uuid=kdu.get("k8scluster-uuid"),
3101 kdu_instance=kdu_instance))
tiernoe876f672020-02-13 14:34:48 +00003102 else:
3103 self.logger.error(logging_text + "Unknown k8s deployment type {}".
3104 format(kdu.get("k8scluster-type")))
3105 continue
3106 tasks_dict_info[task_delete_kdu_instance] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02003107
3108 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00003109 stage[1] = "Deleting ns from VIM."
tierno69f0d382020-05-07 13:08:09 +00003110 if self.ng_ro:
3111 task_delete_ro = asyncio.ensure_future(
3112 self._terminate_ng_ro(logging_text, nsr_deployed, nsr_id, nslcmop_id, stage))
3113 else:
3114 task_delete_ro = asyncio.ensure_future(
3115 self._terminate_RO(logging_text, nsr_deployed, nsr_id, nslcmop_id, stage))
tiernoe876f672020-02-13 14:34:48 +00003116 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02003117
tiernoe876f672020-02-13 14:34:48 +00003118 # rest of staff will be done at finally
3119
3120 except (ROclient.ROClientException, DbException, LcmException, N2VCException) as e:
3121 self.logger.error(logging_text + "Exit Exception {}".format(e))
3122 exc = e
3123 except asyncio.CancelledError:
3124 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(stage[1]))
3125 exc = "Operation was cancelled"
3126 except Exception as e:
3127 exc = traceback.format_exc()
3128 self.logger.critical(logging_text + "Exit Exception while '{}': {}".format(stage[1], e), exc_info=True)
3129 finally:
3130 if exc:
3131 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02003132 try:
tiernoe876f672020-02-13 14:34:48 +00003133 # wait for pending tasks
3134 if tasks_dict_info:
3135 stage[1] = "Waiting for terminate pending tasks."
3136 self.logger.debug(logging_text + stage[1])
3137 error_list += await self._wait_for_tasks(logging_text, tasks_dict_info, timeout_ns_terminate,
3138 stage, nslcmop_id)
3139 stage[1] = stage[2] = ""
3140 except asyncio.CancelledError:
3141 error_list.append("Cancelled")
3142 # TODO cancell all tasks
3143 except Exception as exc:
3144 error_list.append(str(exc))
3145 # update status at database
3146 if error_list:
3147 error_detail = "; ".join(error_list)
3148 # self.logger.error(logging_text + error_detail)
tiernob5203912020-08-11 11:20:13 +00003149 error_description_nslcmop = '{} Detail: {}'.format(stage[0], error_detail)
3150 error_description_nsr = 'Operation: TERMINATING.{}, {}.'.format(nslcmop_id, stage[0])
tierno59d22d22018-09-25 18:10:19 +02003151
tierno59d22d22018-09-25 18:10:19 +02003152 db_nsr_update["operational-status"] = "failed"
tiernoa2143262020-03-27 16:20:40 +00003153 db_nsr_update["detailed-status"] = error_description_nsr + " Detail: " + error_detail
tiernoe876f672020-02-13 14:34:48 +00003154 db_nslcmop_update["detailed-status"] = error_detail
3155 nslcmop_operation_state = "FAILED"
3156 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02003157 else:
tiernoa2143262020-03-27 16:20:40 +00003158 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003159 error_description_nsr = error_description_nslcmop = None
3160 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02003161 db_nsr_update["operational-status"] = "terminated"
3162 db_nsr_update["detailed-status"] = "Done"
3163 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
3164 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00003165 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02003166
tiernoe876f672020-02-13 14:34:48 +00003167 if db_nsr:
3168 self._write_ns_status(
3169 nsr_id=nsr_id,
3170 ns_state=ns_state,
3171 current_operation="IDLE",
3172 current_operation_id=None,
3173 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003174 error_detail=error_detail,
tiernoe876f672020-02-13 14:34:48 +00003175 other_update=db_nsr_update
3176 )
tiernoa17d4f42020-04-28 09:59:23 +00003177 self._write_op_status(
3178 op_id=nslcmop_id,
3179 stage="",
3180 error_message=error_description_nslcmop,
3181 operation_state=nslcmop_operation_state,
3182 other_update=db_nslcmop_update,
3183 )
lloretgalleg6d488782020-07-22 10:13:46 +00003184 if ns_state == "NOT_INSTANTIATED":
3185 try:
3186 self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "NOT_INSTANTIATED"})
3187 except DbException as e:
3188 self.logger.warn(logging_text + 'Error writing VNFR status for nsr-id-ref: {} -> {}'.
3189 format(nsr_id, e))
tiernoa17d4f42020-04-28 09:59:23 +00003190 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00003191 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02003192 if nslcmop_operation_state:
3193 try:
3194 await self.msg.aiowrite("ns", "terminated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tiernoc2564fe2019-01-28 16:18:56 +00003195 "operationState": nslcmop_operation_state,
3196 "autoremove": autoremove},
tierno8a518872018-12-21 13:42:14 +00003197 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003198 except Exception as e:
3199 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02003200
tierno59d22d22018-09-25 18:10:19 +02003201 self.logger.debug(logging_text + "Exit")
3202 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
3203
tiernoe876f672020-02-13 14:34:48 +00003204 async def _wait_for_tasks(self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None):
3205 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00003206 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00003207 error_list = []
3208 pending_tasks = list(created_tasks_info.keys())
3209 num_tasks = len(pending_tasks)
3210 num_done = 0
3211 stage[1] = "{}/{}.".format(num_done, num_tasks)
3212 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00003213 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00003214 new_error = None
tiernoe876f672020-02-13 14:34:48 +00003215 _timeout = timeout + time_start - time()
3216 done, pending_tasks = await asyncio.wait(pending_tasks, timeout=_timeout,
3217 return_when=asyncio.FIRST_COMPLETED)
3218 num_done += len(done)
3219 if not done: # Timeout
3220 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00003221 new_error = created_tasks_info[task] + ": Timeout"
3222 error_detail_list.append(new_error)
3223 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00003224 break
3225 for task in done:
3226 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00003227 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00003228 else:
3229 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00003230 if exc:
3231 if isinstance(exc, asyncio.TimeoutError):
3232 exc = "Timeout"
3233 new_error = created_tasks_info[task] + ": {}".format(exc)
3234 error_list.append(created_tasks_info[task])
3235 error_detail_list.append(new_error)
tierno28c63da2020-04-20 16:28:56 +00003236 if isinstance(exc, (str, DbException, N2VCException, ROclient.ROClientException, LcmException,
tierno2357f4e2020-10-19 16:38:59 +00003237 K8sException, NgRoException)):
tierno067e04a2020-03-31 12:53:13 +00003238 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00003239 else:
tierno067e04a2020-03-31 12:53:13 +00003240 exc_traceback = "".join(traceback.format_exception(None, exc, exc.__traceback__))
tierno2357f4e2020-10-19 16:38:59 +00003241 self.logger.error(logging_text + created_tasks_info[task] + " " + exc_traceback)
tierno067e04a2020-03-31 12:53:13 +00003242 else:
3243 self.logger.debug(logging_text + created_tasks_info[task] + ": Done")
tiernoe876f672020-02-13 14:34:48 +00003244 stage[1] = "{}/{}.".format(num_done, num_tasks)
3245 if new_error:
tiernoa2143262020-03-27 16:20:40 +00003246 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00003247 if nsr_id: # update also nsr
tiernoa2143262020-03-27 16:20:40 +00003248 self.update_db_2("nsrs", nsr_id, {"errorDescription": "Error at: " + ", ".join(error_list),
3249 "errorDetail": ". ".join(error_detail_list)})
tiernoe876f672020-02-13 14:34:48 +00003250 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00003251 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00003252
tiernoda1ff8c2020-10-22 14:12:46 +00003253 @staticmethod
3254 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00003255 """
3256 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
3257 The default-value is used. If it is between < > it look for a value at instantiation_params
3258 :param primitive_desc: portion of VNFD/NSD that describes primitive
3259 :param params: Params provided by user
3260 :param instantiation_params: Instantiation params provided by user
3261 :return: a dictionary with the calculated params
3262 """
3263 calculated_params = {}
3264 for parameter in primitive_desc.get("parameter", ()):
3265 param_name = parameter["name"]
3266 if param_name in params:
3267 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00003268 elif "default-value" in parameter or "value" in parameter:
3269 if "value" in parameter:
3270 calculated_params[param_name] = parameter["value"]
3271 else:
3272 calculated_params[param_name] = parameter["default-value"]
3273 if isinstance(calculated_params[param_name], str) and calculated_params[param_name].startswith("<") \
3274 and calculated_params[param_name].endswith(">"):
3275 if calculated_params[param_name][1:-1] in instantiation_params:
3276 calculated_params[param_name] = instantiation_params[calculated_params[param_name][1:-1]]
tiernoda964822019-01-14 15:53:47 +00003277 else:
3278 raise LcmException("Parameter {} needed to execute primitive {} not provided".
tiernod8323042019-08-09 11:32:23 +00003279 format(calculated_params[param_name], primitive_desc["name"]))
tiernoda964822019-01-14 15:53:47 +00003280 else:
3281 raise LcmException("Parameter {} needed to execute primitive {} not provided".
3282 format(param_name, primitive_desc["name"]))
tierno59d22d22018-09-25 18:10:19 +02003283
tiernoda964822019-01-14 15:53:47 +00003284 if isinstance(calculated_params[param_name], (dict, list, tuple)):
bravof922c4172020-11-24 21:21:43 -03003285 calculated_params[param_name] = yaml.safe_dump(calculated_params[param_name],
3286 default_flow_style=True, width=256)
tiernoda964822019-01-14 15:53:47 +00003287 elif isinstance(calculated_params[param_name], str) and calculated_params[param_name].startswith("!!yaml "):
3288 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00003289 if parameter.get("data-type") == "INTEGER":
3290 try:
3291 calculated_params[param_name] = int(calculated_params[param_name])
3292 except ValueError: # error converting string to int
3293 raise LcmException(
3294 "Parameter {} of primitive {} must be integer".format(param_name, primitive_desc["name"]))
3295 elif parameter.get("data-type") == "BOOLEAN":
3296 calculated_params[param_name] = not ((str(calculated_params[param_name])).lower() == 'false')
tiernoc3f2a822019-11-05 13:45:04 +00003297
3298 # add always ns_config_info if primitive name is config
3299 if primitive_desc["name"] == "config":
3300 if "ns_config_info" in instantiation_params:
3301 calculated_params["ns_config_info"] = instantiation_params["ns_config_info"]
tiernoda964822019-01-14 15:53:47 +00003302 return calculated_params
3303
tiernoa278b842020-07-08 15:33:55 +00003304 def _look_for_deployed_vca(self, deployed_vca, member_vnf_index, vdu_id, vdu_count_index, kdu_name=None,
3305 ee_descriptor_id=None):
tiernoe876f672020-02-13 14:34:48 +00003306 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
3307 for vca in deployed_vca:
3308 if not vca:
3309 continue
3310 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
3311 continue
tiernoe876f672020-02-13 14:34:48 +00003312 if vdu_count_index is not None and vdu_count_index != vca["vdu_count_index"]:
3313 continue
3314 if kdu_name and kdu_name != vca["kdu_name"]:
3315 continue
tiernoa278b842020-07-08 15:33:55 +00003316 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
3317 continue
tiernoe876f672020-02-13 14:34:48 +00003318 break
3319 else:
3320 # vca_deployed not found
tiernoa278b842020-07-08 15:33:55 +00003321 raise LcmException("charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
3322 " is not deployed".format(member_vnf_index, vdu_id, vdu_count_index, kdu_name,
3323 ee_descriptor_id))
tiernoe876f672020-02-13 14:34:48 +00003324 # get ee_id
3325 ee_id = vca.get("ee_id")
tierno588547c2020-07-01 15:30:20 +00003326 vca_type = vca.get("type", "lxc_proxy_charm") # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00003327 if not ee_id:
tierno067e04a2020-03-31 12:53:13 +00003328 raise LcmException("charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
tiernoe876f672020-02-13 14:34:48 +00003329 "execution environment"
tierno067e04a2020-03-31 12:53:13 +00003330 .format(member_vnf_index, vdu_id, kdu_name, vdu_count_index))
tierno588547c2020-07-01 15:30:20 +00003331 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00003332
bravof922c4172020-11-24 21:21:43 -03003333 async def _ns_execute_primitive(self, ee_id, primitive, primitive_params, retries=0, retries_interval=30,
3334 timeout=None, vca_type=None, db_dict=None) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00003335 try:
tierno98ad6ea2019-05-30 17:16:28 +00003336 if primitive == "config":
3337 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00003338
tierno588547c2020-07-01 15:30:20 +00003339 vca_type = vca_type or "lxc_proxy_charm"
3340
quilesj7e13aeb2019-10-08 13:34:55 +02003341 while retries >= 0:
3342 try:
tierno067e04a2020-03-31 12:53:13 +00003343 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00003344 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00003345 ee_id=ee_id,
3346 primitive_name=primitive,
3347 params_dict=primitive_params,
3348 progress_timeout=self.timeout_progress_primitive,
tierno588547c2020-07-01 15:30:20 +00003349 total_timeout=self.timeout_primitive,
3350 db_dict=db_dict),
tierno067e04a2020-03-31 12:53:13 +00003351 timeout=timeout or self.timeout_primitive)
quilesj7e13aeb2019-10-08 13:34:55 +02003352 # execution was OK
3353 break
tierno067e04a2020-03-31 12:53:13 +00003354 except asyncio.CancelledError:
3355 raise
3356 except Exception as e: # asyncio.TimeoutError
3357 if isinstance(e, asyncio.TimeoutError):
3358 e = "Timeout"
quilesj7e13aeb2019-10-08 13:34:55 +02003359 retries -= 1
3360 if retries >= 0:
tierno73d8bd02019-11-18 17:33:27 +00003361 self.logger.debug('Error executing action {} on {} -> {}'.format(primitive, ee_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +02003362 # wait and retry
3363 await asyncio.sleep(retries_interval, loop=self.loop)
tierno73d8bd02019-11-18 17:33:27 +00003364 else:
tierno067e04a2020-03-31 12:53:13 +00003365 return 'FAILED', str(e)
quilesj7e13aeb2019-10-08 13:34:55 +02003366
tiernoe876f672020-02-13 14:34:48 +00003367 return 'COMPLETED', output
quilesj7e13aeb2019-10-08 13:34:55 +02003368
tierno067e04a2020-03-31 12:53:13 +00003369 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003370 raise
quilesj7e13aeb2019-10-08 13:34:55 +02003371 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003372 return 'FAIL', 'Error executing action {}: {}'.format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02003373
3374 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003375 # Try to lock HA task here
3376 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3377 if not task_is_locked_by_me:
3378 return
3379
tierno59d22d22018-09-25 18:10:19 +02003380 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
3381 self.logger.debug(logging_text + "Enter")
3382 # get all needed from database
3383 db_nsr = None
3384 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00003385 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02003386 db_nslcmop_update = {}
3387 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00003388 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02003389 exc = None
3390 try:
kuused124bfe2019-06-18 12:09:24 +02003391 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00003392 step = "Waiting for previous operations to terminate"
kuused124bfe2019-06-18 12:09:24 +02003393 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
3394
quilesj4cda56b2019-12-05 10:02:20 +00003395 self._write_ns_status(
3396 nsr_id=nsr_id,
3397 ns_state=None,
3398 current_operation="RUNNING ACTION",
3399 current_operation_id=nslcmop_id
3400 )
3401
tierno59d22d22018-09-25 18:10:19 +02003402 step = "Getting information from database"
3403 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
3404 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernoda964822019-01-14 15:53:47 +00003405
tiernoe4f7e6c2018-11-27 14:55:30 +00003406 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00003407 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02003408 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003409 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00003410 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00003411 primitive = db_nslcmop["operationParams"]["primitive"]
3412 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
3413 timeout_ns_action = db_nslcmop["operationParams"].get("timeout_ns_action", self.timeout_primitive)
tierno59d22d22018-09-25 18:10:19 +02003414
tierno1b633412019-02-25 16:48:23 +00003415 if vnf_index:
3416 step = "Getting vnfr from database"
3417 db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id})
3418 step = "Getting vnfd from database"
3419 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
3420 else:
tierno067e04a2020-03-31 12:53:13 +00003421 step = "Getting nsd from database"
3422 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00003423
tierno82974b22018-11-27 21:55:36 +00003424 # for backward compatibility
3425 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
3426 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
3427 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
3428 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3429
tiernoda964822019-01-14 15:53:47 +00003430 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00003431 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00003432 if vdu_id:
garciaalea77ced72021-02-17 19:09:12 -03003433 descriptor_configuration = get_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003434 elif kdu_name:
garciaalea77ced72021-02-17 19:09:12 -03003435 descriptor_configuration = get_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00003436 elif vnf_index:
garciaalea77ced72021-02-17 19:09:12 -03003437 descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
tierno1b633412019-02-25 16:48:23 +00003438 else:
tiernoa278b842020-07-08 15:33:55 +00003439 descriptor_configuration = db_nsd.get("ns-configuration")
3440
3441 if descriptor_configuration and descriptor_configuration.get("config-primitive"):
3442 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00003443 if config_primitive["name"] == primitive:
3444 config_primitive_desc = config_primitive
3445 break
tiernoda964822019-01-14 15:53:47 +00003446
garciadeblas6bed6b32020-07-20 11:05:42 +00003447 if not config_primitive_desc:
3448 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
3449 raise LcmException("Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".
3450 format(primitive))
3451 primitive_name = primitive
3452 ee_descriptor_id = None
3453 else:
3454 primitive_name = config_primitive_desc.get("execution-environment-primitive", primitive)
3455 ee_descriptor_id = config_primitive_desc.get("execution-environment-ref")
tierno1b633412019-02-25 16:48:23 +00003456
tierno1b633412019-02-25 16:48:23 +00003457 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00003458 if vdu_id:
3459 vdur = next((x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None)
bravof922c4172020-11-24 21:21:43 -03003460 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00003461 elif kdu_name:
3462 kdur = next((x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None)
bravof922c4172020-11-24 21:21:43 -03003463 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00003464 else:
bravof922c4172020-11-24 21:21:43 -03003465 desc_params = parse_yaml_strings(db_vnfr.get("additionalParamsForVnf"))
tierno1b633412019-02-25 16:48:23 +00003466 else:
bravof922c4172020-11-24 21:21:43 -03003467 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
garciaalea77ced72021-02-17 19:09:12 -03003468 if kdu_name and get_configuration(db_vnfd, kdu_name):
3469 kdu_configuration = get_configuration(db_vnfd, kdu_name)
David Garciad41dbd62020-12-10 12:52:52 +01003470 actions = set()
David Garcia95cc9c52021-02-16 21:07:58 +01003471 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01003472 actions.add(primitive["name"])
David Garcia95cc9c52021-02-16 21:07:58 +01003473 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01003474 actions.add(primitive["name"])
3475 kdu_action = True if primitive_name in actions else False
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003476
tiernoda964822019-01-14 15:53:47 +00003477 # TODO check if ns is in a proper status
tiernoa278b842020-07-08 15:33:55 +00003478 if kdu_name and (primitive_name in ("upgrade", "rollback", "status") or kdu_action):
tierno067e04a2020-03-31 12:53:13 +00003479 # kdur and desc_params already set from before
3480 if primitive_params:
3481 desc_params.update(primitive_params)
3482 # TODO Check if we will need something at vnf level
3483 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
3484 if kdu_name == kdu["kdu-name"] and kdu["member-vnf-index"] == vnf_index:
3485 break
3486 else:
3487 raise LcmException("KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index))
quilesj7e13aeb2019-10-08 13:34:55 +02003488
tierno067e04a2020-03-31 12:53:13 +00003489 if kdu.get("k8scluster-type") not in self.k8scluster_map:
3490 msg = "unknown k8scluster-type '{}'".format(kdu.get("k8scluster-type"))
3491 raise LcmException(msg)
3492
3493 db_dict = {"collection": "nsrs",
3494 "filter": {"_id": nsr_id},
3495 "path": "_admin.deployed.K8s.{}".format(index)}
tiernoa278b842020-07-08 15:33:55 +00003496 self.logger.debug(logging_text + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name))
3497 step = "Executing kdu {}".format(primitive_name)
3498 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00003499 if desc_params.get("kdu_model"):
3500 kdu_model = desc_params.get("kdu_model")
3501 del desc_params["kdu_model"]
3502 else:
3503 kdu_model = kdu.get("kdu-model")
3504 parts = kdu_model.split(sep=":")
3505 if len(parts) == 2:
3506 kdu_model = parts[0]
3507
3508 detailed_status = await asyncio.wait_for(
3509 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
3510 cluster_uuid=kdu.get("k8scluster-uuid"),
3511 kdu_instance=kdu.get("kdu-instance"),
3512 atomic=True, kdu_model=kdu_model,
3513 params=desc_params, db_dict=db_dict,
3514 timeout=timeout_ns_action),
3515 timeout=timeout_ns_action + 10)
3516 self.logger.debug(logging_text + " Upgrade of kdu {} done".format(detailed_status))
tiernoa278b842020-07-08 15:33:55 +00003517 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00003518 detailed_status = await asyncio.wait_for(
3519 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
3520 cluster_uuid=kdu.get("k8scluster-uuid"),
3521 kdu_instance=kdu.get("kdu-instance"),
3522 db_dict=db_dict),
3523 timeout=timeout_ns_action)
tiernoa278b842020-07-08 15:33:55 +00003524 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00003525 detailed_status = await asyncio.wait_for(
3526 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
3527 cluster_uuid=kdu.get("k8scluster-uuid"),
3528 kdu_instance=kdu.get("kdu-instance")),
3529 timeout=timeout_ns_action)
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003530 else:
3531 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(kdu["kdu-name"], nsr_id)
3532 params = self._map_primitive_params(config_primitive_desc, primitive_params, desc_params)
3533
3534 detailed_status = await asyncio.wait_for(
3535 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
3536 cluster_uuid=kdu.get("k8scluster-uuid"),
3537 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00003538 primitive_name=primitive_name,
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003539 params=params, db_dict=db_dict,
3540 timeout=timeout_ns_action),
3541 timeout=timeout_ns_action)
tierno067e04a2020-03-31 12:53:13 +00003542
3543 if detailed_status:
3544 nslcmop_operation_state = 'COMPLETED'
3545 else:
3546 detailed_status = ''
3547 nslcmop_operation_state = 'FAILED'
tierno067e04a2020-03-31 12:53:13 +00003548 else:
bravof922c4172020-11-24 21:21:43 -03003549 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"], member_vnf_index=vnf_index,
3550 vdu_id=vdu_id, vdu_count_index=vdu_count_index,
tiernoa278b842020-07-08 15:33:55 +00003551 ee_descriptor_id=ee_descriptor_id)
tierno588547c2020-07-01 15:30:20 +00003552 db_nslcmop_notif = {"collection": "nslcmops",
3553 "filter": {"_id": nslcmop_id},
3554 "path": "admin.VCA"}
tierno067e04a2020-03-31 12:53:13 +00003555 nslcmop_operation_state, detailed_status = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00003556 ee_id,
tiernoa278b842020-07-08 15:33:55 +00003557 primitive=primitive_name,
tierno067e04a2020-03-31 12:53:13 +00003558 primitive_params=self._map_primitive_params(config_primitive_desc, primitive_params, desc_params),
tierno588547c2020-07-01 15:30:20 +00003559 timeout=timeout_ns_action,
3560 vca_type=vca_type,
3561 db_dict=db_nslcmop_notif)
tierno067e04a2020-03-31 12:53:13 +00003562
3563 db_nslcmop_update["detailed-status"] = detailed_status
3564 error_description_nslcmop = detailed_status if nslcmop_operation_state == "FAILED" else ""
3565 self.logger.debug(logging_text + " task Done with result {} {}".format(nslcmop_operation_state,
3566 detailed_status))
tierno59d22d22018-09-25 18:10:19 +02003567 return # database update is called inside finally
3568
tiernof59ad6c2020-04-08 12:50:52 +00003569 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02003570 self.logger.error(logging_text + "Exit Exception {}".format(e))
3571 exc = e
3572 except asyncio.CancelledError:
3573 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(step))
3574 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00003575 except asyncio.TimeoutError:
3576 self.logger.error(logging_text + "Timeout while '{}'".format(step))
3577 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02003578 except Exception as e:
3579 exc = traceback.format_exc()
3580 self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
3581 finally:
tierno067e04a2020-03-31 12:53:13 +00003582 if exc:
3583 db_nslcmop_update["detailed-status"] = detailed_status = error_description_nslcmop = \
kuuse0ca67472019-05-13 15:59:27 +02003584 "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00003585 nslcmop_operation_state = "FAILED"
3586 if db_nsr:
3587 self._write_ns_status(
3588 nsr_id=nsr_id,
3589 ns_state=db_nsr["nsState"], # TODO check if degraded. For the moment use previous status
3590 current_operation="IDLE",
3591 current_operation_id=None,
3592 # error_description=error_description_nsr,
3593 # error_detail=error_detail,
3594 other_update=db_nsr_update
3595 )
3596
bravof922c4172020-11-24 21:21:43 -03003597 self._write_op_status(op_id=nslcmop_id, stage="", error_message=error_description_nslcmop,
3598 operation_state=nslcmop_operation_state, other_update=db_nslcmop_update)
tierno067e04a2020-03-31 12:53:13 +00003599
tierno59d22d22018-09-25 18:10:19 +02003600 if nslcmop_operation_state:
3601 try:
3602 await self.msg.aiowrite("ns", "actioned", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tierno8a518872018-12-21 13:42:14 +00003603 "operationState": nslcmop_operation_state},
3604 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003605 except Exception as e:
3606 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
3607 self.logger.debug(logging_text + "Exit")
3608 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00003609 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02003610
3611 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003612 # Try to lock HA task here
3613 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3614 if not task_is_locked_by_me:
3615 return
3616
tierno59d22d22018-09-25 18:10:19 +02003617 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
tierno2357f4e2020-10-19 16:38:59 +00003618 stage = ['', '', '']
3619 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02003620 self.logger.debug(logging_text + "Enter")
3621 # get all needed from database
3622 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02003623 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00003624 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02003625 exc = None
tierno9ab95942018-10-10 16:44:22 +02003626 # in case of error, indicates what part of scale was failed to put nsr at error status
3627 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02003628 old_operational_status = ""
3629 old_config_status = ""
tierno59d22d22018-09-25 18:10:19 +02003630 try:
kuused124bfe2019-06-18 12:09:24 +02003631 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00003632 step = "Waiting for previous operations to terminate"
kuused124bfe2019-06-18 12:09:24 +02003633 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
bravof922c4172020-11-24 21:21:43 -03003634 self._write_ns_status(nsr_id=nsr_id, ns_state=None,
3635 current_operation="SCALING", current_operation_id=nslcmop_id)
quilesj4cda56b2019-12-05 10:02:20 +00003636
ikalyvas02d9e7b2019-05-27 18:16:01 +03003637 step = "Getting nslcmop from database"
ikalyvas02d9e7b2019-05-27 18:16:01 +03003638 self.logger.debug(step + " after having waited for previous tasks to be completed")
3639 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03003640
ikalyvas02d9e7b2019-05-27 18:16:01 +03003641 step = "Getting nsr from database"
3642 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03003643 old_operational_status = db_nsr["operational-status"]
3644 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03003645
tierno59d22d22018-09-25 18:10:19 +02003646 step = "Parsing scaling parameters"
3647 db_nsr_update["operational-status"] = "scaling"
3648 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00003649 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003650
3651 #######
3652 nsr_deployed = db_nsr["_admin"].get("deployed")
3653 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tiernoda6fb102019-11-23 00:36:52 +00003654 # vdu_id = db_nslcmop["operationParams"].get("vdu_id")
3655 # vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
3656 # vdu_name = db_nslcmop["operationParams"].get("vdu_name")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003657 #######
3658
tierno59d22d22018-09-25 18:10:19 +02003659 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["member-vnf-index"]
3660 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"]
3661 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00003662 # for backward compatibility
3663 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
3664 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
3665 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
3666 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3667
tierno59d22d22018-09-25 18:10:19 +02003668 step = "Getting vnfr from database"
3669 db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id})
bravof922c4172020-11-24 21:21:43 -03003670
tierno59d22d22018-09-25 18:10:19 +02003671 step = "Getting vnfd from database"
3672 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03003673
tierno59d22d22018-09-25 18:10:19 +02003674 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03003675 scaling_descriptor = find_in_list(
3676 get_scaling_aspect(
3677 db_vnfd
3678 ),
3679 lambda scale_desc: scale_desc["name"] == scaling_group
3680 )
3681 if not scaling_descriptor:
tierno59d22d22018-09-25 18:10:19 +02003682 raise LcmException("input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
3683 "at vnfd:scaling-group-descriptor".format(scaling_group))
ikalyvas02d9e7b2019-05-27 18:16:01 +03003684
tierno15b1cf12019-08-29 13:21:40 +00003685 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03003686 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02003687 nb_scale_op = 0
3688 if not db_nsr["_admin"].get("scaling-group"):
3689 self.update_db_2("nsrs", nsr_id, {"_admin.scaling-group": [{"name": scaling_group, "nb-scale-op": 0}]})
3690 admin_scale_index = 0
3691 else:
3692 for admin_scale_index, admin_scale_info in enumerate(db_nsr["_admin"]["scaling-group"]):
3693 if admin_scale_info["name"] == scaling_group:
3694 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
3695 break
tierno9ab95942018-10-10 16:44:22 +02003696 else: # not found, set index one plus last element and add new entry with the name
3697 admin_scale_index += 1
3698 db_nsr_update["_admin.scaling-group.{}.name".format(admin_scale_index)] = scaling_group
tierno59d22d22018-09-25 18:10:19 +02003699 RO_scaling_info = []
3700 vdu_scaling_info = {"scaling_group_name": scaling_group, "vdu": []}
3701 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03003702 if "aspect-delta-details" not in scaling_descriptor:
3703 raise LcmException(
3704 "Aspect delta details not fount in scaling descriptor {}".format(
3705 scaling_descriptor["name"]
3706 )
3707 )
tierno59d22d22018-09-25 18:10:19 +02003708 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03003709 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02003710
tierno59d22d22018-09-25 18:10:19 +02003711 vdu_scaling_info["scaling_direction"] = "OUT"
3712 vdu_scaling_info["vdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03003713 for delta in deltas:
3714 for vdu_delta in delta["vdu-delta"]:
3715 vdud = get_vdu(db_vnfd, vdu_delta["id"])
3716 vdu_index = get_vdu_index(db_vnfr, vdu_delta["id"])
3717 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
tierno72ef84f2020-10-06 08:22:07 +00003718 if cloud_init_text:
bravof832f8992020-12-07 12:57:31 -03003719 additional_params = self._get_vdu_additional_params(db_vnfr, vdud["id"]) or {}
3720 cloud_init_list = []
3721
3722 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
3723 max_instance_count = 10
3724 if vdu_profile and "max-number-of-instances" in vdu_profile:
3725 max_instance_count = vdu_profile.get("max-number-of-instances", 10)
3726
3727 deafult_instance_num = get_number_of_instances(db_vnfd, vdud["id"])
3728
3729 nb_scale_op += vdu_delta.get("number-of-instances", 1)
3730
3731 if nb_scale_op + deafult_instance_num > max_instance_count:
3732 raise LcmException(
3733 "reached the limit of {} (max-instance-count) "
3734 "scaling-out operations for the "
3735 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
bravof922c4172020-11-24 21:21:43 -03003736 )
bravof832f8992020-12-07 12:57:31 -03003737 for x in range(vdu_delta.get("number-of-instances", 1)):
3738 if cloud_init_text:
3739 # TODO Information of its own ip is not available because db_vnfr is not updated.
3740 additional_params["OSM"] = get_osm_params(
3741 db_vnfr,
3742 vdu_delta["id"],
3743 vdu_index + x
bravof922c4172020-11-24 21:21:43 -03003744 )
bravof832f8992020-12-07 12:57:31 -03003745 cloud_init_list.append(
3746 self._parse_cloud_init(
3747 cloud_init_text,
3748 additional_params,
3749 db_vnfd["id"],
3750 vdud["id"]
3751 )
3752 )
3753 RO_scaling_info.append(
3754 {
3755 "osm_vdu_id": vdu_delta["id"],
3756 "member-vnf-index": vnf_index,
3757 "type": "create",
3758 "count": vdu_delta.get("number-of-instances", 1)
3759 }
3760 )
3761 if cloud_init_list:
3762 RO_scaling_info[-1]["cloud_init"] = cloud_init_list
3763 vdu_scaling_info["vdu-create"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
ikalyvas02d9e7b2019-05-27 18:16:01 +03003764
tierno59d22d22018-09-25 18:10:19 +02003765 elif scaling_type == "SCALE_IN":
tierno59d22d22018-09-25 18:10:19 +02003766 if "min-instance-count" in scaling_descriptor and scaling_descriptor["min-instance-count"] is not None:
3767 min_instance_count = int(scaling_descriptor["min-instance-count"])
bravof832f8992020-12-07 12:57:31 -03003768
tierno59d22d22018-09-25 18:10:19 +02003769 vdu_scaling_info["scaling_direction"] = "IN"
3770 vdu_scaling_info["vdu-delete"] = {}
bravof832f8992020-12-07 12:57:31 -03003771 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
3772 for delta in deltas:
3773 for vdu_delta in delta["vdu-delta"]:
3774 min_instance_count = 0
3775 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
3776 if vdu_profile and "min-number-of-instances" in vdu_profile:
3777 min_instance_count = vdu_profile["min-number-of-instances"]
3778
3779 deafult_instance_num = get_number_of_instances(db_vnfd, vdu_delta["id"])
3780
3781 nb_scale_op -= vdu_delta.get("number-of-instances", 1)
3782 if nb_scale_op + deafult_instance_num < min_instance_count:
3783 raise LcmException(
3784 "reached the limit of {} (min-instance-count) scaling-in operations for the "
3785 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
3786 )
3787 RO_scaling_info.append({"osm_vdu_id": vdu_delta["id"], "member-vnf-index": vnf_index,
3788 "type": "delete", "count": vdu_delta.get("number-of-instances", 1)})
3789 vdu_scaling_info["vdu-delete"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
tierno59d22d22018-09-25 18:10:19 +02003790
3791 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
tierno27246d82018-09-27 15:59:09 +02003792 vdu_delete = copy(vdu_scaling_info.get("vdu-delete"))
tierno59d22d22018-09-25 18:10:19 +02003793 if vdu_scaling_info["scaling_direction"] == "IN":
3794 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02003795 if vdu_delete.get(vdur["vdu-id-ref"]):
3796 vdu_delete[vdur["vdu-id-ref"]] -= 1
tierno59d22d22018-09-25 18:10:19 +02003797 vdu_scaling_info["vdu"].append({
tierno2357f4e2020-10-19 16:38:59 +00003798 "name": vdur.get("name") or vdur.get("vdu-name"),
tierno59d22d22018-09-25 18:10:19 +02003799 "vdu_id": vdur["vdu-id-ref"],
3800 "interface": []
3801 })
3802 for interface in vdur["interfaces"]:
3803 vdu_scaling_info["vdu"][-1]["interface"].append({
3804 "name": interface["name"],
3805 "ip_address": interface["ip-address"],
3806 "mac_address": interface.get("mac-address"),
3807 })
tierno2357f4e2020-10-19 16:38:59 +00003808 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02003809
kuuseac3a8882019-10-03 10:48:06 +02003810 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02003811 step = "Executing pre-scale vnf-config-primitive"
3812 if scaling_descriptor.get("scaling-config-action"):
3813 for scaling_config_action in scaling_descriptor["scaling-config-action"]:
kuuseac3a8882019-10-03 10:48:06 +02003814 if (scaling_config_action.get("trigger") == "pre-scale-in" and scaling_type == "SCALE_IN") \
3815 or (scaling_config_action.get("trigger") == "pre-scale-out" and scaling_type == "SCALE_OUT"):
tierno59d22d22018-09-25 18:10:19 +02003816 vnf_config_primitive = scaling_config_action["vnf-config-primitive-name-ref"]
3817 step = db_nslcmop_update["detailed-status"] = \
3818 "executing pre-scale scaling-config-action '{}'".format(vnf_config_primitive)
tiernoda964822019-01-14 15:53:47 +00003819
tierno59d22d22018-09-25 18:10:19 +02003820 # look for primitive
garciaalea77ced72021-02-17 19:09:12 -03003821 for config_primitive in (get_configuration(
3822 db_vnfd, db_vnfd["id"]
3823 ) or {}).get("config-primitive", ()):
tierno59d22d22018-09-25 18:10:19 +02003824 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02003825 break
3826 else:
3827 raise LcmException(
3828 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00003829 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
tiernoa278b842020-07-08 15:33:55 +00003830 "primitive".format(scaling_group, vnf_config_primitive))
tiernoda964822019-01-14 15:53:47 +00003831
tierno16fedf52019-05-24 08:38:26 +00003832 vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
tiernoda964822019-01-14 15:53:47 +00003833 if db_vnfr.get("additionalParamsForVnf"):
3834 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02003835
tierno9ab95942018-10-10 16:44:22 +02003836 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02003837 db_nsr_update["config-status"] = "configuring pre-scaling"
kuuseac3a8882019-10-03 10:48:06 +02003838 primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params)
3839
tierno7c4e24c2020-05-13 08:41:35 +00003840 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02003841 op_index = self._check_or_add_scale_suboperation(
3842 db_nslcmop, nslcmop_id, vnf_index, vnf_config_primitive, primitive_params, 'PRE-SCALE')
tierno7c4e24c2020-05-13 08:41:35 +00003843 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02003844 # Skip sub-operation
3845 result = 'COMPLETED'
3846 result_detail = 'Done'
3847 self.logger.debug(logging_text +
3848 "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
3849 vnf_config_primitive, result, result_detail))
3850 else:
tierno7c4e24c2020-05-13 08:41:35 +00003851 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02003852 # New sub-operation: Get index of this sub-operation
3853 op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
3854 self.logger.debug(logging_text + "vnf_config_primitive={} New sub-operation".
3855 format(vnf_config_primitive))
3856 else:
tierno7c4e24c2020-05-13 08:41:35 +00003857 # retry: Get registered params for this existing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003858 op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
3859 vnf_index = op.get('member_vnf_index')
3860 vnf_config_primitive = op.get('primitive')
3861 primitive_params = op.get('primitive_params')
tierno7c4e24c2020-05-13 08:41:35 +00003862 self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry".
kuuseac3a8882019-10-03 10:48:06 +02003863 format(vnf_config_primitive))
tierno588547c2020-07-01 15:30:20 +00003864 # Execute the primitive, either with new (first-time) or registered (reintent) args
tiernoa278b842020-07-08 15:33:55 +00003865 ee_descriptor_id = config_primitive.get("execution-environment-ref")
3866 primitive_name = config_primitive.get("execution-environment-primitive",
3867 vnf_config_primitive)
tierno588547c2020-07-01 15:30:20 +00003868 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"],
3869 member_vnf_index=vnf_index,
3870 vdu_id=None,
tiernoa278b842020-07-08 15:33:55 +00003871 vdu_count_index=None,
3872 ee_descriptor_id=ee_descriptor_id)
kuuseac3a8882019-10-03 10:48:06 +02003873 result, result_detail = await self._ns_execute_primitive(
tiernoa278b842020-07-08 15:33:55 +00003874 ee_id, primitive_name, primitive_params, vca_type)
kuuseac3a8882019-10-03 10:48:06 +02003875 self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format(
3876 vnf_config_primitive, result, result_detail))
3877 # Update operationState = COMPLETED | FAILED
3878 self._update_suboperation_status(
3879 db_nslcmop, op_index, result, result_detail)
3880
tierno59d22d22018-09-25 18:10:19 +02003881 if result == "FAILED":
3882 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02003883 db_nsr_update["config-status"] = old_config_status
3884 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02003885 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02003886
tierno2357f4e2020-10-19 16:38:59 +00003887 db_nsr_update["_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)] = nb_scale_op
3888 db_nsr_update["_admin.scaling-group.{}.time".format(admin_scale_index)] = time()
3889
kuuseac3a8882019-10-03 10:48:06 +02003890 # SCALE RO - BEGIN
tierno59d22d22018-09-25 18:10:19 +02003891 if RO_scaling_info:
tierno9ab95942018-10-10 16:44:22 +02003892 scale_process = "RO"
tierno2357f4e2020-10-19 16:38:59 +00003893 if self.ro_config.get("ng"):
3894 await self._scale_ng_ro(logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage)
tierno2357f4e2020-10-19 16:38:59 +00003895 vdu_scaling_info.pop("vdu-create", None)
3896 vdu_scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02003897
tierno9ab95942018-10-10 16:44:22 +02003898 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02003899 if db_nsr_update:
3900 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3901
kuuseac3a8882019-10-03 10:48:06 +02003902 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02003903 # execute primitive service POST-SCALING
3904 step = "Executing post-scale vnf-config-primitive"
3905 if scaling_descriptor.get("scaling-config-action"):
3906 for scaling_config_action in scaling_descriptor["scaling-config-action"]:
kuuseac3a8882019-10-03 10:48:06 +02003907 if (scaling_config_action.get("trigger") == "post-scale-in" and scaling_type == "SCALE_IN") \
3908 or (scaling_config_action.get("trigger") == "post-scale-out" and scaling_type == "SCALE_OUT"):
tierno59d22d22018-09-25 18:10:19 +02003909 vnf_config_primitive = scaling_config_action["vnf-config-primitive-name-ref"]
3910 step = db_nslcmop_update["detailed-status"] = \
3911 "executing post-scale scaling-config-action '{}'".format(vnf_config_primitive)
tiernoda964822019-01-14 15:53:47 +00003912
tierno589befb2019-05-29 07:06:23 +00003913 vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
tiernoda964822019-01-14 15:53:47 +00003914 if db_vnfr.get("additionalParamsForVnf"):
3915 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
3916
tierno59d22d22018-09-25 18:10:19 +02003917 # look for primitive
tierno59d22d22018-09-25 18:10:19 +02003918 for config_primitive in db_vnfd.get("vnf-configuration", {}).get("config-primitive", ()):
3919 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02003920 break
3921 else:
tiernoa278b842020-07-08 15:33:55 +00003922 raise LcmException(
3923 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
3924 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
3925 "config-primitive".format(scaling_group, vnf_config_primitive))
tierno9ab95942018-10-10 16:44:22 +02003926 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02003927 db_nsr_update["config-status"] = "configuring post-scaling"
kuuseac3a8882019-10-03 10:48:06 +02003928 primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params)
tiernod6de1992018-10-11 13:05:52 +02003929
tierno7c4e24c2020-05-13 08:41:35 +00003930 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02003931 op_index = self._check_or_add_scale_suboperation(
3932 db_nslcmop, nslcmop_id, vnf_index, vnf_config_primitive, primitive_params, 'POST-SCALE')
quilesj4cda56b2019-12-05 10:02:20 +00003933 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02003934 # Skip sub-operation
3935 result = 'COMPLETED'
3936 result_detail = 'Done'
3937 self.logger.debug(logging_text +
3938 "vnf_config_primitive={} Skipped sub-operation, result {} {}".
3939 format(vnf_config_primitive, result, result_detail))
3940 else:
quilesj4cda56b2019-12-05 10:02:20 +00003941 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02003942 # New sub-operation: Get index of this sub-operation
3943 op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
3944 self.logger.debug(logging_text + "vnf_config_primitive={} New sub-operation".
3945 format(vnf_config_primitive))
3946 else:
tierno7c4e24c2020-05-13 08:41:35 +00003947 # retry: Get registered params for this existing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003948 op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
3949 vnf_index = op.get('member_vnf_index')
3950 vnf_config_primitive = op.get('primitive')
3951 primitive_params = op.get('primitive_params')
tierno7c4e24c2020-05-13 08:41:35 +00003952 self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry".
kuuseac3a8882019-10-03 10:48:06 +02003953 format(vnf_config_primitive))
tierno588547c2020-07-01 15:30:20 +00003954 # Execute the primitive, either with new (first-time) or registered (reintent) args
tiernoa278b842020-07-08 15:33:55 +00003955 ee_descriptor_id = config_primitive.get("execution-environment-ref")
3956 primitive_name = config_primitive.get("execution-environment-primitive",
3957 vnf_config_primitive)
tierno588547c2020-07-01 15:30:20 +00003958 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"],
3959 member_vnf_index=vnf_index,
3960 vdu_id=None,
tiernoa278b842020-07-08 15:33:55 +00003961 vdu_count_index=None,
3962 ee_descriptor_id=ee_descriptor_id)
kuuseac3a8882019-10-03 10:48:06 +02003963 result, result_detail = await self._ns_execute_primitive(
tiernoa278b842020-07-08 15:33:55 +00003964 ee_id, primitive_name, primitive_params, vca_type)
kuuseac3a8882019-10-03 10:48:06 +02003965 self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format(
3966 vnf_config_primitive, result, result_detail))
3967 # Update operationState = COMPLETED | FAILED
3968 self._update_suboperation_status(
3969 db_nslcmop, op_index, result, result_detail)
3970
tierno59d22d22018-09-25 18:10:19 +02003971 if result == "FAILED":
3972 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02003973 db_nsr_update["config-status"] = old_config_status
3974 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02003975 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02003976
tiernod6de1992018-10-11 13:05:52 +02003977 db_nsr_update["detailed-status"] = "" # "scaled {} {}".format(scaling_group, scaling_type)
ikalyvas02d9e7b2019-05-27 18:16:01 +03003978 db_nsr_update["operational-status"] = "running" if old_operational_status == "failed" \
3979 else old_operational_status
tiernod6de1992018-10-11 13:05:52 +02003980 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02003981 return
tierno2357f4e2020-10-19 16:38:59 +00003982 except (ROclient.ROClientException, DbException, LcmException, NgRoException) as e:
tierno59d22d22018-09-25 18:10:19 +02003983 self.logger.error(logging_text + "Exit Exception {}".format(e))
3984 exc = e
3985 except asyncio.CancelledError:
3986 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(step))
3987 exc = "Operation was cancelled"
3988 except Exception as e:
3989 exc = traceback.format_exc()
3990 self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
3991 finally:
bravof922c4172020-11-24 21:21:43 -03003992 self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE", current_operation_id=None)
tierno59d22d22018-09-25 18:10:19 +02003993 if exc:
tiernoa17d4f42020-04-28 09:59:23 +00003994 db_nslcmop_update["detailed-status"] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
3995 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02003996 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02003997 db_nsr_update["operational-status"] = old_operational_status
3998 db_nsr_update["config-status"] = old_config_status
3999 db_nsr_update["detailed-status"] = ""
4000 if scale_process:
4001 if "VCA" in scale_process:
4002 db_nsr_update["config-status"] = "failed"
4003 if "RO" in scale_process:
4004 db_nsr_update["operational-status"] = "failed"
4005 db_nsr_update["detailed-status"] = "FAILED scaling nslcmop={} {}: {}".format(nslcmop_id, step,
4006 exc)
tiernoa17d4f42020-04-28 09:59:23 +00004007 else:
4008 error_description_nslcmop = None
4009 nslcmop_operation_state = "COMPLETED"
4010 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00004011
bravof922c4172020-11-24 21:21:43 -03004012 self._write_op_status(op_id=nslcmop_id, stage="", error_message=error_description_nslcmop,
4013 operation_state=nslcmop_operation_state, other_update=db_nslcmop_update)
tiernoa17d4f42020-04-28 09:59:23 +00004014 if db_nsr:
bravof922c4172020-11-24 21:21:43 -03004015 self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE",
4016 current_operation_id=None, other_update=db_nsr_update)
tiernoa17d4f42020-04-28 09:59:23 +00004017
tierno59d22d22018-09-25 18:10:19 +02004018 if nslcmop_operation_state:
4019 try:
bravof922c4172020-11-24 21:21:43 -03004020 msg = {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id, "operationState": nslcmop_operation_state}
4021 await self.msg.aiowrite("ns", "scaled", msg, loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02004022 except Exception as e:
4023 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
4024 self.logger.debug(logging_text + "Exit")
4025 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00004026
tierno2357f4e2020-10-19 16:38:59 +00004027 async def _scale_ng_ro(self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage):
4028 nsr_id = db_nslcmop["nsInstanceId"]
4029 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
4030 db_vnfrs = {}
4031
4032 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03004033 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00004034
4035 # for each vnf in ns, read vnfd
4036 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
4037 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
4038 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00004039 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03004040 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00004041 # read from db
4042 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03004043 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00004044 n2vc_key = self.n2vc.get_public_key()
4045 n2vc_key_list = [n2vc_key]
4046 self.scale_vnfr(db_vnfr, vdu_scaling_info.get("vdu-create"), vdu_scaling_info.get("vdu-delete"),
4047 mark_delete=True)
4048 # db_vnfr has been updated, update db_vnfrs to use it
4049 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
4050 await self._instantiate_ng_ro(logging_text, nsr_id, db_nsd, db_nsr, db_nslcmop, db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03004051 db_vnfds, n2vc_key_list, stage=stage, start_deploy=time(),
tierno2357f4e2020-10-19 16:38:59 +00004052 timeout_ns_deploy=self.timeout_ns_deploy)
4053 if vdu_scaling_info.get("vdu-delete"):
4054 self.scale_vnfr(db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False)
4055
tiernob996d942020-07-03 14:52:28 +00004056 async def add_prometheus_metrics(self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip):
4057 if not self.prometheus:
4058 return
4059 # look if exist a file called 'prometheus*.j2' and
4060 artifact_content = self.fs.dir_ls(artifact_path)
4061 job_file = next((f for f in artifact_content if f.startswith("prometheus") and f.endswith(".j2")), None)
4062 if not job_file:
4063 return
4064 with self.fs.file_open((artifact_path, job_file), "r") as f:
4065 job_data = f.read()
4066
4067 # TODO get_service
4068 _, _, service = ee_id.partition(".") # remove prefix "namespace."
4069 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
4070 host_port = "80"
4071 vnfr_id = vnfr_id.replace("-", "")
4072 variables = {
4073 "JOB_NAME": vnfr_id,
4074 "TARGET_IP": target_ip,
4075 "EXPORTER_POD_IP": host_name,
4076 "EXPORTER_POD_PORT": host_port,
4077 }
4078 job_list = self.prometheus.parse_job(job_data, variables)
4079 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
4080 for job in job_list:
4081 if not isinstance(job.get("job_name"), str) or vnfr_id not in job["job_name"]:
4082 job["job_name"] = vnfr_id + "_" + str(randint(1, 10000))
4083 job["nsr_id"] = nsr_id
4084 job_dict = {jl["job_name"]: jl for jl in job_list}
4085 if await self.prometheus.update(job_dict):
4086 return list(job_dict.keys())
David Garciaaae391f2020-11-09 11:12:54 +01004087
4088 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
4089 """
4090 Get VCA Cloud and VCA Cloud Credentials for the VIM account
4091
4092 :param: vim_account_id: VIM Account ID
4093
4094 :return: (cloud_name, cloud_credential)
4095 """
bravof922c4172020-11-24 21:21:43 -03004096 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01004097 return config.get("vca_cloud"), config.get("vca_cloud_credential")
4098
4099 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
4100 """
4101 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
4102
4103 :param: vim_account_id: VIM Account ID
4104
4105 :return: (cloud_name, cloud_credential)
4106 """
bravof922c4172020-11-24 21:21:43 -03004107 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01004108 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")