blob: 5131f9f02e11bc5dedf2f294df8f2a760e2eb916 [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
31from osm_lcm.data_utils.vnfd import get_vnf_configuration, get_vdu_list, get_vdu_profile, \
32 get_ee_sorted_initial_config_primitive_list, get_ee_sorted_terminate_config_primitive_list, \
33 get_kdu_list, get_virtual_link_profiles, get_vdu, get_vdu_configuration, get_kdu_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)
341 vnfd_RO.pop("vnf-configuration", None)
342 vnfd_RO.pop("monitoring-param", None)
343 vnfd_RO.pop("scaling-group-descriptor", None)
344 vnfd_RO.pop("kdu", None)
345 vnfd_RO.pop("k8s-cluster", None)
346 if new_id:
347 vnfd_RO["id"] = new_id
tierno8a518872018-12-21 13:42:14 +0000348
tierno72ef84f2020-10-06 08:22:07 +0000349 # parse cloud-init or cloud-init-file with the provided variables using Jinja2
350 for vdu in get_iterable(vnfd_RO, "vdu"):
351 vdu.pop("cloud-init-file", None)
352 vdu.pop("cloud-init", None)
353 return vnfd_RO
tierno59d22d22018-09-25 18:10:19 +0200354
tierno2357f4e2020-10-19 16:38:59 +0000355 @staticmethod
356 def ip_profile_2_RO(ip_profile):
357 RO_ip_profile = deepcopy(ip_profile)
358 if "dns-server" in RO_ip_profile:
359 if isinstance(RO_ip_profile["dns-server"], list):
360 RO_ip_profile["dns-address"] = []
361 for ds in RO_ip_profile.pop("dns-server"):
362 RO_ip_profile["dns-address"].append(ds['address'])
363 else:
364 RO_ip_profile["dns-address"] = RO_ip_profile.pop("dns-server")
365 if RO_ip_profile.get("ip-version") == "ipv4":
366 RO_ip_profile["ip-version"] = "IPv4"
367 if RO_ip_profile.get("ip-version") == "ipv6":
368 RO_ip_profile["ip-version"] = "IPv6"
369 if "dhcp-params" in RO_ip_profile:
370 RO_ip_profile["dhcp"] = RO_ip_profile.pop("dhcp-params")
371 return RO_ip_profile
372
bravof922c4172020-11-24 21:21:43 -0300373 def _get_ro_vim_id_for_vim_account(self, vim_account):
374 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account})
375 if db_vim["_admin"]["operationalState"] != "ENABLED":
376 raise LcmException("VIM={} is not available. operationalState={}".format(
377 vim_account, db_vim["_admin"]["operationalState"]))
378 RO_vim_id = db_vim["_admin"]["deployed"]["RO"]
379 return RO_vim_id
tierno59d22d22018-09-25 18:10:19 +0200380
bravof922c4172020-11-24 21:21:43 -0300381 def get_ro_wim_id_for_wim_account(self, wim_account):
382 if isinstance(wim_account, str):
383 db_wim = self.db.get_one("wim_accounts", {"_id": wim_account})
384 if db_wim["_admin"]["operationalState"] != "ENABLED":
385 raise LcmException("WIM={} is not available. operationalState={}".format(
386 wim_account, db_wim["_admin"]["operationalState"]))
387 RO_wim_id = db_wim["_admin"]["deployed"]["RO-account"]
388 return RO_wim_id
389 else:
390 return wim_account
tierno59d22d22018-09-25 18:10:19 +0200391
tierno2357f4e2020-10-19 16:38:59 +0000392 def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
tierno27246d82018-09-27 15:59:09 +0200393
tierno2357f4e2020-10-19 16:38:59 +0000394 db_vdu_push_list = []
395 db_update = {"_admin.modified": time()}
396 if vdu_create:
397 for vdu_id, vdu_count in vdu_create.items():
398 vdur = next((vdur for vdur in reversed(db_vnfr["vdur"]) if vdur["vdu-id-ref"] == vdu_id), None)
399 if not vdur:
400 raise LcmException("Error scaling OUT VNFR for {}. There is not any existing vnfr. Scaled to 0?".
401 format(vdu_id))
402
403 for count in range(vdu_count):
404 vdur_copy = deepcopy(vdur)
405 vdur_copy["status"] = "BUILD"
406 vdur_copy["status-detailed"] = None
407 vdur_copy["ip-address"]: None
tierno683eb392020-09-25 12:33:15 +0000408 vdur_copy["_id"] = str(uuid4())
tierno2357f4e2020-10-19 16:38:59 +0000409 vdur_copy["count-index"] += count + 1
410 vdur_copy["id"] = "{}-{}".format(vdur_copy["vdu-id-ref"], vdur_copy["count-index"])
411 vdur_copy.pop("vim_info", None)
412 for iface in vdur_copy["interfaces"]:
413 if iface.get("fixed-ip"):
414 iface["ip-address"] = self.increment_ip_mac(iface["ip-address"], count+1)
415 else:
416 iface.pop("ip-address", None)
417 if iface.get("fixed-mac"):
418 iface["mac-address"] = self.increment_ip_mac(iface["mac-address"], count+1)
419 else:
420 iface.pop("mac-address", None)
421 iface.pop("mgmt_vnf", None) # only first vdu can be managment of vnf
422 db_vdu_push_list.append(vdur_copy)
423 # self.logger.debug("scale out, adding vdu={}".format(vdur_copy))
tierno27246d82018-09-27 15:59:09 +0200424 if vdu_delete:
tierno2357f4e2020-10-19 16:38:59 +0000425 for vdu_id, vdu_count in vdu_delete.items():
426 if mark_delete:
427 indexes_to_delete = [iv[0] for iv in enumerate(db_vnfr["vdur"]) if iv[1]["vdu-id-ref"] == vdu_id]
428 db_update.update({"vdur.{}.status".format(i): "DELETING" for i in indexes_to_delete[-vdu_count:]})
429 else:
430 # it must be deleted one by one because common.db does not allow otherwise
431 vdus_to_delete = [v for v in reversed(db_vnfr["vdur"]) if v["vdu-id-ref"] == vdu_id]
432 for vdu in vdus_to_delete[:vdu_count]:
433 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, None, pull={"vdur": {"_id": vdu["_id"]}})
434 db_push = {"vdur": db_vdu_push_list} if db_vdu_push_list else None
435 self.db.set_one("vnfrs", {"_id": db_vnfr["_id"]}, db_update, push_list=db_push)
436 # modify passed dictionary db_vnfr
437 db_vnfr_ = self.db.get_one("vnfrs", {"_id": db_vnfr["_id"]})
438 db_vnfr["vdur"] = db_vnfr_["vdur"]
tierno27246d82018-09-27 15:59:09 +0200439
tiernof578e552018-11-08 19:07:20 +0100440 def ns_update_nsr(self, ns_update_nsr, db_nsr, nsr_desc_RO):
441 """
442 Updates database nsr with the RO info for the created vld
443 :param ns_update_nsr: dictionary to be filled with the updated info
444 :param db_nsr: content of db_nsr. This is also modified
445 :param nsr_desc_RO: nsr descriptor from RO
446 :return: Nothing, LcmException is raised on errors
447 """
448
449 for vld_index, vld in enumerate(get_iterable(db_nsr, "vld")):
450 for net_RO in get_iterable(nsr_desc_RO, "nets"):
451 if vld["id"] != net_RO.get("ns_net_osm_id"):
452 continue
453 vld["vim-id"] = net_RO.get("vim_net_id")
454 vld["name"] = net_RO.get("vim_name")
455 vld["status"] = net_RO.get("status")
456 vld["status-detailed"] = net_RO.get("error_msg")
457 ns_update_nsr["vld.{}".format(vld_index)] = vld
458 break
459 else:
460 raise LcmException("ns_update_nsr: Not found vld={} at RO info".format(vld["id"]))
461
tiernoe876f672020-02-13 14:34:48 +0000462 def set_vnfr_at_error(self, db_vnfrs, error_text):
463 try:
464 for db_vnfr in db_vnfrs.values():
465 vnfr_update = {"status": "ERROR"}
466 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
467 if "status" not in vdur:
468 vdur["status"] = "ERROR"
469 vnfr_update["vdur.{}.status".format(vdu_index)] = "ERROR"
470 if error_text:
471 vdur["status-detailed"] = str(error_text)
472 vnfr_update["vdur.{}.status-detailed".format(vdu_index)] = "ERROR"
473 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
474 except DbException as e:
475 self.logger.error("Cannot update vnf. {}".format(e))
476
tierno59d22d22018-09-25 18:10:19 +0200477 def ns_update_vnfr(self, db_vnfrs, nsr_desc_RO):
478 """
479 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 +0200480 :param db_vnfrs: dictionary with member-vnf-index: vnfr-content
481 :param nsr_desc_RO: nsr descriptor from RO
482 :return: Nothing, LcmException is raised on errors
tierno59d22d22018-09-25 18:10:19 +0200483 """
484 for vnf_index, db_vnfr in db_vnfrs.items():
485 for vnf_RO in nsr_desc_RO["vnfs"]:
tierno27246d82018-09-27 15:59:09 +0200486 if vnf_RO["member_vnf_index"] != vnf_index:
487 continue
488 vnfr_update = {}
tiernof578e552018-11-08 19:07:20 +0100489 if vnf_RO.get("ip_address"):
tierno1674de82019-04-09 13:03:14 +0000490 db_vnfr["ip-address"] = vnfr_update["ip-address"] = vnf_RO["ip_address"].split(";")[0]
tiernof578e552018-11-08 19:07:20 +0100491 elif not db_vnfr.get("ip-address"):
tierno0ec0c272020-02-19 17:43:01 +0000492 if db_vnfr.get("vdur"): # if not VDUs, there is not ip_address
493 raise LcmExceptionNoMgmtIP("ns member_vnf_index '{}' has no IP address".format(vnf_index))
tierno59d22d22018-09-25 18:10:19 +0200494
tierno27246d82018-09-27 15:59:09 +0200495 for vdu_index, vdur in enumerate(get_iterable(db_vnfr, "vdur")):
496 vdur_RO_count_index = 0
497 if vdur.get("pdu-type"):
498 continue
499 for vdur_RO in get_iterable(vnf_RO, "vms"):
500 if vdur["vdu-id-ref"] != vdur_RO["vdu_osm_id"]:
501 continue
502 if vdur["count-index"] != vdur_RO_count_index:
503 vdur_RO_count_index += 1
504 continue
505 vdur["vim-id"] = vdur_RO.get("vim_vm_id")
tierno1674de82019-04-09 13:03:14 +0000506 if vdur_RO.get("ip_address"):
507 vdur["ip-address"] = vdur_RO["ip_address"].split(";")[0]
tierno274ed572019-04-04 13:33:27 +0000508 else:
509 vdur["ip-address"] = None
tierno27246d82018-09-27 15:59:09 +0200510 vdur["vdu-id-ref"] = vdur_RO.get("vdu_osm_id")
511 vdur["name"] = vdur_RO.get("vim_name")
512 vdur["status"] = vdur_RO.get("status")
513 vdur["status-detailed"] = vdur_RO.get("error_msg")
514 for ifacer in get_iterable(vdur, "interfaces"):
515 for interface_RO in get_iterable(vdur_RO, "interfaces"):
516 if ifacer["name"] == interface_RO.get("internal_name"):
517 ifacer["ip-address"] = interface_RO.get("ip_address")
518 ifacer["mac-address"] = interface_RO.get("mac_address")
519 break
520 else:
521 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vdur={} interface={} "
quilesj7e13aeb2019-10-08 13:34:55 +0200522 "from VIM info"
523 .format(vnf_index, vdur["vdu-id-ref"], ifacer["name"]))
tierno27246d82018-09-27 15:59:09 +0200524 vnfr_update["vdur.{}".format(vdu_index)] = vdur
525 break
526 else:
tierno15b1cf12019-08-29 13:21:40 +0000527 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vdur={} count_index={} from "
528 "VIM info".format(vnf_index, vdur["vdu-id-ref"], vdur["count-index"]))
tiernof578e552018-11-08 19:07:20 +0100529
530 for vld_index, vld in enumerate(get_iterable(db_vnfr, "vld")):
531 for net_RO in get_iterable(nsr_desc_RO, "nets"):
532 if vld["id"] != net_RO.get("vnf_net_osm_id"):
533 continue
534 vld["vim-id"] = net_RO.get("vim_net_id")
535 vld["name"] = net_RO.get("vim_name")
536 vld["status"] = net_RO.get("status")
537 vld["status-detailed"] = net_RO.get("error_msg")
538 vnfr_update["vld.{}".format(vld_index)] = vld
539 break
540 else:
tierno15b1cf12019-08-29 13:21:40 +0000541 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} vld={} from VIM info".format(
tiernof578e552018-11-08 19:07:20 +0100542 vnf_index, vld["id"]))
543
tierno27246d82018-09-27 15:59:09 +0200544 self.update_db_2("vnfrs", db_vnfr["_id"], vnfr_update)
545 break
tierno59d22d22018-09-25 18:10:19 +0200546
547 else:
tierno15b1cf12019-08-29 13:21:40 +0000548 raise LcmException("ns_update_vnfr: Not found member_vnf_index={} from VIM info".format(vnf_index))
tierno59d22d22018-09-25 18:10:19 +0200549
tierno5ee02052019-12-05 19:55:02 +0000550 def _get_ns_config_info(self, nsr_id):
tiernoc3f2a822019-11-05 13:45:04 +0000551 """
552 Generates a mapping between vnf,vdu elements and the N2VC id
tierno5ee02052019-12-05 19:55:02 +0000553 :param nsr_id: id of nsr to get last database _admin.deployed.VCA that contains this list
tiernoc3f2a822019-11-05 13:45:04 +0000554 :return: a dictionary with {osm-config-mapping: {}} where its element contains:
555 "<member-vnf-index>": <N2VC-id> for a vnf configuration, or
556 "<member-vnf-index>.<vdu.id>.<vdu replica(0, 1,..)>": <N2VC-id> for a vdu configuration
557 """
tierno5ee02052019-12-05 19:55:02 +0000558 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
559 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernoc3f2a822019-11-05 13:45:04 +0000560 mapping = {}
561 ns_config_info = {"osm-config-mapping": mapping}
562 for vca in vca_deployed_list:
563 if not vca["member-vnf-index"]:
564 continue
565 if not vca["vdu_id"]:
566 mapping[vca["member-vnf-index"]] = vca["application"]
567 else:
568 mapping["{}.{}.{}".format(vca["member-vnf-index"], vca["vdu_id"], vca["vdu_count_index"])] =\
569 vca["application"]
570 return ns_config_info
571
bravof922c4172020-11-24 21:21:43 -0300572 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 +0000573 n2vc_key_list, stage, start_deploy, timeout_ns_deploy):
tierno2357f4e2020-10-19 16:38:59 +0000574
575 db_vims = {}
576
577 def get_vim_account(vim_account_id):
578 nonlocal db_vims
579 if vim_account_id in db_vims:
580 return db_vims[vim_account_id]
581 db_vim = self.db.get_one("vim_accounts", {"_id": vim_account_id})
582 db_vims[vim_account_id] = db_vim
583 return db_vim
584
585 # modify target_vld info with instantiation parameters
586 def parse_vld_instantiation_params(target_vim, target_vld, vld_params, target_sdn):
587 if vld_params.get("ip-profile"):
588 target_vld["vim_info"][target_vim]["ip_profile"] = vld_params["ip-profile"]
589 if vld_params.get("provider-network"):
590 target_vld["vim_info"][target_vim]["provider_network"] = vld_params["provider-network"]
591 if "sdn-ports" in vld_params["provider-network"] and target_sdn:
592 target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params["provider-network"]["sdn-ports"]
593 if vld_params.get("wimAccountId"):
594 target_wim = "wim:{}".format(vld_params["wimAccountId"])
595 target_vld["vim_info"][target_wim] = {}
596 for param in ("vim-network-name", "vim-network-id"):
597 if vld_params.get(param):
598 if isinstance(vld_params[param], dict):
bravof922c4172020-11-24 21:21:43 -0300599 for vim, vim_net in vld_params[param]:
600 other_target_vim = "vim:" + vim
601 populate_dict(target_vld["vim_info"], (other_target_vim, param.replace("-", "_")), vim_net)
tierno2357f4e2020-10-19 16:38:59 +0000602 else: # isinstance str
603 target_vld["vim_info"][target_vim][param.replace("-", "_")] = vld_params[param]
bravof922c4172020-11-24 21:21:43 -0300604 if vld_params.get("common_id"):
605 target_vld["common_id"] = vld_params.get("common_id")
tierno2357f4e2020-10-19 16:38:59 +0000606
tierno69f0d382020-05-07 13:08:09 +0000607 nslcmop_id = db_nslcmop["_id"]
608 target = {
609 "name": db_nsr["name"],
610 "ns": {"vld": []},
611 "vnf": [],
612 "image": deepcopy(db_nsr["image"]),
613 "flavor": deepcopy(db_nsr["flavor"]),
614 "action_id": nslcmop_id,
tierno2357f4e2020-10-19 16:38:59 +0000615 "cloud_init_content": {},
tierno69f0d382020-05-07 13:08:09 +0000616 }
617 for image in target["image"]:
tierno2357f4e2020-10-19 16:38:59 +0000618 image["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000619 for flavor in target["flavor"]:
tierno2357f4e2020-10-19 16:38:59 +0000620 flavor["vim_info"] = {}
tierno69f0d382020-05-07 13:08:09 +0000621
tierno2357f4e2020-10-19 16:38:59 +0000622 if db_nslcmop.get("lcmOperationType") != "instantiate":
623 # get parameters of instantiation:
624 db_nslcmop_instantiate = self.db.get_list("nslcmops", {"nsInstanceId": db_nslcmop["nsInstanceId"],
625 "lcmOperationType": "instantiate"})[-1]
626 ns_params = db_nslcmop_instantiate.get("operationParams")
627 else:
628 ns_params = db_nslcmop.get("operationParams")
bravof922c4172020-11-24 21:21:43 -0300629 ssh_keys_instantiation = ns_params.get("ssh_keys") or []
630 ssh_keys_all = ssh_keys_instantiation + (n2vc_key_list or [])
tierno69f0d382020-05-07 13:08:09 +0000631
632 cp2target = {}
tierno2357f4e2020-10-19 16:38:59 +0000633 for vld_index, vld in enumerate(db_nsr.get("vld")):
634 target_vim = "vim:{}".format(ns_params["vimAccountId"])
635 target_vld = {
636 "id": vld["id"],
637 "name": vld["name"],
638 "mgmt-network": vld.get("mgmt-network", False),
639 "type": vld.get("type"),
640 "vim_info": {
bravof922c4172020-11-24 21:21:43 -0300641 target_vim: {
642 "vim_network_name": vld.get("vim-network-name"),
643 "vim_account_id": ns_params["vimAccountId"]
644 }
tierno2357f4e2020-10-19 16:38:59 +0000645 }
646 }
647 # check if this network needs SDN assist
tierno2357f4e2020-10-19 16:38:59 +0000648 if vld.get("pci-interfaces"):
bravof922c4172020-11-24 21:21:43 -0300649 db_vim = VimAccountDB.get_vim_account_with_id(target_vld["vim_info"][0]["vim_account_id"])
tierno2357f4e2020-10-19 16:38:59 +0000650 sdnc_id = db_vim["config"].get("sdn-controller")
651 if sdnc_id:
bravof922c4172020-11-24 21:21:43 -0300652 target_vld["vim_info"].append({"sdnc_id": sdnc_id})
tierno2357f4e2020-10-19 16:38:59 +0000653
bravof922c4172020-11-24 21:21:43 -0300654 nsd_vnf_profiles = get_vnf_profiles(nsd)
655 for nsd_vnf_profile in nsd_vnf_profiles:
656 for cp in nsd_vnf_profile["virtual-link-connectivity"]:
657 if cp["virtual-link-profile-id"] == vld["id"]:
658 cp2target["member_vnf:{}.{}".format(
659 cp["constituent-cpd-id"][0]["constituent-base-element-id"],
660 cp["constituent-cpd-id"][0]["constituent-cpd-id"]
661 )] = "nsrs:{}:vld.{}".format(nsr_id, vld_index)
tierno2357f4e2020-10-19 16:38:59 +0000662
663 # check at nsd descriptor, if there is an ip-profile
664 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300665 virtual_link_profiles = get_virtual_link_profiles(nsd)
666
667 for vlp in virtual_link_profiles:
668 ip_profile = find_in_list(nsd["ip-profiles"],
669 lambda profile: profile["name"] == vlp["ip-profile-ref"])
tierno2357f4e2020-10-19 16:38:59 +0000670 vld_params["ip-profile"] = ip_profile["ip-profile-params"]
671 # update vld_params with instantiation params
bravof922c4172020-11-24 21:21:43 -0300672 vld_instantiation_params = find_in_list(get_iterable(ns_params, "vld"),
673 lambda a_vld: a_vld["name"] in (vld["name"], vld["id"]))
tierno2357f4e2020-10-19 16:38:59 +0000674 if vld_instantiation_params:
675 vld_params.update(vld_instantiation_params)
bravof922c4172020-11-24 21:21:43 -0300676 parse_vld_instantiation_params(target_vim, target_vld, vld_params, None)
tierno69f0d382020-05-07 13:08:09 +0000677 target["ns"]["vld"].append(target_vld)
bravof922c4172020-11-24 21:21:43 -0300678
tierno69f0d382020-05-07 13:08:09 +0000679 for vnfr in db_vnfrs.values():
bravof922c4172020-11-24 21:21:43 -0300680 vnfd = find_in_list(db_vnfds, lambda db_vnf: db_vnf["id"] == vnfr["vnfd-ref"])
681 vnf_params = find_in_list(get_iterable(ns_params, "vnf"),
682 lambda a_vnf: a_vnf["member-vnf-index"] == vnfr["member-vnf-index-ref"])
tierno69f0d382020-05-07 13:08:09 +0000683 target_vnf = deepcopy(vnfr)
tierno2357f4e2020-10-19 16:38:59 +0000684 target_vim = "vim:{}".format(vnfr["vim-account-id"])
tierno69f0d382020-05-07 13:08:09 +0000685 for vld in target_vnf.get("vld", ()):
tierno2357f4e2020-10-19 16:38:59 +0000686 # check if connected to a ns.vld, to fill target'
bravof922c4172020-11-24 21:21:43 -0300687 vnf_cp = find_in_list(vnfd.get("int-virtual-link-desc", ()),
688 lambda cpd: cpd.get("id") == vld["id"])
tierno69f0d382020-05-07 13:08:09 +0000689 if vnf_cp:
690 ns_cp = "member_vnf:{}.{}".format(vnfr["member-vnf-index-ref"], vnf_cp["id"])
691 if cp2target.get(ns_cp):
692 vld["target"] = cp2target[ns_cp]
bravof922c4172020-11-24 21:21:43 -0300693
694 vld["vim_info"] = {target_vim: {"vim_network_name": vld.get("vim-network-name")}}
tierno2357f4e2020-10-19 16:38:59 +0000695 # check if this network needs SDN assist
696 target_sdn = None
697 if vld.get("pci-interfaces"):
698 db_vim = get_vim_account(vnfr["vim-account-id"])
699 sdnc_id = db_vim["config"].get("sdn-controller")
700 if sdnc_id:
701 sdn_vld = "vnfrs:{}:vld.{}".format(target_vnf["_id"], vld["id"])
702 target_sdn = "sdn:{}".format(sdnc_id)
703 vld["vim_info"][target_sdn] = {
704 "sdn": True, "target_vim": target_vim, "vlds": [sdn_vld], "type": vld.get("type")}
tierno69f0d382020-05-07 13:08:09 +0000705
tierno2357f4e2020-10-19 16:38:59 +0000706 # check at vnfd descriptor, if there is an ip-profile
707 vld_params = {}
bravof922c4172020-11-24 21:21:43 -0300708 vnfd_vlp = find_in_list(
709 get_virtual_link_profiles(vnfd),
710 lambda a_link_profile: a_link_profile["id"] == vld["id"]
711 )
712 if vnfd_vlp and vnfd_vlp.get("virtual-link-protocol-data") and \
713 vnfd_vlp["virtual-link-protocol-data"].get("l3-protocol-data"):
714 ip_profile_source_data = vnfd_vlp["virtual-link-protocol-data"]["l3-protocol-data"]
715 ip_profile_dest_data = {}
716 if "ip-version" in ip_profile_source_data:
717 ip_profile_dest_data["ip-version"] = ip_profile_source_data["ip-version"]
718 if "cidr" in ip_profile_source_data:
719 ip_profile_dest_data["subnet-address"] = ip_profile_source_data["cidr"]
720 if "gateway-ip" in ip_profile_source_data:
721 ip_profile_dest_data["gateway-address"] = ip_profile_source_data["gateway-ip"]
722 if "dhcp-enabled" in ip_profile_source_data:
723 ip_profile_dest_data["dhcp-params"] = {
724 "enabled": ip_profile_source_data["dhcp-enabled"]
725 }
726
727 vld_params["ip-profile"] = ip_profile_dest_data
tierno2357f4e2020-10-19 16:38:59 +0000728 # update vld_params with instantiation params
729 if vnf_params:
bravof922c4172020-11-24 21:21:43 -0300730 vld_instantiation_params = find_in_list(get_iterable(vnf_params, "internal-vld"),
731 lambda i_vld: i_vld["name"] == vld["id"])
tierno2357f4e2020-10-19 16:38:59 +0000732 if vld_instantiation_params:
733 vld_params.update(vld_instantiation_params)
734 parse_vld_instantiation_params(target_vim, vld, vld_params, target_sdn)
735
736 vdur_list = []
tierno69f0d382020-05-07 13:08:09 +0000737 for vdur in target_vnf.get("vdur", ()):
tierno2357f4e2020-10-19 16:38:59 +0000738 if vdur.get("status") == "DELETING" or vdur.get("pdu-type"):
739 continue # This vdu must not be created
bravof922c4172020-11-24 21:21:43 -0300740 vdur["vim_info"] = {"vim_account_id": vnfr["vim-account-id"]}
tierno69f0d382020-05-07 13:08:09 +0000741
bravof922c4172020-11-24 21:21:43 -0300742 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
743
744 if ssh_keys_all:
745 vdu_configuration = get_vdu_configuration(vnfd, vdur["vdu-id-ref"])
746 vnf_configuration = get_vnf_configuration(vnfd)
747 if vdu_configuration and vdu_configuration.get("config-access") and \
748 vdu_configuration.get("config-access").get("ssh-access"):
749 vdur["ssh-keys"] = ssh_keys_all
750 vdur["ssh-access-required"] = vdu_configuration["config-access"]["ssh-access"]["required"]
751 elif vnf_configuration and vnf_configuration.get("config-access") and \
752 vnf_configuration.get("config-access").get("ssh-access") and \
tierno69f0d382020-05-07 13:08:09 +0000753 any(iface.get("mgmt-vnf") for iface in vdur["interfaces"]):
bravof922c4172020-11-24 21:21:43 -0300754 vdur["ssh-keys"] = ssh_keys_all
755 vdur["ssh-access-required"] = vnf_configuration["config-access"]["ssh-access"]["required"]
756 elif ssh_keys_instantiation and \
757 find_in_list(vdur["interfaces"], lambda iface: iface.get("mgmt-vnf")):
758 vdur["ssh-keys"] = ssh_keys_instantiation
tierno69f0d382020-05-07 13:08:09 +0000759
bravof922c4172020-11-24 21:21:43 -0300760 self.logger.debug("NS > vdur > {}".format(vdur))
761
762 vdud = get_vdu(vnfd, vdur["vdu-id-ref"])
tierno69f0d382020-05-07 13:08:09 +0000763 # cloud-init
764 if vdud.get("cloud-init-file"):
765 vdur["cloud-init"] = "{}:file:{}".format(vnfd["_id"], vdud.get("cloud-init-file"))
tierno2357f4e2020-10-19 16:38:59 +0000766 # read file and put content at target.cloul_init_content. Avoid ng_ro to use shared package system
767 if vdur["cloud-init"] not in target["cloud_init_content"]:
768 base_folder = vnfd["_admin"]["storage"]
769 cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"],
770 vdud.get("cloud-init-file"))
771 with self.fs.file_open(cloud_init_file, "r") as ci_file:
772 target["cloud_init_content"][vdur["cloud-init"]] = ci_file.read()
tierno69f0d382020-05-07 13:08:09 +0000773 elif vdud.get("cloud-init"):
bravof922c4172020-11-24 21:21:43 -0300774 vdur["cloud-init"] = "{}:vdu:{}".format(vnfd["_id"], get_vdu_index(vnfd, vdur["vdu-id-ref"]))
tierno2357f4e2020-10-19 16:38:59 +0000775 # put content at target.cloul_init_content. Avoid ng_ro read vnfd descriptor
776 target["cloud_init_content"][vdur["cloud-init"]] = vdud["cloud-init"]
777 vdur["additionalParams"] = vdur.get("additionalParams") or {}
778 deploy_params_vdu = self._format_additional_params(vdur.get("additionalParams") or {})
bravof922c4172020-11-24 21:21:43 -0300779 deploy_params_vdu["OSM"] = get_osm_params(vnfr, vdur["vdu-id-ref"], vdur["count-index"])
tierno2357f4e2020-10-19 16:38:59 +0000780 vdur["additionalParams"] = deploy_params_vdu
tierno69f0d382020-05-07 13:08:09 +0000781
782 # flavor
783 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
tierno2357f4e2020-10-19 16:38:59 +0000784 if target_vim not in ns_flavor["vim_info"]:
785 ns_flavor["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +0000786 # image
787 ns_image = target["image"][int(vdur["ns-image-id"])]
tierno2357f4e2020-10-19 16:38:59 +0000788 if target_vim not in ns_image["vim_info"]:
789 ns_image["vim_info"][target_vim] = {}
tierno69f0d382020-05-07 13:08:09 +0000790
tierno2357f4e2020-10-19 16:38:59 +0000791 vdur["vim_info"] = {target_vim: {}}
792 # instantiation parameters
793 # if vnf_params:
794 # vdu_instantiation_params = next((v for v in get_iterable(vnf_params, "vdu") if v["id"] ==
795 # vdud["id"]), None)
796 vdur_list.append(vdur)
797 target_vnf["vdur"] = vdur_list
tierno69f0d382020-05-07 13:08:09 +0000798 target["vnf"].append(target_vnf)
799
800 desc = await self.RO.deploy(nsr_id, target)
bravof922c4172020-11-24 21:21:43 -0300801 self.logger.debug("RO return > {}".format(desc))
tierno69f0d382020-05-07 13:08:09 +0000802 action_id = desc["action_id"]
tierno2357f4e2020-10-19 16:38:59 +0000803 await self._wait_ng_ro(nsr_id, action_id, nslcmop_id, start_deploy, timeout_ns_deploy, stage)
tierno69f0d382020-05-07 13:08:09 +0000804
805 # Updating NSR
806 db_nsr_update = {
807 "_admin.deployed.RO.operational-status": "running",
808 "detailed-status": " ".join(stage)
809 }
810 # db_nsr["_admin.deployed.RO.detailed-status"] = "Deployed at VIM"
811 self.update_db_2("nsrs", nsr_id, db_nsr_update)
812 self._write_op_status(nslcmop_id, stage)
813 self.logger.debug(logging_text + "ns deployed at RO. RO_id={}".format(action_id))
814 return
815
tierno2357f4e2020-10-19 16:38:59 +0000816 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 +0000817 detailed_status_old = None
818 db_nsr_update = {}
tierno2357f4e2020-10-19 16:38:59 +0000819 start_time = start_time or time()
tierno69f0d382020-05-07 13:08:09 +0000820 while time() <= start_time + timeout:
821 desc_status = await self.RO.status(nsr_id, action_id)
bravof922c4172020-11-24 21:21:43 -0300822 self.logger.debug("Wait NG RO > {}".format(desc_status))
tierno69f0d382020-05-07 13:08:09 +0000823 if desc_status["status"] == "FAILED":
824 raise NgRoException(desc_status["details"])
825 elif desc_status["status"] == "BUILD":
tierno2357f4e2020-10-19 16:38:59 +0000826 if stage:
827 stage[2] = "VIM: ({})".format(desc_status["details"])
tierno69f0d382020-05-07 13:08:09 +0000828 elif desc_status["status"] == "DONE":
tierno2357f4e2020-10-19 16:38:59 +0000829 if stage:
830 stage[2] = "Deployed at VIM"
tierno69f0d382020-05-07 13:08:09 +0000831 break
832 else:
833 assert False, "ROclient.check_ns_status returns unknown {}".format(desc_status["status"])
tierno2357f4e2020-10-19 16:38:59 +0000834 if stage and nslcmop_id and stage[2] != detailed_status_old:
tierno69f0d382020-05-07 13:08:09 +0000835 detailed_status_old = stage[2]
836 db_nsr_update["detailed-status"] = " ".join(stage)
837 self.update_db_2("nsrs", nsr_id, db_nsr_update)
838 self._write_op_status(nslcmop_id, stage)
bravof922c4172020-11-24 21:21:43 -0300839 await asyncio.sleep(15, loop=self.loop)
tierno69f0d382020-05-07 13:08:09 +0000840 else: # timeout_ns_deploy
841 raise NgRoException("Timeout waiting ns to deploy")
842
843 async def _terminate_ng_ro(self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage):
844 db_nsr_update = {}
845 failed_detail = []
846 action_id = None
847 start_deploy = time()
848 try:
849 target = {
850 "ns": {"vld": []},
851 "vnf": [],
852 "image": [],
853 "flavor": [],
tierno2357f4e2020-10-19 16:38:59 +0000854 "action_id": nslcmop_id
tierno69f0d382020-05-07 13:08:09 +0000855 }
856 desc = await self.RO.deploy(nsr_id, target)
857 action_id = desc["action_id"]
858 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = action_id
859 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETING"
860 self.logger.debug(logging_text + "ns terminate action at RO. action_id={}".format(action_id))
861
862 # wait until done
863 delete_timeout = 20 * 60 # 20 minutes
tierno2357f4e2020-10-19 16:38:59 +0000864 await self._wait_ng_ro(nsr_id, action_id, nslcmop_id, start_deploy, delete_timeout, stage)
tierno69f0d382020-05-07 13:08:09 +0000865
866 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
867 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
868 # delete all nsr
869 await self.RO.delete(nsr_id)
870 except Exception as e:
871 if isinstance(e, NgRoException) and e.http_code == 404: # not found
872 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
873 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
874 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
875 self.logger.debug(logging_text + "RO_action_id={} already deleted".format(action_id))
876 elif isinstance(e, NgRoException) and e.http_code == 409: # conflict
877 failed_detail.append("delete conflict: {}".format(e))
878 self.logger.debug(logging_text + "RO_action_id={} delete conflict: {}".format(action_id, e))
879 else:
880 failed_detail.append("delete error: {}".format(e))
881 self.logger.error(logging_text + "RO_action_id={} delete error: {}".format(action_id, e))
882
883 if failed_detail:
884 stage[2] = "Error deleting from VIM"
885 else:
886 stage[2] = "Deleted from VIM"
887 db_nsr_update["detailed-status"] = " ".join(stage)
888 self.update_db_2("nsrs", nsr_id, db_nsr_update)
889 self._write_op_status(nslcmop_id, stage)
890
891 if failed_detail:
892 raise LcmException("; ".join(failed_detail))
893 return
894
bravof922c4172020-11-24 21:21:43 -0300895 async def instantiate_RO(self, logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs, db_vnfds,
tiernoe876f672020-02-13 14:34:48 +0000896 n2vc_key_list, stage):
tiernoe95ed362020-04-23 08:24:57 +0000897 """
898 Instantiate at RO
899 :param logging_text: preffix text to use at logging
900 :param nsr_id: nsr identity
901 :param nsd: database content of ns descriptor
902 :param db_nsr: database content of ns record
903 :param db_nslcmop: database content of ns operation, in this case, 'instantiate'
904 :param db_vnfrs:
bravof922c4172020-11-24 21:21:43 -0300905 :param db_vnfds: database content of vnfds, indexed by id (not _id). {id: {vnfd_object}, ...}
tiernoe95ed362020-04-23 08:24:57 +0000906 :param n2vc_key_list: ssh-public-key list to be inserted to management vdus via cloud-init
907 :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
908 :return: None or exception
909 """
tiernoe876f672020-02-13 14:34:48 +0000910 try:
tiernoe876f672020-02-13 14:34:48 +0000911 start_deploy = time()
912 ns_params = db_nslcmop.get("operationParams")
913 if ns_params and ns_params.get("timeout_ns_deploy"):
914 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
915 else:
916 timeout_ns_deploy = self.timeout.get("ns_deploy", self.timeout_ns_deploy)
quilesj7e13aeb2019-10-08 13:34:55 +0200917
tiernoe876f672020-02-13 14:34:48 +0000918 # Check for and optionally request placement optimization. Database will be updated if placement activated
919 stage[2] = "Waiting for Placement."
tierno8790a3d2020-04-23 22:49:52 +0000920 if await self._do_placement(logging_text, db_nslcmop, db_vnfrs):
921 # in case of placement change ns_params[vimAcountId) if not present at any vnfrs
922 for vnfr in db_vnfrs.values():
923 if ns_params["vimAccountId"] == vnfr["vim-account-id"]:
924 break
925 else:
926 ns_params["vimAccountId"] == vnfr["vim-account-id"]
quilesj7e13aeb2019-10-08 13:34:55 +0200927
bravof922c4172020-11-24 21:21:43 -0300928 return await self._instantiate_ng_ro(logging_text, nsr_id, nsd, db_nsr, db_nslcmop, db_vnfrs,
929 db_vnfds, n2vc_key_list, stage, start_deploy, timeout_ns_deploy)
tierno2357f4e2020-10-19 16:38:59 +0000930 except Exception as e:
tierno067e04a2020-03-31 12:53:13 +0000931 stage[2] = "ERROR deploying at VIM"
tiernoe876f672020-02-13 14:34:48 +0000932 self.set_vnfr_at_error(db_vnfrs, str(e))
tierno2357f4e2020-10-19 16:38:59 +0000933 self.logger.error("Error deploying at VIM {}".format(e),
934 exc_info=not isinstance(e, (ROclient.ROClientException, LcmException, DbException,
935 NgRoException)))
tiernoe876f672020-02-13 14:34:48 +0000936 raise
quilesj7e13aeb2019-10-08 13:34:55 +0200937
tierno7ecbc342020-09-21 14:05:39 +0000938 async def wait_kdu_up(self, logging_text, nsr_id, vnfr_id, kdu_name):
939 """
940 Wait for kdu to be up, get ip address
941 :param logging_text: prefix use for logging
942 :param nsr_id:
943 :param vnfr_id:
944 :param kdu_name:
945 :return: IP address
946 """
947
948 # self.logger.debug(logging_text + "Starting wait_kdu_up")
949 nb_tries = 0
950
951 while nb_tries < 360:
952 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
tiernoe5d05972020-10-09 12:03:24 +0000953 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 +0000954 if not kdur:
955 raise LcmException("Not found vnfr_id={}, kdu_name={}".format(vnfr_id, kdu_name))
956 if kdur.get("status"):
957 if kdur["status"] in ("READY", "ENABLED"):
958 return kdur.get("ip-address")
959 else:
960 raise LcmException("target KDU={} is in error state".format(kdu_name))
961
962 await asyncio.sleep(10, loop=self.loop)
963 nb_tries += 1
964 raise LcmException("Timeout waiting KDU={} instantiated".format(kdu_name))
965
tiernoa5088192019-11-26 16:12:53 +0000966 async def wait_vm_up_insert_key_ro(self, logging_text, nsr_id, vnfr_id, vdu_id, vdu_index, pub_key=None, user=None):
967 """
968 Wait for ip addres at RO, and optionally, insert public key in virtual machine
969 :param logging_text: prefix use for logging
970 :param nsr_id:
971 :param vnfr_id:
972 :param vdu_id:
973 :param vdu_index:
974 :param pub_key: public ssh key to inject, None to skip
975 :param user: user to apply the public ssh key
976 :return: IP address
977 """
quilesj7e13aeb2019-10-08 13:34:55 +0200978
tierno2357f4e2020-10-19 16:38:59 +0000979 self.logger.debug(logging_text + "Starting wait_vm_up_insert_key_ro")
tiernod8323042019-08-09 11:32:23 +0000980 ro_nsr_id = None
981 ip_address = None
982 nb_tries = 0
983 target_vdu_id = None
quilesj3149f262019-12-03 10:58:10 +0000984 ro_retries = 0
quilesj7e13aeb2019-10-08 13:34:55 +0200985
tiernod8323042019-08-09 11:32:23 +0000986 while True:
quilesj7e13aeb2019-10-08 13:34:55 +0200987
quilesj3149f262019-12-03 10:58:10 +0000988 ro_retries += 1
989 if ro_retries >= 360: # 1 hour
990 raise LcmException("Not found _admin.deployed.RO.nsr_id for nsr_id: {}".format(nsr_id))
991
tiernod8323042019-08-09 11:32:23 +0000992 await asyncio.sleep(10, loop=self.loop)
quilesj7e13aeb2019-10-08 13:34:55 +0200993
994 # get ip address
tiernod8323042019-08-09 11:32:23 +0000995 if not target_vdu_id:
996 db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
quilesj3149f262019-12-03 10:58:10 +0000997
998 if not vdu_id: # for the VNF case
tiernoe876f672020-02-13 14:34:48 +0000999 if db_vnfr.get("status") == "ERROR":
1000 raise LcmException("Cannot inject ssh-key because target VNF is in error state")
tiernod8323042019-08-09 11:32:23 +00001001 ip_address = db_vnfr.get("ip-address")
1002 if not ip_address:
1003 continue
quilesj3149f262019-12-03 10:58:10 +00001004 vdur = next((x for x in get_iterable(db_vnfr, "vdur") if x.get("ip-address") == ip_address), None)
1005 else: # VDU case
1006 vdur = next((x for x in get_iterable(db_vnfr, "vdur")
1007 if x.get("vdu-id-ref") == vdu_id and x.get("count-index") == vdu_index), None)
1008
tierno0e8c3f02020-03-12 17:18:21 +00001009 if not vdur and len(db_vnfr.get("vdur", ())) == 1: # If only one, this should be the target vdu
1010 vdur = db_vnfr["vdur"][0]
quilesj3149f262019-12-03 10:58:10 +00001011 if not vdur:
tierno0e8c3f02020-03-12 17:18:21 +00001012 raise LcmException("Not found vnfr_id={}, vdu_id={}, vdu_index={}".format(vnfr_id, vdu_id,
1013 vdu_index))
tierno2357f4e2020-10-19 16:38:59 +00001014 # New generation RO stores information at "vim_info"
1015 ng_ro_status = None
David Garciaa8bbe672020-11-19 13:06:54 +01001016 target_vim = None
tierno2357f4e2020-10-19 16:38:59 +00001017 if vdur.get("vim_info"):
1018 target_vim = next(t for t in vdur["vim_info"]) # there should be only one key
1019 ng_ro_status = vdur["vim_info"][target_vim].get("vim_status")
1020 if vdur.get("pdu-type") or vdur.get("status") == "ACTIVE" or ng_ro_status == "ACTIVE":
quilesj3149f262019-12-03 10:58:10 +00001021 ip_address = vdur.get("ip-address")
1022 if not ip_address:
1023 continue
1024 target_vdu_id = vdur["vdu-id-ref"]
bravof922c4172020-11-24 21:21:43 -03001025 elif vdur.get("status") == "ERROR" or ng_ro_status == "ERROR":
quilesj3149f262019-12-03 10:58:10 +00001026 raise LcmException("Cannot inject ssh-key because target VM is in error state")
1027
tiernod8323042019-08-09 11:32:23 +00001028 if not target_vdu_id:
1029 continue
tiernod8323042019-08-09 11:32:23 +00001030
quilesj7e13aeb2019-10-08 13:34:55 +02001031 # inject public key into machine
1032 if pub_key and user:
tierno2357f4e2020-10-19 16:38:59 +00001033 self.logger.debug(logging_text + "Inserting RO key")
bravof922c4172020-11-24 21:21:43 -03001034 self.logger.debug("SSH > PubKey > {}".format(pub_key))
tierno0e8c3f02020-03-12 17:18:21 +00001035 if vdur.get("pdu-type"):
1036 self.logger.error(logging_text + "Cannot inject ssh-ky to a PDU")
1037 return ip_address
quilesj7e13aeb2019-10-08 13:34:55 +02001038 try:
1039 ro_vm_id = "{}-{}".format(db_vnfr["member-vnf-index-ref"], target_vdu_id) # TODO add vdu_index
tierno69f0d382020-05-07 13:08:09 +00001040 if self.ng_ro:
bravof922c4172020-11-24 21:21:43 -03001041 target = {"action": {"action": "inject_ssh_key", "key": pub_key, "user": user},
tierno2357f4e2020-10-19 16:38:59 +00001042 "vnf": [{"_id": vnfr_id, "vdur": [{"id": vdur["id"]}]}],
tierno69f0d382020-05-07 13:08:09 +00001043 }
tierno2357f4e2020-10-19 16:38:59 +00001044 desc = await self.RO.deploy(nsr_id, target)
1045 action_id = desc["action_id"]
1046 await self._wait_ng_ro(nsr_id, action_id, timeout=600)
1047 break
tierno69f0d382020-05-07 13:08:09 +00001048 else:
tierno2357f4e2020-10-19 16:38:59 +00001049 # wait until NS is deployed at RO
1050 if not ro_nsr_id:
1051 db_nsrs = self.db.get_one("nsrs", {"_id": nsr_id})
1052 ro_nsr_id = deep_get(db_nsrs, ("_admin", "deployed", "RO", "nsr_id"))
1053 if not ro_nsr_id:
1054 continue
tierno69f0d382020-05-07 13:08:09 +00001055 result_dict = await self.RO.create_action(
1056 item="ns",
1057 item_id_name=ro_nsr_id,
1058 descriptor={"add_public_key": pub_key, "vms": [ro_vm_id], "user": user}
1059 )
1060 # result_dict contains the format {VM-id: {vim_result: 200, description: text}}
1061 if not result_dict or not isinstance(result_dict, dict):
1062 raise LcmException("Unknown response from RO when injecting key")
1063 for result in result_dict.values():
1064 if result.get("vim_result") == 200:
1065 break
1066 else:
1067 raise ROclient.ROClientException("error injecting key: {}".format(
1068 result.get("description")))
1069 break
1070 except NgRoException as e:
1071 raise LcmException("Reaching max tries injecting key. Error: {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02001072 except ROclient.ROClientException as e:
tiernoa5088192019-11-26 16:12:53 +00001073 if not nb_tries:
1074 self.logger.debug(logging_text + "error injecting key: {}. Retrying until {} seconds".
1075 format(e, 20*10))
quilesj7e13aeb2019-10-08 13:34:55 +02001076 nb_tries += 1
tiernoa5088192019-11-26 16:12:53 +00001077 if nb_tries >= 20:
quilesj7e13aeb2019-10-08 13:34:55 +02001078 raise LcmException("Reaching max tries injecting key. Error: {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02001079 else:
quilesj7e13aeb2019-10-08 13:34:55 +02001080 break
1081
1082 return ip_address
1083
tierno5ee02052019-12-05 19:55:02 +00001084 async def _wait_dependent_n2vc(self, nsr_id, vca_deployed_list, vca_index):
1085 """
1086 Wait until dependent VCA deployments have been finished. NS wait for VNFs and VDUs. VNFs for VDUs
1087 """
1088 my_vca = vca_deployed_list[vca_index]
1089 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
quilesj3655ae02019-12-12 16:08:35 +00001090 # vdu or kdu: no dependencies
tierno5ee02052019-12-05 19:55:02 +00001091 return
1092 timeout = 300
1093 while timeout >= 0:
quilesj3655ae02019-12-12 16:08:35 +00001094 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
1095 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
1096 configuration_status_list = db_nsr["configurationStatus"]
1097 for index, vca_deployed in enumerate(configuration_status_list):
tierno5ee02052019-12-05 19:55:02 +00001098 if index == vca_index:
quilesj3655ae02019-12-12 16:08:35 +00001099 # myself
tierno5ee02052019-12-05 19:55:02 +00001100 continue
1101 if not my_vca.get("member-vnf-index") or \
1102 (vca_deployed.get("member-vnf-index") == my_vca.get("member-vnf-index")):
quilesj3655ae02019-12-12 16:08:35 +00001103 internal_status = configuration_status_list[index].get("status")
1104 if internal_status == 'READY':
1105 continue
1106 elif internal_status == 'BROKEN':
tierno5ee02052019-12-05 19:55:02 +00001107 raise LcmException("Configuration aborted because dependent charm/s has failed")
quilesj3655ae02019-12-12 16:08:35 +00001108 else:
1109 break
tierno5ee02052019-12-05 19:55:02 +00001110 else:
quilesj3655ae02019-12-12 16:08:35 +00001111 # no dependencies, return
tierno5ee02052019-12-05 19:55:02 +00001112 return
1113 await asyncio.sleep(10)
1114 timeout -= 1
tierno5ee02052019-12-05 19:55:02 +00001115
1116 raise LcmException("Configuration aborted because dependent charm/s timeout")
1117
tiernoe876f672020-02-13 14:34:48 +00001118 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 +00001119 config_descriptor, deploy_params, base_folder, nslcmop_id, stage, vca_type, vca_name,
1120 ee_config_descriptor):
tiernod8323042019-08-09 11:32:23 +00001121 nsr_id = db_nsr["_id"]
1122 db_update_entry = "_admin.deployed.VCA.{}.".format(vca_index)
tiernoda6fb102019-11-23 00:36:52 +00001123 vca_deployed_list = db_nsr["_admin"]["deployed"]["VCA"]
tiernod8323042019-08-09 11:32:23 +00001124 vca_deployed = db_nsr["_admin"]["deployed"]["VCA"][vca_index]
tiernob996d942020-07-03 14:52:28 +00001125 osm_config = {"osm": {"ns_id": db_nsr["_id"]}}
quilesj7e13aeb2019-10-08 13:34:55 +02001126 db_dict = {
1127 'collection': 'nsrs',
1128 'filter': {'_id': nsr_id},
1129 'path': db_update_entry
1130 }
tiernod8323042019-08-09 11:32:23 +00001131 step = ""
1132 try:
quilesj3655ae02019-12-12 16:08:35 +00001133
1134 element_type = 'NS'
1135 element_under_configuration = nsr_id
1136
tiernod8323042019-08-09 11:32:23 +00001137 vnfr_id = None
1138 if db_vnfr:
1139 vnfr_id = db_vnfr["_id"]
tiernob996d942020-07-03 14:52:28 +00001140 osm_config["osm"]["vnf_id"] = vnfr_id
tiernod8323042019-08-09 11:32:23 +00001141
1142 namespace = "{nsi}.{ns}".format(
1143 nsi=nsi_id if nsi_id else "",
1144 ns=nsr_id)
quilesj3655ae02019-12-12 16:08:35 +00001145
tiernod8323042019-08-09 11:32:23 +00001146 if vnfr_id:
quilesj3655ae02019-12-12 16:08:35 +00001147 element_type = 'VNF'
1148 element_under_configuration = vnfr_id
quilesjb8a35dd2020-01-09 15:10:14 +00001149 namespace += ".{}".format(vnfr_id)
tiernod8323042019-08-09 11:32:23 +00001150 if vdu_id:
1151 namespace += ".{}-{}".format(vdu_id, vdu_index or 0)
quilesj3655ae02019-12-12 16:08:35 +00001152 element_type = 'VDU'
quilesjb8a35dd2020-01-09 15:10:14 +00001153 element_under_configuration = "{}-{}".format(vdu_id, vdu_index or 0)
tiernob996d942020-07-03 14:52:28 +00001154 osm_config["osm"]["vdu_id"] = vdu_id
tierno51183952020-04-03 15:48:18 +00001155 elif kdu_name:
1156 namespace += ".{}".format(kdu_name)
1157 element_type = 'KDU'
1158 element_under_configuration = kdu_name
tiernob996d942020-07-03 14:52:28 +00001159 osm_config["osm"]["kdu_name"] = kdu_name
tiernod8323042019-08-09 11:32:23 +00001160
1161 # Get artifact path
tierno588547c2020-07-01 15:30:20 +00001162 artifact_path = "{}/{}/{}/{}".format(
tiernod8323042019-08-09 11:32:23 +00001163 base_folder["folder"],
1164 base_folder["pkg-dir"],
tierno588547c2020-07-01 15:30:20 +00001165 "charms" if vca_type in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm") else "helm-charts",
1166 vca_name
tiernod8323042019-08-09 11:32:23 +00001167 )
bravof922c4172020-11-24 21:21:43 -03001168
1169 self.logger.debug("Artifact path > {}".format(artifact_path))
1170
tiernoa278b842020-07-08 15:33:55 +00001171 # get initial_config_primitive_list that applies to this element
1172 initial_config_primitive_list = config_descriptor.get('initial-config-primitive')
1173
bravof922c4172020-11-24 21:21:43 -03001174 self.logger.debug("Initial config primitive list > {}".format(initial_config_primitive_list))
1175
tiernoa278b842020-07-08 15:33:55 +00001176 # add config if not present for NS charm
1177 ee_descriptor_id = ee_config_descriptor.get("id")
bravof922c4172020-11-24 21:21:43 -03001178 self.logger.debug("EE Descriptor > {}".format(ee_descriptor_id))
1179 initial_config_primitive_list = get_ee_sorted_initial_config_primitive_list(initial_config_primitive_list,
1180 vca_deployed, ee_descriptor_id)
tiernod8323042019-08-09 11:32:23 +00001181
bravof922c4172020-11-24 21:21:43 -03001182 self.logger.debug("Initial config primitive list #2 > {}".format(initial_config_primitive_list))
tierno588547c2020-07-01 15:30:20 +00001183 # n2vc_redesign STEP 3.1
tierno588547c2020-07-01 15:30:20 +00001184 # find old ee_id if exists
1185 ee_id = vca_deployed.get("ee_id")
tiernod8323042019-08-09 11:32:23 +00001186
David Garciaaae391f2020-11-09 11:12:54 +01001187 vim_account_id = (
1188 deep_get(db_vnfr, ("vim-account-id",)) or
1189 deep_get(deploy_params, ("OSM", "vim_account_id"))
1190 )
1191 vca_cloud, vca_cloud_credential = self.get_vca_cloud_and_credentials(vim_account_id)
1192 vca_k8s_cloud, vca_k8s_cloud_credential = self.get_vca_k8s_cloud_and_credentials(vim_account_id)
tierno588547c2020-07-01 15:30:20 +00001193 # create or register execution environment in VCA
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001194 if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
quilesj7e13aeb2019-10-08 13:34:55 +02001195
tierno588547c2020-07-01 15:30:20 +00001196 self._write_configuration_status(
1197 nsr_id=nsr_id,
1198 vca_index=vca_index,
1199 status='CREATING',
1200 element_under_configuration=element_under_configuration,
1201 element_type=element_type
1202 )
tiernod8323042019-08-09 11:32:23 +00001203
tierno588547c2020-07-01 15:30:20 +00001204 step = "create execution environment"
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001205 self.logger.debug(logging_text + step)
David Garciaaae391f2020-11-09 11:12:54 +01001206
1207 ee_id = None
1208 credentials = None
1209 if vca_type == "k8s_proxy_charm":
1210 ee_id = await self.vca_map[vca_type].install_k8s_proxy_charm(
1211 charm_name=artifact_path[artifact_path.rfind("/") + 1:],
1212 namespace=namespace,
1213 artifact_path=artifact_path,
1214 db_dict=db_dict,
1215 cloud_name=vca_k8s_cloud,
1216 credential_name=vca_k8s_cloud_credential,
1217 )
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001218 elif vca_type == "helm" or vca_type == "helm-v3":
bravof922c4172020-11-24 21:21:43 -03001219 ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
1220 namespace=namespace,
1221 reuse_ee_id=ee_id,
1222 db_dict=db_dict,
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001223 config=osm_config,
1224 artifact_path=artifact_path,
1225 vca_type=vca_type
bravof922c4172020-11-24 21:21:43 -03001226 )
lloretgalleg18cb3cb2020-12-10 14:21:10 +00001227 else:
David Garciaaae391f2020-11-09 11:12:54 +01001228 ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
1229 namespace=namespace,
1230 reuse_ee_id=ee_id,
1231 db_dict=db_dict,
David Garciaaae391f2020-11-09 11:12:54 +01001232 cloud_name=vca_cloud,
1233 credential_name=vca_cloud_credential,
1234 )
quilesj3655ae02019-12-12 16:08:35 +00001235
tierno588547c2020-07-01 15:30:20 +00001236 elif vca_type == "native_charm":
1237 step = "Waiting to VM being up and getting IP address"
1238 self.logger.debug(logging_text + step)
1239 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(logging_text, nsr_id, vnfr_id, vdu_id, vdu_index,
1240 user=None, pub_key=None)
1241 credentials = {"hostname": rw_mgmt_ip}
1242 # get username
1243 username = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user"))
1244 # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were
1245 # merged. Meanwhile let's get username from initial-config-primitive
tiernoa278b842020-07-08 15:33:55 +00001246 if not username and initial_config_primitive_list:
1247 for config_primitive in initial_config_primitive_list:
tierno588547c2020-07-01 15:30:20 +00001248 for param in config_primitive.get("parameter", ()):
1249 if param["name"] == "ssh-username":
1250 username = param["value"]
1251 break
1252 if not username:
tiernoa278b842020-07-08 15:33:55 +00001253 raise LcmException("Cannot determine the username neither with 'initial-config-primitive' nor with "
tierno588547c2020-07-01 15:30:20 +00001254 "'config-access.ssh-access.default-user'")
1255 credentials["username"] = username
1256 # n2vc_redesign STEP 3.2
quilesj3655ae02019-12-12 16:08:35 +00001257
tierno588547c2020-07-01 15:30:20 +00001258 self._write_configuration_status(
1259 nsr_id=nsr_id,
1260 vca_index=vca_index,
1261 status='REGISTERING',
1262 element_under_configuration=element_under_configuration,
1263 element_type=element_type
1264 )
quilesj3655ae02019-12-12 16:08:35 +00001265
tierno588547c2020-07-01 15:30:20 +00001266 step = "register execution environment {}".format(credentials)
1267 self.logger.debug(logging_text + step)
1268 ee_id = await self.vca_map[vca_type].register_execution_environment(
David Garciaaae391f2020-11-09 11:12:54 +01001269 credentials=credentials,
1270 namespace=namespace,
1271 db_dict=db_dict,
1272 cloud_name=vca_cloud,
1273 credential_name=vca_cloud_credential,
1274 )
tierno3bedc9b2019-11-27 15:46:57 +00001275
tierno588547c2020-07-01 15:30:20 +00001276 # for compatibility with MON/POL modules, the need model and application name at database
1277 # TODO ask MON/POL if needed to not assuming anymore the format "model_name.application_name"
1278 ee_id_parts = ee_id.split('.')
1279 db_nsr_update = {db_update_entry + "ee_id": ee_id}
1280 if len(ee_id_parts) >= 2:
1281 model_name = ee_id_parts[0]
1282 application_name = ee_id_parts[1]
1283 db_nsr_update[db_update_entry + "model"] = model_name
1284 db_nsr_update[db_update_entry + "application"] = application_name
tiernod8323042019-08-09 11:32:23 +00001285
1286 # n2vc_redesign STEP 3.3
tiernod8323042019-08-09 11:32:23 +00001287 step = "Install configuration Software"
quilesj3655ae02019-12-12 16:08:35 +00001288
tiernoc231a872020-01-21 08:49:05 +00001289 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001290 nsr_id=nsr_id,
1291 vca_index=vca_index,
1292 status='INSTALLING SW',
1293 element_under_configuration=element_under_configuration,
tierno51183952020-04-03 15:48:18 +00001294 element_type=element_type,
tierno588547c2020-07-01 15:30:20 +00001295 other_update=db_nsr_update
quilesj3655ae02019-12-12 16:08:35 +00001296 )
1297
tierno3bedc9b2019-11-27 15:46:57 +00001298 # TODO check if already done
quilesj7e13aeb2019-10-08 13:34:55 +02001299 self.logger.debug(logging_text + step)
David Garcia18a63322020-04-01 16:14:59 +02001300 config = None
tierno588547c2020-07-01 15:30:20 +00001301 if vca_type == "native_charm":
tiernoa278b842020-07-08 15:33:55 +00001302 config_primitive = next((p for p in initial_config_primitive_list if p["name"] == "config"), None)
1303 if config_primitive:
1304 config = self._map_primitive_params(
1305 config_primitive,
1306 {},
1307 deploy_params
1308 )
tierno588547c2020-07-01 15:30:20 +00001309 num_units = 1
1310 if vca_type == "lxc_proxy_charm":
1311 if element_type == "NS":
1312 num_units = db_nsr.get("config-units") or 1
1313 elif element_type == "VNF":
1314 num_units = db_vnfr.get("config-units") or 1
1315 elif element_type == "VDU":
1316 for v in db_vnfr["vdur"]:
1317 if vdu_id == v["vdu-id-ref"]:
1318 num_units = v.get("config-units") or 1
1319 break
David Garciaaae391f2020-11-09 11:12:54 +01001320 if vca_type != "k8s_proxy_charm":
1321 await self.vca_map[vca_type].install_configuration_sw(
1322 ee_id=ee_id,
1323 artifact_path=artifact_path,
1324 db_dict=db_dict,
1325 config=config,
1326 num_units=num_units,
1327 )
quilesj7e13aeb2019-10-08 13:34:55 +02001328
quilesj63f90042020-01-17 09:53:55 +00001329 # write in db flag of configuration_sw already installed
1330 self.update_db_2("nsrs", nsr_id, {db_update_entry + "config_sw_installed": True})
1331
1332 # add relations for this VCA (wait for other peers related with this VCA)
tierno588547c2020-07-01 15:30:20 +00001333 await self._add_vca_relations(logging_text=logging_text, nsr_id=nsr_id,
1334 vca_index=vca_index, vca_type=vca_type)
quilesj63f90042020-01-17 09:53:55 +00001335
quilesj7e13aeb2019-10-08 13:34:55 +02001336 # if SSH access is required, then get execution environment SSH public
David Garciaa27e20a2020-07-10 13:12:44 +02001337 # if native charm we have waited already to VM be UP
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001338 if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm", "helm-v3"):
tierno3bedc9b2019-11-27 15:46:57 +00001339 pub_key = None
1340 user = None
tierno588547c2020-07-01 15:30:20 +00001341 # self.logger.debug("get ssh key block")
tierno3bedc9b2019-11-27 15:46:57 +00001342 if deep_get(config_descriptor, ("config-access", "ssh-access", "required")):
tierno588547c2020-07-01 15:30:20 +00001343 # self.logger.debug("ssh key needed")
tierno3bedc9b2019-11-27 15:46:57 +00001344 # Needed to inject a ssh key
1345 user = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user"))
1346 step = "Install configuration Software, getting public ssh key"
tierno588547c2020-07-01 15:30:20 +00001347 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 +02001348
tiernoacc90452019-12-10 11:06:54 +00001349 step = "Insert public key into VM user={} ssh_key={}".format(user, pub_key)
tierno3bedc9b2019-11-27 15:46:57 +00001350 else:
tierno588547c2020-07-01 15:30:20 +00001351 # self.logger.debug("no need to get ssh key")
tierno3bedc9b2019-11-27 15:46:57 +00001352 step = "Waiting to VM being up and getting IP address"
1353 self.logger.debug(logging_text + step)
quilesj7e13aeb2019-10-08 13:34:55 +02001354
tierno3bedc9b2019-11-27 15:46:57 +00001355 # n2vc_redesign STEP 5.1
1356 # wait for RO (ip-address) Insert pub_key into VM
tierno5ee02052019-12-05 19:55:02 +00001357 if vnfr_id:
tierno7ecbc342020-09-21 14:05:39 +00001358 if kdu_name:
1359 rw_mgmt_ip = await self.wait_kdu_up(logging_text, nsr_id, vnfr_id, kdu_name)
1360 else:
1361 rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(logging_text, nsr_id, vnfr_id, vdu_id,
1362 vdu_index, user=user, pub_key=pub_key)
tierno5ee02052019-12-05 19:55:02 +00001363 else:
1364 rw_mgmt_ip = None # This is for a NS configuration
tierno3bedc9b2019-11-27 15:46:57 +00001365
1366 self.logger.debug(logging_text + ' VM_ip_address={}'.format(rw_mgmt_ip))
quilesj7e13aeb2019-10-08 13:34:55 +02001367
tiernoa5088192019-11-26 16:12:53 +00001368 # store rw_mgmt_ip in deploy params for later replacement
quilesj7e13aeb2019-10-08 13:34:55 +02001369 deploy_params["rw_mgmt_ip"] = rw_mgmt_ip
tiernod8323042019-08-09 11:32:23 +00001370
1371 # n2vc_redesign STEP 6 Execute initial config primitive
quilesj7e13aeb2019-10-08 13:34:55 +02001372 step = 'execute initial config primitive'
quilesj3655ae02019-12-12 16:08:35 +00001373
1374 # wait for dependent primitives execution (NS -> VNF -> VDU)
tierno5ee02052019-12-05 19:55:02 +00001375 if initial_config_primitive_list:
1376 await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
quilesj3655ae02019-12-12 16:08:35 +00001377
1378 # stage, in function of element type: vdu, kdu, vnf or ns
1379 my_vca = vca_deployed_list[vca_index]
1380 if my_vca.get("vdu_id") or my_vca.get("kdu_name"):
1381 # VDU or KDU
tiernoe876f672020-02-13 14:34:48 +00001382 stage[0] = 'Stage 3/5: running Day-1 primitives for VDU.'
quilesj3655ae02019-12-12 16:08:35 +00001383 elif my_vca.get("member-vnf-index"):
1384 # VNF
tiernoe876f672020-02-13 14:34:48 +00001385 stage[0] = 'Stage 4/5: running Day-1 primitives for VNF.'
quilesj3655ae02019-12-12 16:08:35 +00001386 else:
1387 # NS
tiernoe876f672020-02-13 14:34:48 +00001388 stage[0] = 'Stage 5/5: running Day-1 primitives for NS.'
quilesj3655ae02019-12-12 16:08:35 +00001389
tiernoc231a872020-01-21 08:49:05 +00001390 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001391 nsr_id=nsr_id,
1392 vca_index=vca_index,
1393 status='EXECUTING PRIMITIVE'
1394 )
1395
1396 self._write_op_status(
1397 op_id=nslcmop_id,
1398 stage=stage
1399 )
1400
tiernoe876f672020-02-13 14:34:48 +00001401 check_if_terminated_needed = True
tiernod8323042019-08-09 11:32:23 +00001402 for initial_config_primitive in initial_config_primitive_list:
tiernoda6fb102019-11-23 00:36:52 +00001403 # adding information on the vca_deployed if it is a NS execution environment
1404 if not vca_deployed["member-vnf-index"]:
David Garciad4816682019-12-09 14:57:43 +01001405 deploy_params["ns_config_info"] = json.dumps(self._get_ns_config_info(nsr_id))
tiernod8323042019-08-09 11:32:23 +00001406 # TODO check if already done
1407 primitive_params_ = self._map_primitive_params(initial_config_primitive, {}, deploy_params)
tierno3bedc9b2019-11-27 15:46:57 +00001408
tiernod8323042019-08-09 11:32:23 +00001409 step = "execute primitive '{}' params '{}'".format(initial_config_primitive["name"], primitive_params_)
1410 self.logger.debug(logging_text + step)
tierno588547c2020-07-01 15:30:20 +00001411 await self.vca_map[vca_type].exec_primitive(
quilesj7e13aeb2019-10-08 13:34:55 +02001412 ee_id=ee_id,
1413 primitive_name=initial_config_primitive["name"],
1414 params_dict=primitive_params_,
1415 db_dict=db_dict
1416 )
tiernoe876f672020-02-13 14:34:48 +00001417 # Once some primitive has been exec, check and write at db if it needs to exec terminated primitives
1418 if check_if_terminated_needed:
1419 if config_descriptor.get('terminate-config-primitive'):
1420 self.update_db_2("nsrs", nsr_id, {db_update_entry + "needed_terminate": True})
1421 check_if_terminated_needed = False
quilesj3655ae02019-12-12 16:08:35 +00001422
tiernod8323042019-08-09 11:32:23 +00001423 # TODO register in database that primitive is done
quilesj7e13aeb2019-10-08 13:34:55 +02001424
tiernob996d942020-07-03 14:52:28 +00001425 # STEP 7 Configure metrics
lloretgalleg18ebc3a2020-10-22 09:54:51 +00001426 if vca_type == "helm" or vca_type == "helm-v3":
tiernob996d942020-07-03 14:52:28 +00001427 prometheus_jobs = await self.add_prometheus_metrics(
1428 ee_id=ee_id,
1429 artifact_path=artifact_path,
1430 ee_config_descriptor=ee_config_descriptor,
1431 vnfr_id=vnfr_id,
1432 nsr_id=nsr_id,
1433 target_ip=rw_mgmt_ip,
1434 )
1435 if prometheus_jobs:
1436 self.update_db_2("nsrs", nsr_id, {db_update_entry + "prometheus_jobs": prometheus_jobs})
1437
quilesj7e13aeb2019-10-08 13:34:55 +02001438 step = "instantiated at VCA"
1439 self.logger.debug(logging_text + step)
1440
tiernoc231a872020-01-21 08:49:05 +00001441 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001442 nsr_id=nsr_id,
1443 vca_index=vca_index,
1444 status='READY'
1445 )
1446
tiernod8323042019-08-09 11:32:23 +00001447 except Exception as e: # TODO not use Exception but N2VC exception
quilesj3655ae02019-12-12 16:08:35 +00001448 # self.update_db_2("nsrs", nsr_id, {db_update_entry + "instantiation": "FAILED"})
tiernoe876f672020-02-13 14:34:48 +00001449 if not isinstance(e, (DbException, N2VCException, LcmException, asyncio.CancelledError)):
1450 self.logger.error("Exception while {} : {}".format(step, e), exc_info=True)
tiernoc231a872020-01-21 08:49:05 +00001451 self._write_configuration_status(
quilesj3655ae02019-12-12 16:08:35 +00001452 nsr_id=nsr_id,
1453 vca_index=vca_index,
1454 status='BROKEN'
1455 )
tiernoe876f672020-02-13 14:34:48 +00001456 raise LcmException("{} {}".format(step, e)) from e
tiernod8323042019-08-09 11:32:23 +00001457
quilesj4cda56b2019-12-05 10:02:20 +00001458 def _write_ns_status(self, nsr_id: str, ns_state: str, current_operation: str, current_operation_id: str,
tiernoa2143262020-03-27 16:20:40 +00001459 error_description: str = None, error_detail: str = None, other_update: dict = None):
tiernoe876f672020-02-13 14:34:48 +00001460 """
1461 Update db_nsr fields.
1462 :param nsr_id:
1463 :param ns_state:
1464 :param current_operation:
1465 :param current_operation_id:
1466 :param error_description:
tiernoa2143262020-03-27 16:20:40 +00001467 :param error_detail:
tiernoe876f672020-02-13 14:34:48 +00001468 :param other_update: Other required changes at database if provided, will be cleared
1469 :return:
1470 """
quilesj4cda56b2019-12-05 10:02:20 +00001471 try:
tiernoe876f672020-02-13 14:34:48 +00001472 db_dict = other_update or {}
1473 db_dict["_admin.nslcmop"] = current_operation_id # for backward compatibility
1474 db_dict["_admin.current-operation"] = current_operation_id
1475 db_dict["_admin.operation-type"] = current_operation if current_operation != "IDLE" else None
quilesj4cda56b2019-12-05 10:02:20 +00001476 db_dict["currentOperation"] = current_operation
1477 db_dict["currentOperationID"] = current_operation_id
1478 db_dict["errorDescription"] = error_description
tiernoa2143262020-03-27 16:20:40 +00001479 db_dict["errorDetail"] = error_detail
tiernoe876f672020-02-13 14:34:48 +00001480
1481 if ns_state:
1482 db_dict["nsState"] = ns_state
quilesj4cda56b2019-12-05 10:02:20 +00001483 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001484 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001485 self.logger.warn('Error writing NS status, ns={}: {}'.format(nsr_id, e))
1486
tiernoe876f672020-02-13 14:34:48 +00001487 def _write_op_status(self, op_id: str, stage: list = None, error_message: str = None, queuePosition: int = 0,
1488 operation_state: str = None, other_update: dict = None):
quilesj3655ae02019-12-12 16:08:35 +00001489 try:
tiernoe876f672020-02-13 14:34:48 +00001490 db_dict = other_update or {}
quilesj3655ae02019-12-12 16:08:35 +00001491 db_dict['queuePosition'] = queuePosition
tiernoe876f672020-02-13 14:34:48 +00001492 if isinstance(stage, list):
1493 db_dict['stage'] = stage[0]
1494 db_dict['detailed-status'] = " ".join(stage)
1495 elif stage is not None:
1496 db_dict['stage'] = str(stage)
1497
1498 if error_message is not None:
quilesj3655ae02019-12-12 16:08:35 +00001499 db_dict['errorMessage'] = error_message
tiernoe876f672020-02-13 14:34:48 +00001500 if operation_state is not None:
1501 db_dict['operationState'] = operation_state
1502 db_dict["statusEnteredTime"] = time()
quilesj3655ae02019-12-12 16:08:35 +00001503 self.update_db_2("nslcmops", op_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001504 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001505 self.logger.warn('Error writing OPERATION status for op_id: {} -> {}'.format(op_id, e))
1506
tierno51183952020-04-03 15:48:18 +00001507 def _write_all_config_status(self, db_nsr: dict, status: str):
quilesj3655ae02019-12-12 16:08:35 +00001508 try:
tierno51183952020-04-03 15:48:18 +00001509 nsr_id = db_nsr["_id"]
quilesj3655ae02019-12-12 16:08:35 +00001510 # configurationStatus
1511 config_status = db_nsr.get('configurationStatus')
1512 if config_status:
tierno51183952020-04-03 15:48:18 +00001513 db_nsr_update = {"configurationStatus.{}.status".format(index): status for index, v in
1514 enumerate(config_status) if v}
quilesj3655ae02019-12-12 16:08:35 +00001515 # update status
tierno51183952020-04-03 15:48:18 +00001516 self.update_db_2("nsrs", nsr_id, db_nsr_update)
quilesj3655ae02019-12-12 16:08:35 +00001517
tiernoe876f672020-02-13 14:34:48 +00001518 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001519 self.logger.warn('Error writing all configuration status, ns={}: {}'.format(nsr_id, e))
1520
quilesj63f90042020-01-17 09:53:55 +00001521 def _write_configuration_status(self, nsr_id: str, vca_index: int, status: str = None,
tierno51183952020-04-03 15:48:18 +00001522 element_under_configuration: str = None, element_type: str = None,
1523 other_update: dict = None):
quilesj3655ae02019-12-12 16:08:35 +00001524
1525 # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
1526 # .format(vca_index, status))
1527
1528 try:
1529 db_path = 'configurationStatus.{}.'.format(vca_index)
tierno51183952020-04-03 15:48:18 +00001530 db_dict = other_update or {}
quilesj63f90042020-01-17 09:53:55 +00001531 if status:
1532 db_dict[db_path + 'status'] = status
quilesj3655ae02019-12-12 16:08:35 +00001533 if element_under_configuration:
1534 db_dict[db_path + 'elementUnderConfiguration'] = element_under_configuration
1535 if element_type:
1536 db_dict[db_path + 'elementType'] = element_type
1537 self.update_db_2("nsrs", nsr_id, db_dict)
tiernoe876f672020-02-13 14:34:48 +00001538 except DbException as e:
quilesj3655ae02019-12-12 16:08:35 +00001539 self.logger.warn('Error writing configuration status={}, ns={}, vca_index={}: {}'
1540 .format(status, nsr_id, vca_index, e))
quilesj4cda56b2019-12-05 10:02:20 +00001541
tierno38089af2020-04-16 07:56:58 +00001542 async def _do_placement(self, logging_text, db_nslcmop, db_vnfrs):
1543 """
1544 Check and computes the placement, (vim account where to deploy). If it is decided by an external tool, it
1545 sends the request via kafka and wait until the result is wrote at database (nslcmops _admin.plca).
1546 Database is used because the result can be obtained from a different LCM worker in case of HA.
1547 :param logging_text: contains the prefix for logging, with the ns and nslcmop identifiers
1548 :param db_nslcmop: database content of nslcmop
1549 :param db_vnfrs: database content of vnfrs, indexed by member-vnf-index.
tierno8790a3d2020-04-23 22:49:52 +00001550 :return: True if some modification is done. Modifies database vnfrs and parameter db_vnfr with the
1551 computed 'vim-account-id'
tierno38089af2020-04-16 07:56:58 +00001552 """
tierno8790a3d2020-04-23 22:49:52 +00001553 modified = False
tierno38089af2020-04-16 07:56:58 +00001554 nslcmop_id = db_nslcmop['_id']
magnussonle9198bb2020-01-21 13:00:51 +01001555 placement_engine = deep_get(db_nslcmop, ('operationParams', 'placement-engine'))
1556 if placement_engine == "PLA":
tierno38089af2020-04-16 07:56:58 +00001557 self.logger.debug(logging_text + "Invoke and wait for placement optimization")
1558 await self.msg.aiowrite("pla", "get_placement", {'nslcmopId': nslcmop_id}, loop=self.loop)
magnussonle9198bb2020-01-21 13:00:51 +01001559 db_poll_interval = 5
tierno38089af2020-04-16 07:56:58 +00001560 wait = db_poll_interval * 10
magnussonle9198bb2020-01-21 13:00:51 +01001561 pla_result = None
1562 while not pla_result and wait >= 0:
1563 await asyncio.sleep(db_poll_interval)
1564 wait -= db_poll_interval
tierno38089af2020-04-16 07:56:58 +00001565 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
magnussonle9198bb2020-01-21 13:00:51 +01001566 pla_result = deep_get(db_nslcmop, ('_admin', 'pla'))
1567
1568 if not pla_result:
tierno38089af2020-04-16 07:56:58 +00001569 raise LcmException("Placement timeout for nslcmopId={}".format(nslcmop_id))
magnussonle9198bb2020-01-21 13:00:51 +01001570
1571 for pla_vnf in pla_result['vnf']:
1572 vnfr = db_vnfrs.get(pla_vnf['member-vnf-index'])
1573 if not pla_vnf.get('vimAccountId') or not vnfr:
1574 continue
tierno8790a3d2020-04-23 22:49:52 +00001575 modified = True
magnussonle9198bb2020-01-21 13:00:51 +01001576 self.db.set_one("vnfrs", {"_id": vnfr["_id"]}, {"vim-account-id": pla_vnf['vimAccountId']})
tierno38089af2020-04-16 07:56:58 +00001577 # Modifies db_vnfrs
1578 vnfr["vim-account-id"] = pla_vnf['vimAccountId']
tierno8790a3d2020-04-23 22:49:52 +00001579 return modified
magnussonle9198bb2020-01-21 13:00:51 +01001580
1581 def update_nsrs_with_pla_result(self, params):
1582 try:
1583 nslcmop_id = deep_get(params, ('placement', 'nslcmopId'))
1584 self.update_db_2("nslcmops", nslcmop_id, {"_admin.pla": params.get('placement')})
1585 except Exception as e:
1586 self.logger.warn('Update failed for nslcmop_id={}:{}'.format(nslcmop_id, e))
1587
tierno59d22d22018-09-25 18:10:19 +02001588 async def instantiate(self, nsr_id, nslcmop_id):
quilesj7e13aeb2019-10-08 13:34:55 +02001589 """
1590
1591 :param nsr_id: ns instance to deploy
1592 :param nslcmop_id: operation to run
1593 :return:
1594 """
kuused124bfe2019-06-18 12:09:24 +02001595
1596 # Try to lock HA task here
1597 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
1598 if not task_is_locked_by_me:
quilesj3655ae02019-12-12 16:08:35 +00001599 self.logger.debug('instantiate() task is not locked by me, ns={}'.format(nsr_id))
kuused124bfe2019-06-18 12:09:24 +02001600 return
1601
tierno59d22d22018-09-25 18:10:19 +02001602 logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id)
1603 self.logger.debug(logging_text + "Enter")
quilesj7e13aeb2019-10-08 13:34:55 +02001604
tierno59d22d22018-09-25 18:10:19 +02001605 # get all needed from database
quilesj7e13aeb2019-10-08 13:34:55 +02001606
1607 # database nsrs record
tierno59d22d22018-09-25 18:10:19 +02001608 db_nsr = None
quilesj7e13aeb2019-10-08 13:34:55 +02001609
1610 # database nslcmops record
tierno59d22d22018-09-25 18:10:19 +02001611 db_nslcmop = None
quilesj7e13aeb2019-10-08 13:34:55 +02001612
1613 # update operation on nsrs
tiernoe876f672020-02-13 14:34:48 +00001614 db_nsr_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02001615 # update operation on nslcmops
tierno59d22d22018-09-25 18:10:19 +02001616 db_nslcmop_update = {}
quilesj7e13aeb2019-10-08 13:34:55 +02001617
tierno59d22d22018-09-25 18:10:19 +02001618 nslcmop_operation_state = None
quilesj7e13aeb2019-10-08 13:34:55 +02001619 db_vnfrs = {} # vnf's info indexed by member-index
1620 # n2vc_info = {}
tiernoe876f672020-02-13 14:34:48 +00001621 tasks_dict_info = {} # from task to info text
tierno59d22d22018-09-25 18:10:19 +02001622 exc = None
tiernoe876f672020-02-13 14:34:48 +00001623 error_list = []
1624 stage = ['Stage 1/5: preparation of the environment.', "Waiting for previous operations to terminate.", ""]
1625 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02001626 try:
kuused124bfe2019-06-18 12:09:24 +02001627 # wait for any previous tasks in process
1628 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
1629
tiernob5203912020-08-11 11:20:13 +00001630 stage[1] = "Sync filesystem from database."
tierno21e42212020-07-09 13:51:20 +00001631 self.fs.sync() # TODO, make use of partial sync, only for the needed packages
1632
quilesj7e13aeb2019-10-08 13:34:55 +02001633 # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds)
tiernob5203912020-08-11 11:20:13 +00001634 stage[1] = "Reading from database."
quilesj4cda56b2019-12-05 10:02:20 +00001635 # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id
tiernoe876f672020-02-13 14:34:48 +00001636 db_nsr_update["detailed-status"] = "creating"
1637 db_nsr_update["operational-status"] = "init"
quilesj4cda56b2019-12-05 10:02:20 +00001638 self._write_ns_status(
1639 nsr_id=nsr_id,
1640 ns_state="BUILDING",
1641 current_operation="INSTANTIATING",
tiernoe876f672020-02-13 14:34:48 +00001642 current_operation_id=nslcmop_id,
1643 other_update=db_nsr_update
1644 )
1645 self._write_op_status(
1646 op_id=nslcmop_id,
1647 stage=stage,
1648 queuePosition=0
quilesj4cda56b2019-12-05 10:02:20 +00001649 )
1650
quilesj7e13aeb2019-10-08 13:34:55 +02001651 # read from db: operation
tiernob5203912020-08-11 11:20:13 +00001652 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
tierno59d22d22018-09-25 18:10:19 +02001653 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
tierno744303e2020-01-13 16:46:31 +00001654 ns_params = db_nslcmop.get("operationParams")
1655 if ns_params and ns_params.get("timeout_ns_deploy"):
1656 timeout_ns_deploy = ns_params["timeout_ns_deploy"]
1657 else:
1658 timeout_ns_deploy = self.timeout.get("ns_deploy", self.timeout_ns_deploy)
quilesj7e13aeb2019-10-08 13:34:55 +02001659
1660 # read from db: ns
tiernob5203912020-08-11 11:20:13 +00001661 stage[1] = "Getting nsr={} from db.".format(nsr_id)
tierno59d22d22018-09-25 18:10:19 +02001662 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernob5203912020-08-11 11:20:13 +00001663 stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
tiernod732fb82020-05-21 13:18:23 +00001664 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
1665 db_nsr["nsd"] = nsd
tiernod8323042019-08-09 11:32:23 +00001666 # nsr_name = db_nsr["name"] # TODO short-name??
tierno47e86b52018-10-10 14:05:55 +02001667
quilesj7e13aeb2019-10-08 13:34:55 +02001668 # read from db: vnf's of this ns
tiernob5203912020-08-11 11:20:13 +00001669 stage[1] = "Getting vnfrs from db."
tiernoe876f672020-02-13 14:34:48 +00001670 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02001671 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
tierno27246d82018-09-27 15:59:09 +02001672
quilesj7e13aeb2019-10-08 13:34:55 +02001673 # read from db: vnfd's for every vnf
bravof922c4172020-11-24 21:21:43 -03001674 db_vnfds = [] # every vnfd data
quilesj7e13aeb2019-10-08 13:34:55 +02001675
1676 # for each vnf in ns, read vnfd
tierno27246d82018-09-27 15:59:09 +02001677 for vnfr in db_vnfrs_list:
bravof922c4172020-11-24 21:21:43 -03001678 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
1679 vnfd_id = vnfr["vnfd-id"]
1680 vnfd_ref = vnfr["vnfd-ref"]
lloretgalleg6d488782020-07-22 10:13:46 +00001681
quilesj7e13aeb2019-10-08 13:34:55 +02001682 # if we haven't this vnfd, read it from db
tierno27246d82018-09-27 15:59:09 +02001683 if vnfd_id not in db_vnfds:
quilesj63f90042020-01-17 09:53:55 +00001684 # read from db
tiernob5203912020-08-11 11:20:13 +00001685 stage[1] = "Getting vnfd={} id='{}' from db.".format(vnfd_id, vnfd_ref)
tiernoe876f672020-02-13 14:34:48 +00001686 self.logger.debug(logging_text + stage[1])
tierno27246d82018-09-27 15:59:09 +02001687 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
tierno27246d82018-09-27 15:59:09 +02001688
quilesj7e13aeb2019-10-08 13:34:55 +02001689 # store vnfd
David Garciad41dbd62020-12-10 12:52:52 +01001690 db_vnfds.append(vnfd)
quilesj7e13aeb2019-10-08 13:34:55 +02001691
1692 # Get or generates the _admin.deployed.VCA list
tiernoe4f7e6c2018-11-27 14:55:30 +00001693 vca_deployed_list = None
1694 if db_nsr["_admin"].get("deployed"):
1695 vca_deployed_list = db_nsr["_admin"]["deployed"].get("VCA")
1696 if vca_deployed_list is None:
1697 vca_deployed_list = []
quilesj3655ae02019-12-12 16:08:35 +00001698 configuration_status_list = []
tiernoe4f7e6c2018-11-27 14:55:30 +00001699 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
quilesj3655ae02019-12-12 16:08:35 +00001700 db_nsr_update["configurationStatus"] = configuration_status_list
quilesj7e13aeb2019-10-08 13:34:55 +02001701 # add _admin.deployed.VCA to db_nsr dictionary, value=vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00001702 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00001703 elif isinstance(vca_deployed_list, dict):
1704 # maintain backward compatibility. Change a dict to list at database
1705 vca_deployed_list = list(vca_deployed_list.values())
1706 db_nsr_update["_admin.deployed.VCA"] = vca_deployed_list
tierno98ad6ea2019-05-30 17:16:28 +00001707 populate_dict(db_nsr, ("_admin", "deployed", "VCA"), vca_deployed_list)
tiernoe4f7e6c2018-11-27 14:55:30 +00001708
tierno6cf25f52019-09-12 09:33:40 +00001709 if not isinstance(deep_get(db_nsr, ("_admin", "deployed", "RO", "vnfd")), list):
tiernoa009e552019-01-30 16:45:44 +00001710 populate_dict(db_nsr, ("_admin", "deployed", "RO", "vnfd"), [])
1711 db_nsr_update["_admin.deployed.RO.vnfd"] = []
tierno59d22d22018-09-25 18:10:19 +02001712
tiernobaa51102018-12-14 13:16:18 +00001713 # set state to INSTANTIATED. When instantiated NBI will not delete directly
1714 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
1715 self.update_db_2("nsrs", nsr_id, db_nsr_update)
lloretgalleg6d488782020-07-22 10:13:46 +00001716 self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"})
quilesj3655ae02019-12-12 16:08:35 +00001717
1718 # n2vc_redesign STEP 2 Deploy Network Scenario
tiernoe876f672020-02-13 14:34:48 +00001719 stage[0] = 'Stage 2/5: deployment of KDUs, VMs and execution environments.'
quilesj3655ae02019-12-12 16:08:35 +00001720 self._write_op_status(
1721 op_id=nslcmop_id,
tiernoe876f672020-02-13 14:34:48 +00001722 stage=stage
quilesj3655ae02019-12-12 16:08:35 +00001723 )
1724
tiernob5203912020-08-11 11:20:13 +00001725 stage[1] = "Deploying KDUs."
tiernoe876f672020-02-13 14:34:48 +00001726 # self.logger.debug(logging_text + "Before deploy_kdus")
calvinosanch9f9c6f22019-11-04 13:37:39 +01001727 # Call to deploy_kdus in case exists the "vdu:kdu" param
tiernoe876f672020-02-13 14:34:48 +00001728 await self.deploy_kdus(
1729 logging_text=logging_text,
1730 nsr_id=nsr_id,
1731 nslcmop_id=nslcmop_id,
1732 db_vnfrs=db_vnfrs,
1733 db_vnfds=db_vnfds,
1734 task_instantiation_info=tasks_dict_info,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001735 )
tiernoe876f672020-02-13 14:34:48 +00001736
1737 stage[1] = "Getting VCA public key."
tiernod8323042019-08-09 11:32:23 +00001738 # n2vc_redesign STEP 1 Get VCA public ssh-key
1739 # feature 1429. Add n2vc public key to needed VMs
tierno3bedc9b2019-11-27 15:46:57 +00001740 n2vc_key = self.n2vc.get_public_key()
tiernoa5088192019-11-26 16:12:53 +00001741 n2vc_key_list = [n2vc_key]
1742 if self.vca_config.get("public_key"):
1743 n2vc_key_list.append(self.vca_config["public_key"])
tierno98ad6ea2019-05-30 17:16:28 +00001744
tiernoe876f672020-02-13 14:34:48 +00001745 stage[1] = "Deploying NS at VIM."
tiernod8323042019-08-09 11:32:23 +00001746 task_ro = asyncio.ensure_future(
quilesj7e13aeb2019-10-08 13:34:55 +02001747 self.instantiate_RO(
1748 logging_text=logging_text,
1749 nsr_id=nsr_id,
1750 nsd=nsd,
1751 db_nsr=db_nsr,
1752 db_nslcmop=db_nslcmop,
1753 db_vnfrs=db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03001754 db_vnfds=db_vnfds,
tiernoe876f672020-02-13 14:34:48 +00001755 n2vc_key_list=n2vc_key_list,
1756 stage=stage
tierno98ad6ea2019-05-30 17:16:28 +00001757 )
tiernod8323042019-08-09 11:32:23 +00001758 )
1759 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_RO", task_ro)
tiernoa2143262020-03-27 16:20:40 +00001760 tasks_dict_info[task_ro] = "Deploying at VIM"
tierno98ad6ea2019-05-30 17:16:28 +00001761
tiernod8323042019-08-09 11:32:23 +00001762 # n2vc_redesign STEP 3 to 6 Deploy N2VC
tiernoe876f672020-02-13 14:34:48 +00001763 stage[1] = "Deploying Execution Environments."
1764 self.logger.debug(logging_text + stage[1])
tierno98ad6ea2019-05-30 17:16:28 +00001765
tiernod8323042019-08-09 11:32:23 +00001766 nsi_id = None # TODO put nsi_id when this nsr belongs to a NSI
bravof922c4172020-11-24 21:21:43 -03001767 for vnf_profile in get_vnf_profiles(nsd):
1768 vnfd_id = vnf_profile["vnfd-id"]
1769 vnfd = find_in_list(db_vnfds, lambda a_vnf: a_vnf["id"] == vnfd_id)
1770 member_vnf_index = str(vnf_profile["id"])
tiernod8323042019-08-09 11:32:23 +00001771 db_vnfr = db_vnfrs[member_vnf_index]
1772 base_folder = vnfd["_admin"]["storage"]
1773 vdu_id = None
1774 vdu_index = 0
tierno98ad6ea2019-05-30 17:16:28 +00001775 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001776 kdu_name = None
tierno59d22d22018-09-25 18:10:19 +02001777
tierno8a518872018-12-21 13:42:14 +00001778 # Get additional parameters
bravof922c4172020-11-24 21:21:43 -03001779 deploy_params = {"OSM": get_osm_params(db_vnfr)}
tiernod8323042019-08-09 11:32:23 +00001780 if db_vnfr.get("additionalParamsForVnf"):
bravof922c4172020-11-24 21:21:43 -03001781 deploy_params.update(parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy()))
tierno8a518872018-12-21 13:42:14 +00001782
bravof922c4172020-11-24 21:21:43 -03001783 descriptor_config = get_vnf_configuration(vnfd)
tierno588547c2020-07-01 15:30:20 +00001784 if descriptor_config:
quilesj7e13aeb2019-10-08 13:34:55 +02001785 self._deploy_n2vc(
tiernoa54150d2019-12-05 17:15:10 +00001786 logging_text=logging_text + "member_vnf_index={} ".format(member_vnf_index),
quilesj7e13aeb2019-10-08 13:34:55 +02001787 db_nsr=db_nsr,
1788 db_vnfr=db_vnfr,
1789 nslcmop_id=nslcmop_id,
1790 nsr_id=nsr_id,
1791 nsi_id=nsi_id,
1792 vnfd_id=vnfd_id,
1793 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001794 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001795 member_vnf_index=member_vnf_index,
1796 vdu_index=vdu_index,
1797 vdu_name=vdu_name,
1798 deploy_params=deploy_params,
1799 descriptor_config=descriptor_config,
1800 base_folder=base_folder,
tiernoe876f672020-02-13 14:34:48 +00001801 task_instantiation_info=tasks_dict_info,
1802 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001803 )
tierno59d22d22018-09-25 18:10:19 +02001804
1805 # Deploy charms for each VDU that supports one.
bravof922c4172020-11-24 21:21:43 -03001806 for vdud in get_vdu_list(vnfd):
tiernod8323042019-08-09 11:32:23 +00001807 vdu_id = vdud["id"]
bravof922c4172020-11-24 21:21:43 -03001808 descriptor_config = get_vdu_configuration(vnfd, vdu_id)
1809 vdur = find_in_list(db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id)
1810
tierno626e0152019-11-29 14:16:16 +00001811 if vdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03001812 deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
tierno626e0152019-11-29 14:16:16 +00001813 else:
1814 deploy_params_vdu = deploy_params
bravof922c4172020-11-24 21:21:43 -03001815 deploy_params_vdu["OSM"] = get_osm_params(db_vnfr, vdu_id, vdu_count_index=0)
1816 vdud_count = get_vdu_profile(vnfd, vdu_id).get("max-number-of-instances", 1)
1817
1818 self.logger.debug("VDUD > {}".format(vdud))
1819 self.logger.debug("Descriptor config > {}".format(descriptor_config))
tierno588547c2020-07-01 15:30:20 +00001820 if descriptor_config:
tiernod8323042019-08-09 11:32:23 +00001821 vdu_name = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001822 kdu_name = None
bravof922c4172020-11-24 21:21:43 -03001823 for vdu_index in range(vdud_count):
tiernod8323042019-08-09 11:32:23 +00001824 # TODO vnfr_params["rw_mgmt_ip"] = vdur["ip-address"]
quilesj7e13aeb2019-10-08 13:34:55 +02001825 self._deploy_n2vc(
tiernoa54150d2019-12-05 17:15:10 +00001826 logging_text=logging_text + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
1827 member_vnf_index, vdu_id, vdu_index),
quilesj7e13aeb2019-10-08 13:34:55 +02001828 db_nsr=db_nsr,
1829 db_vnfr=db_vnfr,
1830 nslcmop_id=nslcmop_id,
1831 nsr_id=nsr_id,
1832 nsi_id=nsi_id,
1833 vnfd_id=vnfd_id,
1834 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001835 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001836 member_vnf_index=member_vnf_index,
1837 vdu_index=vdu_index,
1838 vdu_name=vdu_name,
tierno626e0152019-11-29 14:16:16 +00001839 deploy_params=deploy_params_vdu,
quilesj7e13aeb2019-10-08 13:34:55 +02001840 descriptor_config=descriptor_config,
1841 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001842 task_instantiation_info=tasks_dict_info,
1843 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001844 )
bravof922c4172020-11-24 21:21:43 -03001845 for kdud in get_kdu_list(vnfd):
calvinosanch9f9c6f22019-11-04 13:37:39 +01001846 kdu_name = kdud["name"]
lloretgalleg07e53f52020-12-15 10:54:02 +00001847 descriptor_config = kdud.get('kdu-configuration')
tierno588547c2020-07-01 15:30:20 +00001848 if descriptor_config:
calvinosanch9f9c6f22019-11-04 13:37:39 +01001849 vdu_id = None
1850 vdu_index = 0
1851 vdu_name = None
tierno72ef84f2020-10-06 08:22:07 +00001852 kdur = next(x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name)
bravof922c4172020-11-24 21:21:43 -03001853 deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
tierno72ef84f2020-10-06 08:22:07 +00001854 if kdur.get("additionalParams"):
bravof922c4172020-11-24 21:21:43 -03001855 deploy_params_kdu = parse_yaml_strings(kdur["additionalParams"])
tierno59d22d22018-09-25 18:10:19 +02001856
calvinosanch9f9c6f22019-11-04 13:37:39 +01001857 self._deploy_n2vc(
1858 logging_text=logging_text,
1859 db_nsr=db_nsr,
1860 db_vnfr=db_vnfr,
1861 nslcmop_id=nslcmop_id,
1862 nsr_id=nsr_id,
1863 nsi_id=nsi_id,
1864 vnfd_id=vnfd_id,
1865 vdu_id=vdu_id,
1866 kdu_name=kdu_name,
1867 member_vnf_index=member_vnf_index,
1868 vdu_index=vdu_index,
1869 vdu_name=vdu_name,
tierno72ef84f2020-10-06 08:22:07 +00001870 deploy_params=deploy_params_kdu,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001871 descriptor_config=descriptor_config,
1872 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001873 task_instantiation_info=tasks_dict_info,
1874 stage=stage
calvinosanch9f9c6f22019-11-04 13:37:39 +01001875 )
tierno59d22d22018-09-25 18:10:19 +02001876
tierno1b633412019-02-25 16:48:23 +00001877 # Check if this NS has a charm configuration
tiernod8323042019-08-09 11:32:23 +00001878 descriptor_config = nsd.get("ns-configuration")
1879 if descriptor_config and descriptor_config.get("juju"):
1880 vnfd_id = None
1881 db_vnfr = None
1882 member_vnf_index = None
1883 vdu_id = None
calvinosanch9f9c6f22019-11-04 13:37:39 +01001884 kdu_name = None
tiernod8323042019-08-09 11:32:23 +00001885 vdu_index = 0
1886 vdu_name = None
tierno1b633412019-02-25 16:48:23 +00001887
tiernod8323042019-08-09 11:32:23 +00001888 # Get additional parameters
David Garcia40603572020-12-10 20:10:53 +01001889 deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
tiernod8323042019-08-09 11:32:23 +00001890 if db_nsr.get("additionalParamsForNs"):
bravof922c4172020-11-24 21:21:43 -03001891 deploy_params.update(parse_yaml_strings(db_nsr["additionalParamsForNs"].copy()))
tiernod8323042019-08-09 11:32:23 +00001892 base_folder = nsd["_admin"]["storage"]
quilesj7e13aeb2019-10-08 13:34:55 +02001893 self._deploy_n2vc(
1894 logging_text=logging_text,
1895 db_nsr=db_nsr,
1896 db_vnfr=db_vnfr,
1897 nslcmop_id=nslcmop_id,
1898 nsr_id=nsr_id,
1899 nsi_id=nsi_id,
1900 vnfd_id=vnfd_id,
1901 vdu_id=vdu_id,
calvinosanch9f9c6f22019-11-04 13:37:39 +01001902 kdu_name=kdu_name,
quilesj7e13aeb2019-10-08 13:34:55 +02001903 member_vnf_index=member_vnf_index,
1904 vdu_index=vdu_index,
1905 vdu_name=vdu_name,
1906 deploy_params=deploy_params,
1907 descriptor_config=descriptor_config,
1908 base_folder=base_folder,
tierno8e2fae72020-04-01 15:21:15 +00001909 task_instantiation_info=tasks_dict_info,
1910 stage=stage
quilesj7e13aeb2019-10-08 13:34:55 +02001911 )
tierno1b633412019-02-25 16:48:23 +00001912
tiernoe876f672020-02-13 14:34:48 +00001913 # rest of staff will be done at finally
tierno1b633412019-02-25 16:48:23 +00001914
tiernoe876f672020-02-13 14:34:48 +00001915 except (ROclient.ROClientException, DbException, LcmException, N2VCException) as e:
1916 self.logger.error(logging_text + "Exit Exception while '{}': {}".format(stage[1], e))
tierno59d22d22018-09-25 18:10:19 +02001917 exc = e
1918 except asyncio.CancelledError:
tiernoe876f672020-02-13 14:34:48 +00001919 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(stage[1]))
tierno59d22d22018-09-25 18:10:19 +02001920 exc = "Operation was cancelled"
1921 except Exception as e:
1922 exc = traceback.format_exc()
tiernoe876f672020-02-13 14:34:48 +00001923 self.logger.critical(logging_text + "Exit Exception while '{}': {}".format(stage[1], e), exc_info=True)
tierno59d22d22018-09-25 18:10:19 +02001924 finally:
1925 if exc:
tiernoe876f672020-02-13 14:34:48 +00001926 error_list.append(str(exc))
tiernobaa51102018-12-14 13:16:18 +00001927 try:
tiernoe876f672020-02-13 14:34:48 +00001928 # wait for pending tasks
1929 if tasks_dict_info:
1930 stage[1] = "Waiting for instantiate pending tasks."
1931 self.logger.debug(logging_text + stage[1])
1932 error_list += await self._wait_for_tasks(logging_text, tasks_dict_info, timeout_ns_deploy,
1933 stage, nslcmop_id, nsr_id=nsr_id)
1934 stage[1] = stage[2] = ""
1935 except asyncio.CancelledError:
1936 error_list.append("Cancelled")
1937 # TODO cancel all tasks
1938 except Exception as exc:
1939 error_list.append(str(exc))
quilesj4cda56b2019-12-05 10:02:20 +00001940
tiernoe876f672020-02-13 14:34:48 +00001941 # update operation-status
1942 db_nsr_update["operational-status"] = "running"
1943 # let's begin with VCA 'configured' status (later we can change it)
1944 db_nsr_update["config-status"] = "configured"
1945 for task, task_name in tasks_dict_info.items():
1946 if not task.done() or task.cancelled() or task.exception():
1947 if task_name.startswith(self.task_name_deploy_vca):
1948 # A N2VC task is pending
1949 db_nsr_update["config-status"] = "failed"
quilesj4cda56b2019-12-05 10:02:20 +00001950 else:
tiernoe876f672020-02-13 14:34:48 +00001951 # RO or KDU task is pending
1952 db_nsr_update["operational-status"] = "failed"
quilesj3655ae02019-12-12 16:08:35 +00001953
tiernoe876f672020-02-13 14:34:48 +00001954 # update status at database
1955 if error_list:
tiernoa2143262020-03-27 16:20:40 +00001956 error_detail = ". ".join(error_list)
tiernoe876f672020-02-13 14:34:48 +00001957 self.logger.error(logging_text + error_detail)
tiernob5203912020-08-11 11:20:13 +00001958 error_description_nslcmop = '{} Detail: {}'.format(stage[0], error_detail)
1959 error_description_nsr = 'Operation: INSTANTIATING.{}, {}'.format(nslcmop_id, stage[0])
quilesj3655ae02019-12-12 16:08:35 +00001960
tiernoa2143262020-03-27 16:20:40 +00001961 db_nsr_update["detailed-status"] = error_description_nsr + " Detail: " + error_detail
tiernoe876f672020-02-13 14:34:48 +00001962 db_nslcmop_update["detailed-status"] = error_detail
1963 nslcmop_operation_state = "FAILED"
1964 ns_state = "BROKEN"
1965 else:
tiernoa2143262020-03-27 16:20:40 +00001966 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00001967 error_description_nsr = error_description_nslcmop = None
1968 ns_state = "READY"
1969 db_nsr_update["detailed-status"] = "Done"
1970 db_nslcmop_update["detailed-status"] = "Done"
1971 nslcmop_operation_state = "COMPLETED"
quilesj4cda56b2019-12-05 10:02:20 +00001972
tiernoe876f672020-02-13 14:34:48 +00001973 if db_nsr:
1974 self._write_ns_status(
1975 nsr_id=nsr_id,
1976 ns_state=ns_state,
1977 current_operation="IDLE",
1978 current_operation_id=None,
1979 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00001980 error_detail=error_detail,
tiernoe876f672020-02-13 14:34:48 +00001981 other_update=db_nsr_update
1982 )
tiernoa17d4f42020-04-28 09:59:23 +00001983 self._write_op_status(
1984 op_id=nslcmop_id,
1985 stage="",
1986 error_message=error_description_nslcmop,
1987 operation_state=nslcmop_operation_state,
1988 other_update=db_nslcmop_update,
1989 )
quilesj3655ae02019-12-12 16:08:35 +00001990
tierno59d22d22018-09-25 18:10:19 +02001991 if nslcmop_operation_state:
1992 try:
1993 await self.msg.aiowrite("ns", "instantiated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tierno8a518872018-12-21 13:42:14 +00001994 "operationState": nslcmop_operation_state},
1995 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02001996 except Exception as e:
1997 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
1998
1999 self.logger.debug(logging_text + "Exit")
2000 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
2001
tierno588547c2020-07-01 15:30:20 +00002002 async def _add_vca_relations(self, logging_text, nsr_id, vca_index: int,
2003 timeout: int = 3600, vca_type: str = None) -> bool:
quilesj63f90042020-01-17 09:53:55 +00002004
2005 # steps:
2006 # 1. find all relations for this VCA
2007 # 2. wait for other peers related
2008 # 3. add relations
2009
2010 try:
tierno588547c2020-07-01 15:30:20 +00002011 vca_type = vca_type or "lxc_proxy_charm"
quilesj63f90042020-01-17 09:53:55 +00002012
2013 # STEP 1: find all relations for this VCA
2014
2015 # read nsr record
2016 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
David Garcia171f3542020-05-21 16:41:07 +02002017 nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
quilesj63f90042020-01-17 09:53:55 +00002018
2019 # this VCA data
2020 my_vca = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))[vca_index]
2021
2022 # read all ns-configuration relations
2023 ns_relations = list()
David Garcia171f3542020-05-21 16:41:07 +02002024 db_ns_relations = deep_get(nsd, ('ns-configuration', 'relation'))
quilesj63f90042020-01-17 09:53:55 +00002025 if db_ns_relations:
2026 for r in db_ns_relations:
2027 # check if this VCA is in the relation
2028 if my_vca.get('member-vnf-index') in\
2029 (r.get('entities')[0].get('id'), r.get('entities')[1].get('id')):
2030 ns_relations.append(r)
2031
2032 # read all vnf-configuration relations
2033 vnf_relations = list()
2034 db_vnfd_list = db_nsr.get('vnfd-id')
2035 if db_vnfd_list:
2036 for vnfd in db_vnfd_list:
2037 db_vnfd = self.db.get_one("vnfds", {"_id": vnfd})
2038 db_vnf_relations = deep_get(db_vnfd, ('vnf-configuration', 'relation'))
2039 if db_vnf_relations:
2040 for r in db_vnf_relations:
2041 # check if this VCA is in the relation
2042 if my_vca.get('vdu_id') in (r.get('entities')[0].get('id'), r.get('entities')[1].get('id')):
2043 vnf_relations.append(r)
2044
2045 # if no relations, terminate
2046 if not ns_relations and not vnf_relations:
2047 self.logger.debug(logging_text + ' No relations')
2048 return True
2049
2050 self.logger.debug(logging_text + ' adding relations\n {}\n {}'.format(ns_relations, vnf_relations))
2051
2052 # add all relations
2053 start = time()
2054 while True:
2055 # check timeout
2056 now = time()
2057 if now - start >= timeout:
2058 self.logger.error(logging_text + ' : timeout adding relations')
2059 return False
2060
2061 # reload nsr from database (we need to update record: _admin.deloyed.VCA)
2062 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
2063
2064 # for each defined NS relation, find the VCA's related
tierno364c4572020-09-14 12:11:32 +00002065 for r in ns_relations.copy():
quilesj63f90042020-01-17 09:53:55 +00002066 from_vca_ee_id = None
2067 to_vca_ee_id = None
2068 from_vca_endpoint = None
2069 to_vca_endpoint = None
2070 vca_list = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))
2071 for vca in vca_list:
2072 if vca.get('member-vnf-index') == r.get('entities')[0].get('id') \
2073 and vca.get('config_sw_installed'):
2074 from_vca_ee_id = vca.get('ee_id')
2075 from_vca_endpoint = r.get('entities')[0].get('endpoint')
2076 if vca.get('member-vnf-index') == r.get('entities')[1].get('id') \
2077 and vca.get('config_sw_installed'):
2078 to_vca_ee_id = vca.get('ee_id')
2079 to_vca_endpoint = r.get('entities')[1].get('endpoint')
2080 if from_vca_ee_id and to_vca_ee_id:
2081 # add relation
tierno588547c2020-07-01 15:30:20 +00002082 await self.vca_map[vca_type].add_relation(
quilesj63f90042020-01-17 09:53:55 +00002083 ee_id_1=from_vca_ee_id,
2084 ee_id_2=to_vca_ee_id,
2085 endpoint_1=from_vca_endpoint,
2086 endpoint_2=to_vca_endpoint)
2087 # remove entry from relations list
2088 ns_relations.remove(r)
2089 else:
2090 # check failed peers
2091 try:
2092 vca_status_list = db_nsr.get('configurationStatus')
2093 if vca_status_list:
2094 for i in range(len(vca_list)):
2095 vca = vca_list[i]
2096 vca_status = vca_status_list[i]
2097 if vca.get('member-vnf-index') == r.get('entities')[0].get('id'):
2098 if vca_status.get('status') == 'BROKEN':
2099 # peer broken: remove relation from list
2100 ns_relations.remove(r)
2101 if vca.get('member-vnf-index') == r.get('entities')[1].get('id'):
2102 if vca_status.get('status') == 'BROKEN':
2103 # peer broken: remove relation from list
2104 ns_relations.remove(r)
2105 except Exception:
2106 # ignore
2107 pass
2108
2109 # for each defined VNF relation, find the VCA's related
tierno364c4572020-09-14 12:11:32 +00002110 for r in vnf_relations.copy():
quilesj63f90042020-01-17 09:53:55 +00002111 from_vca_ee_id = None
2112 to_vca_ee_id = None
2113 from_vca_endpoint = None
2114 to_vca_endpoint = None
2115 vca_list = deep_get(db_nsr, ('_admin', 'deployed', 'VCA'))
2116 for vca in vca_list:
David Garcia97be6832020-09-09 15:40:44 +02002117 key_to_check = "vdu_id"
2118 if vca.get("vdu_id") is None:
2119 key_to_check = "vnfd_id"
2120 if vca.get(key_to_check) == r.get('entities')[0].get('id') and vca.get('config_sw_installed'):
quilesj63f90042020-01-17 09:53:55 +00002121 from_vca_ee_id = vca.get('ee_id')
2122 from_vca_endpoint = r.get('entities')[0].get('endpoint')
David Garcia97be6832020-09-09 15:40:44 +02002123 if vca.get(key_to_check) == r.get('entities')[1].get('id') and vca.get('config_sw_installed'):
quilesj63f90042020-01-17 09:53:55 +00002124 to_vca_ee_id = vca.get('ee_id')
2125 to_vca_endpoint = r.get('entities')[1].get('endpoint')
2126 if from_vca_ee_id and to_vca_ee_id:
2127 # add relation
tierno588547c2020-07-01 15:30:20 +00002128 await self.vca_map[vca_type].add_relation(
quilesj63f90042020-01-17 09:53:55 +00002129 ee_id_1=from_vca_ee_id,
2130 ee_id_2=to_vca_ee_id,
2131 endpoint_1=from_vca_endpoint,
2132 endpoint_2=to_vca_endpoint)
2133 # remove entry from relations list
2134 vnf_relations.remove(r)
2135 else:
2136 # check failed peers
2137 try:
2138 vca_status_list = db_nsr.get('configurationStatus')
2139 if vca_status_list:
2140 for i in range(len(vca_list)):
2141 vca = vca_list[i]
2142 vca_status = vca_status_list[i]
2143 if vca.get('vdu_id') == r.get('entities')[0].get('id'):
2144 if vca_status.get('status') == 'BROKEN':
2145 # peer broken: remove relation from list
David Garcia092afbd2020-08-25 13:17:25 +02002146 vnf_relations.remove(r)
quilesj63f90042020-01-17 09:53:55 +00002147 if vca.get('vdu_id') == r.get('entities')[1].get('id'):
2148 if vca_status.get('status') == 'BROKEN':
2149 # peer broken: remove relation from list
David Garcia092afbd2020-08-25 13:17:25 +02002150 vnf_relations.remove(r)
quilesj63f90042020-01-17 09:53:55 +00002151 except Exception:
2152 # ignore
2153 pass
2154
2155 # wait for next try
2156 await asyncio.sleep(5.0)
2157
2158 if not ns_relations and not vnf_relations:
2159 self.logger.debug('Relations added')
2160 break
2161
2162 return True
2163
2164 except Exception as e:
2165 self.logger.warn(logging_text + ' ERROR adding relations: {}'.format(e))
2166 return False
2167
tierno7ecbc342020-09-21 14:05:39 +00002168 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 +00002169 vnfd: dict, k8s_instance_info: dict, k8params: dict = None, timeout: int = 600):
2170
tiernob9018152020-04-16 14:18:24 +00002171 try:
lloretgalleg7c121132020-07-08 07:53:22 +00002172 k8sclustertype = k8s_instance_info["k8scluster-type"]
2173 # Instantiate kdu
2174 db_dict_install = {"collection": "nsrs",
2175 "filter": {"_id": nsr_id},
2176 "path": nsr_db_path}
2177
2178 kdu_instance = await self.k8scluster_map[k8sclustertype].install(
2179 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2180 kdu_model=k8s_instance_info["kdu-model"],
2181 atomic=True,
2182 params=k8params,
2183 db_dict=db_dict_install,
2184 timeout=timeout,
2185 kdu_name=k8s_instance_info["kdu-name"],
2186 namespace=k8s_instance_info["namespace"])
2187 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
2188
2189 # Obtain services to obtain management service ip
2190 services = await self.k8scluster_map[k8sclustertype].get_services(
2191 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2192 kdu_instance=kdu_instance,
2193 namespace=k8s_instance_info["namespace"])
2194
2195 # Obtain management service info (if exists)
tierno7ecbc342020-09-21 14:05:39 +00002196 vnfr_update_dict = {}
lloretgalleg7c121132020-07-08 07:53:22 +00002197 if services:
tierno7ecbc342020-09-21 14:05:39 +00002198 vnfr_update_dict["kdur.{}.services".format(kdu_index)] = services
lloretgalleg7c121132020-07-08 07:53:22 +00002199 mgmt_services = [service for service in kdud.get("service", []) if service.get("mgmt-service")]
2200 for mgmt_service in mgmt_services:
2201 for service in services:
2202 if service["name"].startswith(mgmt_service["name"]):
2203 # Mgmt service found, Obtain service ip
2204 ip = service.get("external_ip", service.get("cluster_ip"))
2205 if isinstance(ip, list) and len(ip) == 1:
2206 ip = ip[0]
2207
2208 vnfr_update_dict["kdur.{}.ip-address".format(kdu_index)] = ip
2209
2210 # Check if must update also mgmt ip at the vnf
2211 service_external_cp = mgmt_service.get("external-connection-point-ref")
2212 if service_external_cp:
2213 if deep_get(vnfd, ("mgmt-interface", "cp")) == service_external_cp:
2214 vnfr_update_dict["ip-address"] = ip
2215
2216 break
2217 else:
2218 self.logger.warn("Mgmt service name: {} not found".format(mgmt_service["name"]))
2219
tierno7ecbc342020-09-21 14:05:39 +00002220 vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
2221 self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
lloretgalleg7c121132020-07-08 07:53:22 +00002222
Dominik Fleischmannc1975dd2020-08-19 12:17:51 +02002223 kdu_config = kdud.get("kdu-configuration")
2224 if kdu_config and kdu_config.get("initial-config-primitive") and kdu_config.get("juju") is None:
2225 initial_config_primitive_list = kdu_config.get("initial-config-primitive")
2226 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
2227
2228 for initial_config_primitive in initial_config_primitive_list:
2229 primitive_params_ = self._map_primitive_params(initial_config_primitive, {}, {})
2230
2231 await asyncio.wait_for(
2232 self.k8scluster_map[k8sclustertype].exec_primitive(
2233 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
2234 kdu_instance=kdu_instance,
2235 primitive_name=initial_config_primitive["name"],
2236 params=primitive_params_, db_dict={}),
2237 timeout=timeout)
2238
tiernob9018152020-04-16 14:18:24 +00002239 except Exception as e:
lloretgalleg7c121132020-07-08 07:53:22 +00002240 # Prepare update db with error and raise exception
tiernob9018152020-04-16 14:18:24 +00002241 try:
lloretgalleg7c121132020-07-08 07:53:22 +00002242 self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)})
tierno7ecbc342020-09-21 14:05:39 +00002243 self.update_db_2("vnfrs", vnfr_data.get("_id"), {"kdur.{}.status".format(kdu_index): "ERROR"})
tiernob9018152020-04-16 14:18:24 +00002244 except Exception:
lloretgalleg7c121132020-07-08 07:53:22 +00002245 # ignore to keep original exception
tiernob9018152020-04-16 14:18:24 +00002246 pass
lloretgalleg7c121132020-07-08 07:53:22 +00002247 # reraise original error
2248 raise
2249
2250 return kdu_instance
tiernob9018152020-04-16 14:18:24 +00002251
tiernoe876f672020-02-13 14:34:48 +00002252 async def deploy_kdus(self, logging_text, nsr_id, nslcmop_id, db_vnfrs, db_vnfds, task_instantiation_info):
calvinosanch9f9c6f22019-11-04 13:37:39 +01002253 # Launch kdus if present in the descriptor
tierno626e0152019-11-29 14:16:16 +00002254
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002255 k8scluster_id_2_uuic = {"helm-chart-v3": {}, "helm-chart": {}, "juju-bundle": {}}
tierno626e0152019-11-29 14:16:16 +00002256
tierno16f4a4e2020-07-20 09:05:51 +00002257 async def _get_cluster_id(cluster_id, cluster_type):
tierno626e0152019-11-29 14:16:16 +00002258 nonlocal k8scluster_id_2_uuic
2259 if cluster_id in k8scluster_id_2_uuic[cluster_type]:
2260 return k8scluster_id_2_uuic[cluster_type][cluster_id]
2261
tierno16f4a4e2020-07-20 09:05:51 +00002262 # check if K8scluster is creating and wait look if previous tasks in process
2263 task_name, task_dependency = self.lcm_tasks.lookfor_related("k8scluster", cluster_id)
2264 if task_dependency:
2265 text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(task_name, cluster_id)
2266 self.logger.debug(logging_text + text)
2267 await asyncio.wait(task_dependency, timeout=3600)
2268
tierno626e0152019-11-29 14:16:16 +00002269 db_k8scluster = self.db.get_one("k8sclusters", {"_id": cluster_id}, fail_on_empty=False)
2270 if not db_k8scluster:
2271 raise LcmException("K8s cluster {} cannot be found".format(cluster_id))
tierno16f4a4e2020-07-20 09:05:51 +00002272
tierno626e0152019-11-29 14:16:16 +00002273 k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id"))
2274 if not k8s_id:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002275 if cluster_type == "helm-chart-v3":
2276 try:
2277 # backward compatibility for existing clusters that have not been initialized for helm v3
2278 k8s_credentials = yaml.safe_dump(db_k8scluster.get("credentials"))
2279 k8s_id, uninstall_sw = await self.k8sclusterhelm3.init_env(k8s_credentials,
2280 reuse_cluster_uuid=cluster_id)
2281 db_k8scluster_update = {}
2282 db_k8scluster_update["_admin.helm-chart-v3.error_msg"] = None
2283 db_k8scluster_update["_admin.helm-chart-v3.id"] = k8s_id
2284 db_k8scluster_update["_admin.helm-chart-v3.created"] = uninstall_sw
2285 db_k8scluster_update["_admin.helm-chart-v3.operationalState"] = "ENABLED"
2286 self.update_db_2("k8sclusters", cluster_id, db_k8scluster_update)
2287 except Exception as e:
2288 self.logger.error(logging_text + "error initializing helm-v3 cluster: {}".format(str(e)))
2289 raise LcmException("K8s cluster '{}' has not been initialized for '{}'".format(cluster_id,
2290 cluster_type))
2291 else:
2292 raise LcmException("K8s cluster '{}' has not been initialized for '{}'".
2293 format(cluster_id, cluster_type))
tierno626e0152019-11-29 14:16:16 +00002294 k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id
2295 return k8s_id
2296
2297 logging_text += "Deploy kdus: "
tiernoe876f672020-02-13 14:34:48 +00002298 step = ""
calvinosanch9f9c6f22019-11-04 13:37:39 +01002299 try:
tierno626e0152019-11-29 14:16:16 +00002300 db_nsr_update = {"_admin.deployed.K8s": []}
calvinosanch9f9c6f22019-11-04 13:37:39 +01002301 self.update_db_2("nsrs", nsr_id, db_nsr_update)
calvinosanch9f9c6f22019-11-04 13:37:39 +01002302
tierno626e0152019-11-29 14:16:16 +00002303 index = 0
tiernoe876f672020-02-13 14:34:48 +00002304 updated_cluster_list = []
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002305 updated_v3_cluster_list = []
tiernoe876f672020-02-13 14:34:48 +00002306
tierno626e0152019-11-29 14:16:16 +00002307 for vnfr_data in db_vnfrs.values():
lloretgalleg7c121132020-07-08 07:53:22 +00002308 for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")):
2309 # Step 0: Prepare and set parameters
bravof922c4172020-11-24 21:21:43 -03002310 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
quilesjacde94f2020-01-23 10:07:08 +00002311 vnfd_id = vnfr_data.get('vnfd-id')
David Garciad41dbd62020-12-10 12:52:52 +01002312 vnfd_with_id = find_in_list(db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id)
2313 kdud = next(kdud for kdud in vnfd_with_id["kdu"] if kdud["name"] == kdur["kdu-name"])
tiernode1584f2020-04-07 09:07:33 +00002314 namespace = kdur.get("k8s-namespace")
tierno626e0152019-11-29 14:16:16 +00002315 if kdur.get("helm-chart"):
lloretgalleg07e53f52020-12-15 10:54:02 +00002316 kdumodel = kdur["helm-chart"]
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002317 # Default version: helm3, if helm-version is v2 assign v2
2318 k8sclustertype = "helm-chart-v3"
2319 self.logger.debug("kdur: {}".format(kdur))
2320 if kdur.get("helm-version") and kdur.get("helm-version") == "v2":
2321 k8sclustertype = "helm-chart"
tierno626e0152019-11-29 14:16:16 +00002322 elif kdur.get("juju-bundle"):
lloretgalleg07e53f52020-12-15 10:54:02 +00002323 kdumodel = kdur["juju-bundle"]
tiernoe876f672020-02-13 14:34:48 +00002324 k8sclustertype = "juju-bundle"
tierno626e0152019-11-29 14:16:16 +00002325 else:
tiernoe876f672020-02-13 14:34:48 +00002326 raise LcmException("kdu type for kdu='{}.{}' is neither helm-chart nor "
2327 "juju-bundle. Maybe an old NBI version is running".
2328 format(vnfr_data["member-vnf-index-ref"], kdur["kdu-name"]))
quilesjacde94f2020-01-23 10:07:08 +00002329 # check if kdumodel is a file and exists
2330 try:
David Garciad41dbd62020-12-10 12:52:52 +01002331 vnfd_with_id = find_in_list(db_vnfds, lambda vnfd: vnfd["_id"] == vnfd_id)
2332 storage = deep_get(vnfd_with_id, ('_admin', 'storage'))
tierno51183952020-04-03 15:48:18 +00002333 if storage and storage.get('pkg-dir'): # may be not present if vnfd has not artifacts
2334 # path format: /vnfdid/pkkdir/helm-charts|juju-bundles/kdumodel
Dominik Fleischmann010c0e72020-05-18 15:19:11 +02002335 filename = '{}/{}/{}s/{}'.format(storage["folder"], storage["pkg-dir"], k8sclustertype,
tierno51183952020-04-03 15:48:18 +00002336 kdumodel)
2337 if self.fs.file_exists(filename, mode='file') or self.fs.file_exists(filename, mode='dir'):
2338 kdumodel = self.fs.path + filename
2339 except (asyncio.TimeoutError, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00002340 raise
2341 except Exception: # it is not a file
quilesjacde94f2020-01-23 10:07:08 +00002342 pass
lloretgallegedc5f332020-02-20 11:50:50 +01002343
tiernoe876f672020-02-13 14:34:48 +00002344 k8s_cluster_id = kdur["k8s-cluster"]["id"]
2345 step = "Synchronize repos for k8s cluster '{}'".format(k8s_cluster_id)
tierno16f4a4e2020-07-20 09:05:51 +00002346 cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype)
lloretgallegedc5f332020-02-20 11:50:50 +01002347
lloretgalleg7c121132020-07-08 07:53:22 +00002348 # Synchronize repos
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002349 if (k8sclustertype == "helm-chart" and cluster_uuid not in updated_cluster_list)\
2350 or (k8sclustertype == "helm-chart-v3" and cluster_uuid not in updated_v3_cluster_list):
tiernoe876f672020-02-13 14:34:48 +00002351 del_repo_list, added_repo_dict = await asyncio.ensure_future(
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002352 self.k8scluster_map[k8sclustertype].synchronize_repos(cluster_uuid=cluster_uuid))
tiernoe876f672020-02-13 14:34:48 +00002353 if del_repo_list or added_repo_dict:
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002354 if k8sclustertype == "helm-chart":
2355 unset = {'_admin.helm_charts_added.' + item: None for item in del_repo_list}
2356 updated = {'_admin.helm_charts_added.' +
2357 item: name for item, name in added_repo_dict.items()}
2358 updated_cluster_list.append(cluster_uuid)
2359 elif k8sclustertype == "helm-chart-v3":
2360 unset = {'_admin.helm_charts_v3_added.' + item: None for item in del_repo_list}
2361 updated = {'_admin.helm_charts_v3_added.' +
2362 item: name for item, name in added_repo_dict.items()}
2363 updated_v3_cluster_list.append(cluster_uuid)
2364 self.logger.debug(logging_text + "repos synchronized on k8s cluster "
2365 "'{}' to_delete: {}, to_add: {}".
2366 format(k8s_cluster_id, del_repo_list, added_repo_dict))
tiernoe876f672020-02-13 14:34:48 +00002367 self.db.set_one("k8sclusters", {"_id": k8s_cluster_id}, updated, unset=unset)
lloretgallegedc5f332020-02-20 11:50:50 +01002368
lloretgalleg7c121132020-07-08 07:53:22 +00002369 # Instantiate kdu
tiernoe876f672020-02-13 14:34:48 +00002370 step = "Instantiating KDU {}.{} in k8s cluster {}".format(vnfr_data["member-vnf-index-ref"],
2371 kdur["kdu-name"], k8s_cluster_id)
lloretgalleg7c121132020-07-08 07:53:22 +00002372 k8s_instance_info = {"kdu-instance": None,
2373 "k8scluster-uuid": cluster_uuid,
2374 "k8scluster-type": k8sclustertype,
2375 "member-vnf-index": vnfr_data["member-vnf-index-ref"],
2376 "kdu-name": kdur["kdu-name"],
2377 "kdu-model": kdumodel,
2378 "namespace": namespace}
tiernob9018152020-04-16 14:18:24 +00002379 db_path = "_admin.deployed.K8s.{}".format(index)
lloretgalleg7c121132020-07-08 07:53:22 +00002380 db_nsr_update[db_path] = k8s_instance_info
tierno626e0152019-11-29 14:16:16 +00002381 self.update_db_2("nsrs", nsr_id, db_nsr_update)
David Garciad41dbd62020-12-10 12:52:52 +01002382 vnfd_with_id = find_in_list(db_vnfds, lambda vnf: vnf["_id"] == vnfd_id)
tiernoa2143262020-03-27 16:20:40 +00002383 task = asyncio.ensure_future(
David Garciad41dbd62020-12-10 12:52:52 +01002384 self._install_kdu(nsr_id, db_path, vnfr_data, kdu_index, kdud, vnfd_with_id,
lloretgalleg7c121132020-07-08 07:53:22 +00002385 k8s_instance_info, k8params=desc_params, timeout=600))
tiernoe876f672020-02-13 14:34:48 +00002386 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_KDU-{}".format(index), task)
tiernoa2143262020-03-27 16:20:40 +00002387 task_instantiation_info[task] = "Deploying KDU {}".format(kdur["kdu-name"])
tiernoe876f672020-02-13 14:34:48 +00002388
tierno626e0152019-11-29 14:16:16 +00002389 index += 1
quilesjdd799ac2020-01-23 16:31:11 +00002390
tiernoe876f672020-02-13 14:34:48 +00002391 except (LcmException, asyncio.CancelledError):
2392 raise
calvinosanch9f9c6f22019-11-04 13:37:39 +01002393 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00002394 msg = "Exception {} while {}: {}".format(type(e).__name__, step, e)
2395 if isinstance(e, (N2VCException, DbException)):
2396 self.logger.error(logging_text + msg)
2397 else:
2398 self.logger.critical(logging_text + msg, exc_info=True)
quilesjdd799ac2020-01-23 16:31:11 +00002399 raise LcmException(msg)
calvinosanch9f9c6f22019-11-04 13:37:39 +01002400 finally:
calvinosanch9f9c6f22019-11-04 13:37:39 +01002401 if db_nsr_update:
2402 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoda6fb102019-11-23 00:36:52 +00002403
quilesj7e13aeb2019-10-08 13:34:55 +02002404 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 +01002405 kdu_name, member_vnf_index, vdu_index, vdu_name, deploy_params, descriptor_config,
tiernoe876f672020-02-13 14:34:48 +00002406 base_folder, task_instantiation_info, stage):
quilesj7e13aeb2019-10-08 13:34:55 +02002407 # launch instantiate_N2VC in a asyncio task and register task object
2408 # Look where information of this charm is at database <nsrs>._admin.deployed.VCA
2409 # if not found, create one entry and update database
quilesj7e13aeb2019-10-08 13:34:55 +02002410 # fill db_nsr._admin.deployed.VCA.<index>
tierno588547c2020-07-01 15:30:20 +00002411
2412 self.logger.debug(logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id))
2413 if descriptor_config.get("juju"): # There is one execution envioronment of type juju
2414 ee_list = [descriptor_config]
2415 elif descriptor_config.get("execution-environment-list"):
2416 ee_list = descriptor_config.get("execution-environment-list")
2417 else: # other types as script are not supported
2418 ee_list = []
2419
2420 for ee_item in ee_list:
2421 self.logger.debug(logging_text + "_deploy_n2vc ee_item juju={}, helm={}".format(ee_item.get('juju'),
2422 ee_item.get("helm-chart")))
tiernoa278b842020-07-08 15:33:55 +00002423 ee_descriptor_id = ee_item.get("id")
tierno588547c2020-07-01 15:30:20 +00002424 if ee_item.get("juju"):
2425 vca_name = ee_item['juju'].get('charm')
2426 vca_type = "lxc_proxy_charm" if ee_item['juju'].get('charm') is not None else "native_charm"
2427 if ee_item['juju'].get('cloud') == "k8s":
2428 vca_type = "k8s_proxy_charm"
2429 elif ee_item['juju'].get('proxy') is False:
2430 vca_type = "native_charm"
2431 elif ee_item.get("helm-chart"):
2432 vca_name = ee_item['helm-chart']
lloretgalleg18ebc3a2020-10-22 09:54:51 +00002433 if ee_item.get("helm-version") and ee_item.get("helm-version") == "v2":
2434 vca_type = "helm"
2435 else:
2436 vca_type = "helm-v3"
tierno588547c2020-07-01 15:30:20 +00002437 else:
2438 self.logger.debug(logging_text + "skipping non juju neither charm configuration")
quilesj7e13aeb2019-10-08 13:34:55 +02002439 continue
quilesj3655ae02019-12-12 16:08:35 +00002440
tierno588547c2020-07-01 15:30:20 +00002441 vca_index = -1
2442 for vca_index, vca_deployed in enumerate(db_nsr["_admin"]["deployed"]["VCA"]):
2443 if not vca_deployed:
2444 continue
2445 if vca_deployed.get("member-vnf-index") == member_vnf_index and \
2446 vca_deployed.get("vdu_id") == vdu_id and \
2447 vca_deployed.get("kdu_name") == kdu_name and \
tiernoa278b842020-07-08 15:33:55 +00002448 vca_deployed.get("vdu_count_index", 0) == vdu_index and \
2449 vca_deployed.get("ee_descriptor_id") == ee_descriptor_id:
tierno588547c2020-07-01 15:30:20 +00002450 break
2451 else:
2452 # not found, create one.
tiernoa278b842020-07-08 15:33:55 +00002453 target = "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index)
2454 if vdu_id:
2455 target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0)
2456 elif kdu_name:
2457 target += "/kdu/{}".format(kdu_name)
tierno588547c2020-07-01 15:30:20 +00002458 vca_deployed = {
tiernoa278b842020-07-08 15:33:55 +00002459 "target_element": target,
2460 # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string
tierno588547c2020-07-01 15:30:20 +00002461 "member-vnf-index": member_vnf_index,
2462 "vdu_id": vdu_id,
2463 "kdu_name": kdu_name,
2464 "vdu_count_index": vdu_index,
2465 "operational-status": "init", # TODO revise
2466 "detailed-status": "", # TODO revise
2467 "step": "initial-deploy", # TODO revise
2468 "vnfd_id": vnfd_id,
2469 "vdu_name": vdu_name,
tiernoa278b842020-07-08 15:33:55 +00002470 "type": vca_type,
2471 "ee_descriptor_id": ee_descriptor_id
tierno588547c2020-07-01 15:30:20 +00002472 }
2473 vca_index += 1
quilesj3655ae02019-12-12 16:08:35 +00002474
tierno588547c2020-07-01 15:30:20 +00002475 # create VCA and configurationStatus in db
2476 db_dict = {
2477 "_admin.deployed.VCA.{}".format(vca_index): vca_deployed,
2478 "configurationStatus.{}".format(vca_index): dict()
2479 }
2480 self.update_db_2("nsrs", nsr_id, db_dict)
quilesj7e13aeb2019-10-08 13:34:55 +02002481
tierno588547c2020-07-01 15:30:20 +00002482 db_nsr["_admin"]["deployed"]["VCA"].append(vca_deployed)
2483
bravof922c4172020-11-24 21:21:43 -03002484 self.logger.debug("N2VC > NSR_ID > {}".format(nsr_id))
2485 self.logger.debug("N2VC > DB_NSR > {}".format(db_nsr))
2486 self.logger.debug("N2VC > VCA_DEPLOYED > {}".format(vca_deployed))
2487
tierno588547c2020-07-01 15:30:20 +00002488 # Launch task
2489 task_n2vc = asyncio.ensure_future(
2490 self.instantiate_N2VC(
2491 logging_text=logging_text,
2492 vca_index=vca_index,
2493 nsi_id=nsi_id,
2494 db_nsr=db_nsr,
2495 db_vnfr=db_vnfr,
2496 vdu_id=vdu_id,
2497 kdu_name=kdu_name,
2498 vdu_index=vdu_index,
2499 deploy_params=deploy_params,
2500 config_descriptor=descriptor_config,
2501 base_folder=base_folder,
2502 nslcmop_id=nslcmop_id,
2503 stage=stage,
2504 vca_type=vca_type,
tiernob996d942020-07-03 14:52:28 +00002505 vca_name=vca_name,
2506 ee_config_descriptor=ee_item
tierno588547c2020-07-01 15:30:20 +00002507 )
quilesj7e13aeb2019-10-08 13:34:55 +02002508 )
tierno588547c2020-07-01 15:30:20 +00002509 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_N2VC-{}".format(vca_index), task_n2vc)
2510 task_instantiation_info[task_n2vc] = self.task_name_deploy_vca + " {}.{}".format(
2511 member_vnf_index or "", vdu_id or "")
tiernobaa51102018-12-14 13:16:18 +00002512
tiernoc9556972019-07-05 15:25:25 +00002513 @staticmethod
kuuse0ca67472019-05-13 15:59:27 +02002514 def _create_nslcmop(nsr_id, operation, params):
2515 """
2516 Creates a ns-lcm-opp content to be stored at database.
2517 :param nsr_id: internal id of the instance
2518 :param operation: instantiate, terminate, scale, action, ...
2519 :param params: user parameters for the operation
2520 :return: dictionary following SOL005 format
2521 """
2522 # Raise exception if invalid arguments
2523 if not (nsr_id and operation and params):
2524 raise LcmException(
2525 "Parameters 'nsr_id', 'operation' and 'params' needed to create primitive not provided")
2526 now = time()
2527 _id = str(uuid4())
2528 nslcmop = {
2529 "id": _id,
2530 "_id": _id,
2531 # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
2532 "operationState": "PROCESSING",
2533 "statusEnteredTime": now,
2534 "nsInstanceId": nsr_id,
2535 "lcmOperationType": operation,
2536 "startTime": now,
2537 "isAutomaticInvocation": False,
2538 "operationParams": params,
2539 "isCancelPending": False,
2540 "links": {
2541 "self": "/osm/nslcm/v1/ns_lcm_op_occs/" + _id,
2542 "nsInstance": "/osm/nslcm/v1/ns_instances/" + nsr_id,
2543 }
2544 }
2545 return nslcmop
2546
calvinosanch9f9c6f22019-11-04 13:37:39 +01002547 def _format_additional_params(self, params):
tierno626e0152019-11-29 14:16:16 +00002548 params = params or {}
calvinosanch9f9c6f22019-11-04 13:37:39 +01002549 for key, value in params.items():
2550 if str(value).startswith("!!yaml "):
2551 params[key] = yaml.safe_load(value[7:])
calvinosanch9f9c6f22019-11-04 13:37:39 +01002552 return params
2553
kuuse8b998e42019-07-30 15:22:16 +02002554 def _get_terminate_primitive_params(self, seq, vnf_index):
2555 primitive = seq.get('name')
2556 primitive_params = {}
2557 params = {
2558 "member_vnf_index": vnf_index,
2559 "primitive": primitive,
2560 "primitive_params": primitive_params,
2561 }
2562 desc_params = {}
2563 return self._map_primitive_params(seq, params, desc_params)
2564
kuuseac3a8882019-10-03 10:48:06 +02002565 # sub-operations
2566
tierno51183952020-04-03 15:48:18 +00002567 def _retry_or_skip_suboperation(self, db_nslcmop, op_index):
2568 op = deep_get(db_nslcmop, ('_admin', 'operations'), [])[op_index]
2569 if op.get('operationState') == 'COMPLETED':
kuuseac3a8882019-10-03 10:48:06 +02002570 # b. Skip sub-operation
2571 # _ns_execute_primitive() or RO.create_action() will NOT be executed
2572 return self.SUBOPERATION_STATUS_SKIP
2573 else:
tierno7c4e24c2020-05-13 08:41:35 +00002574 # c. retry executing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02002575 # The sub-operation exists, and operationState != 'COMPLETED'
tierno7c4e24c2020-05-13 08:41:35 +00002576 # Update operationState = 'PROCESSING' to indicate a retry.
kuuseac3a8882019-10-03 10:48:06 +02002577 operationState = 'PROCESSING'
2578 detailed_status = 'In progress'
2579 self._update_suboperation_status(
2580 db_nslcmop, op_index, operationState, detailed_status)
2581 # Return the sub-operation index
2582 # _ns_execute_primitive() or RO.create_action() will be called from scale()
2583 # with arguments extracted from the sub-operation
2584 return op_index
2585
2586 # Find a sub-operation where all keys in a matching dictionary must match
2587 # Returns the index of the matching sub-operation, or SUBOPERATION_STATUS_NOT_FOUND if no match
2588 def _find_suboperation(self, db_nslcmop, match):
tierno7c4e24c2020-05-13 08:41:35 +00002589 if db_nslcmop and match:
kuuseac3a8882019-10-03 10:48:06 +02002590 op_list = db_nslcmop.get('_admin', {}).get('operations', [])
2591 for i, op in enumerate(op_list):
2592 if all(op.get(k) == match[k] for k in match):
2593 return i
2594 return self.SUBOPERATION_STATUS_NOT_FOUND
2595
2596 # Update status for a sub-operation given its index
2597 def _update_suboperation_status(self, db_nslcmop, op_index, operationState, detailed_status):
2598 # Update DB for HA tasks
2599 q_filter = {'_id': db_nslcmop['_id']}
2600 update_dict = {'_admin.operations.{}.operationState'.format(op_index): operationState,
2601 '_admin.operations.{}.detailed-status'.format(op_index): detailed_status}
2602 self.db.set_one("nslcmops",
2603 q_filter=q_filter,
2604 update_dict=update_dict,
2605 fail_on_empty=False)
2606
2607 # Add sub-operation, return the index of the added sub-operation
2608 # Optionally, set operationState, detailed-status, and operationType
2609 # Status and type are currently set for 'scale' sub-operations:
2610 # 'operationState' : 'PROCESSING' | 'COMPLETED' | 'FAILED'
2611 # 'detailed-status' : status message
2612 # 'operationType': may be any type, in the case of scaling: 'PRE-SCALE' | 'POST-SCALE'
2613 # Status and operation type are currently only used for 'scale', but NOT for 'terminate' sub-operations.
tierno2357f4e2020-10-19 16:38:59 +00002614 def _add_suboperation(self, db_nslcmop, vnf_index, vdu_id, vdu_count_index, vdu_name, primitive,
quilesj7e13aeb2019-10-08 13:34:55 +02002615 mapped_primitive_params, operationState=None, detailed_status=None, operationType=None,
kuuseac3a8882019-10-03 10:48:06 +02002616 RO_nsr_id=None, RO_scaling_info=None):
tiernoe876f672020-02-13 14:34:48 +00002617 if not db_nslcmop:
kuuseac3a8882019-10-03 10:48:06 +02002618 return self.SUBOPERATION_STATUS_NOT_FOUND
2619 # Get the "_admin.operations" list, if it exists
2620 db_nslcmop_admin = db_nslcmop.get('_admin', {})
2621 op_list = db_nslcmop_admin.get('operations')
2622 # Create or append to the "_admin.operations" list
kuuse8b998e42019-07-30 15:22:16 +02002623 new_op = {'member_vnf_index': vnf_index,
2624 'vdu_id': vdu_id,
2625 'vdu_count_index': vdu_count_index,
2626 'primitive': primitive,
2627 'primitive_params': mapped_primitive_params}
kuuseac3a8882019-10-03 10:48:06 +02002628 if operationState:
2629 new_op['operationState'] = operationState
2630 if detailed_status:
2631 new_op['detailed-status'] = detailed_status
2632 if operationType:
2633 new_op['lcmOperationType'] = operationType
2634 if RO_nsr_id:
2635 new_op['RO_nsr_id'] = RO_nsr_id
2636 if RO_scaling_info:
2637 new_op['RO_scaling_info'] = RO_scaling_info
2638 if not op_list:
2639 # No existing operations, create key 'operations' with current operation as first list element
2640 db_nslcmop_admin.update({'operations': [new_op]})
2641 op_list = db_nslcmop_admin.get('operations')
2642 else:
2643 # Existing operations, append operation to list
2644 op_list.append(new_op)
kuuse8b998e42019-07-30 15:22:16 +02002645
kuuseac3a8882019-10-03 10:48:06 +02002646 db_nslcmop_update = {'_admin.operations': op_list}
2647 self.update_db_2("nslcmops", db_nslcmop['_id'], db_nslcmop_update)
2648 op_index = len(op_list) - 1
2649 return op_index
2650
2651 # Helper methods for scale() sub-operations
2652
2653 # pre-scale/post-scale:
2654 # Check for 3 different cases:
2655 # a. New: First time execution, return SUBOPERATION_STATUS_NEW
2656 # b. Skip: Existing sub-operation exists, operationState == 'COMPLETED', return SUBOPERATION_STATUS_SKIP
tierno7c4e24c2020-05-13 08:41:35 +00002657 # c. retry: Existing sub-operation exists, operationState != 'COMPLETED', return op_index to re-execute
quilesj7e13aeb2019-10-08 13:34:55 +02002658 def _check_or_add_scale_suboperation(self, db_nslcmop, vnf_index, vnf_config_primitive, primitive_params,
2659 operationType, RO_nsr_id=None, RO_scaling_info=None):
kuuseac3a8882019-10-03 10:48:06 +02002660 # Find this sub-operation
tierno7c4e24c2020-05-13 08:41:35 +00002661 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02002662 operationType = 'SCALE-RO'
2663 match = {
2664 'member_vnf_index': vnf_index,
2665 'RO_nsr_id': RO_nsr_id,
2666 'RO_scaling_info': RO_scaling_info,
2667 }
2668 else:
2669 match = {
2670 'member_vnf_index': vnf_index,
2671 'primitive': vnf_config_primitive,
2672 'primitive_params': primitive_params,
2673 'lcmOperationType': operationType
2674 }
2675 op_index = self._find_suboperation(db_nslcmop, match)
tierno51183952020-04-03 15:48:18 +00002676 if op_index == self.SUBOPERATION_STATUS_NOT_FOUND:
kuuseac3a8882019-10-03 10:48:06 +02002677 # a. New sub-operation
2678 # The sub-operation does not exist, add it.
2679 # _ns_execute_primitive() will be called from scale() as usual, with non-modified arguments
2680 # The following parameters are set to None for all kind of scaling:
2681 vdu_id = None
2682 vdu_count_index = None
2683 vdu_name = None
tierno51183952020-04-03 15:48:18 +00002684 if RO_nsr_id and RO_scaling_info:
kuuseac3a8882019-10-03 10:48:06 +02002685 vnf_config_primitive = None
2686 primitive_params = None
2687 else:
2688 RO_nsr_id = None
2689 RO_scaling_info = None
2690 # Initial status for sub-operation
2691 operationState = 'PROCESSING'
2692 detailed_status = 'In progress'
2693 # Add sub-operation for pre/post-scaling (zero or more operations)
2694 self._add_suboperation(db_nslcmop,
2695 vnf_index,
2696 vdu_id,
2697 vdu_count_index,
2698 vdu_name,
2699 vnf_config_primitive,
2700 primitive_params,
2701 operationState,
2702 detailed_status,
2703 operationType,
2704 RO_nsr_id,
2705 RO_scaling_info)
2706 return self.SUBOPERATION_STATUS_NEW
2707 else:
2708 # Return either SUBOPERATION_STATUS_SKIP (operationState == 'COMPLETED'),
2709 # or op_index (operationState != 'COMPLETED')
tierno51183952020-04-03 15:48:18 +00002710 return self._retry_or_skip_suboperation(db_nslcmop, op_index)
kuuseac3a8882019-10-03 10:48:06 +02002711
preethika.pdf7d8e02019-12-10 13:10:48 +00002712 # Function to return execution_environment id
2713
2714 def _get_ee_id(self, vnf_index, vdu_id, vca_deployed_list):
tiernoe876f672020-02-13 14:34:48 +00002715 # TODO vdu_index_count
preethika.pdf7d8e02019-12-10 13:10:48 +00002716 for vca in vca_deployed_list:
2717 if vca["member-vnf-index"] == vnf_index and vca["vdu_id"] == vdu_id:
2718 return vca["ee_id"]
2719
tierno588547c2020-07-01 15:30:20 +00002720 async def destroy_N2VC(self, logging_text, db_nslcmop, vca_deployed, config_descriptor,
2721 vca_index, destroy_ee=True, exec_primitives=True):
tiernoe876f672020-02-13 14:34:48 +00002722 """
2723 Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
2724 :param logging_text:
2725 :param db_nslcmop:
2726 :param vca_deployed: Dictionary of deployment info at db_nsr._admin.depoloyed.VCA.<INDEX>
2727 :param config_descriptor: Configuration descriptor of the NSD, VNFD, VNFD.vdu or VNFD.kdu
2728 :param vca_index: index in the database _admin.deployed.VCA
2729 :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
tierno588547c2020-07-01 15:30:20 +00002730 :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
2731 not executed properly
tiernoe876f672020-02-13 14:34:48 +00002732 :return: None or exception
2733 """
tiernoe876f672020-02-13 14:34:48 +00002734
tierno588547c2020-07-01 15:30:20 +00002735 self.logger.debug(
2736 logging_text + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
2737 vca_index, vca_deployed, config_descriptor, destroy_ee
2738 )
2739 )
2740
2741 vca_type = vca_deployed.get("type", "lxc_proxy_charm")
2742
2743 # execute terminate_primitives
2744 if exec_primitives:
bravof922c4172020-11-24 21:21:43 -03002745 terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
2746 config_descriptor.get("terminate-config-primitive"), vca_deployed.get("ee_descriptor_id"))
tierno588547c2020-07-01 15:30:20 +00002747 vdu_id = vca_deployed.get("vdu_id")
2748 vdu_count_index = vca_deployed.get("vdu_count_index")
2749 vdu_name = vca_deployed.get("vdu_name")
2750 vnf_index = vca_deployed.get("member-vnf-index")
2751 if terminate_primitives and vca_deployed.get("needed_terminate"):
tierno588547c2020-07-01 15:30:20 +00002752 for seq in terminate_primitives:
2753 # For each sequence in list, get primitive and call _ns_execute_primitive()
2754 step = "Calling terminate action for vnf_member_index={} primitive={}".format(
2755 vnf_index, seq.get("name"))
2756 self.logger.debug(logging_text + step)
2757 # Create the primitive for each sequence, i.e. "primitive": "touch"
2758 primitive = seq.get('name')
2759 mapped_primitive_params = self._get_terminate_primitive_params(seq, vnf_index)
tierno588547c2020-07-01 15:30:20 +00002760
2761 # Add sub-operation
2762 self._add_suboperation(db_nslcmop,
2763 vnf_index,
2764 vdu_id,
2765 vdu_count_index,
2766 vdu_name,
2767 primitive,
2768 mapped_primitive_params)
2769 # Sub-operations: Call _ns_execute_primitive() instead of action()
2770 try:
2771 result, result_detail = await self._ns_execute_primitive(vca_deployed["ee_id"], primitive,
2772 mapped_primitive_params,
2773 vca_type=vca_type)
2774 except LcmException:
2775 # this happens when VCA is not deployed. In this case it is not needed to terminate
2776 continue
2777 result_ok = ['COMPLETED', 'PARTIALLY_COMPLETED']
2778 if result not in result_ok:
2779 raise LcmException("terminate_primitive {} for vnf_member_index={} fails with "
2780 "error {}".format(seq.get("name"), vnf_index, result_detail))
2781 # set that this VCA do not need terminated
2782 db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(vca_index)
2783 self.update_db_2("nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False})
tiernoe876f672020-02-13 14:34:48 +00002784
tiernob996d942020-07-03 14:52:28 +00002785 if vca_deployed.get("prometheus_jobs") and self.prometheus:
2786 await self.prometheus.update(remove_jobs=vca_deployed["prometheus_jobs"])
2787
tiernoe876f672020-02-13 14:34:48 +00002788 if destroy_ee:
tierno588547c2020-07-01 15:30:20 +00002789 await self.vca_map[vca_type].delete_execution_environment(vca_deployed["ee_id"])
kuuse0ca67472019-05-13 15:59:27 +02002790
tierno51183952020-04-03 15:48:18 +00002791 async def _delete_all_N2VC(self, db_nsr: dict):
2792 self._write_all_config_status(db_nsr=db_nsr, status='TERMINATING')
2793 namespace = "." + db_nsr["_id"]
tiernof59ad6c2020-04-08 12:50:52 +00002794 try:
2795 await self.n2vc.delete_namespace(namespace=namespace, total_timeout=self.timeout_charm_delete)
2796 except N2VCNotFound: # already deleted. Skip
2797 pass
tierno51183952020-04-03 15:48:18 +00002798 self._write_all_config_status(db_nsr=db_nsr, status='DELETED')
quilesj3655ae02019-12-12 16:08:35 +00002799
tiernoe876f672020-02-13 14:34:48 +00002800 async def _terminate_RO(self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage):
2801 """
2802 Terminates a deployment from RO
2803 :param logging_text:
2804 :param nsr_deployed: db_nsr._admin.deployed
2805 :param nsr_id:
2806 :param nslcmop_id:
2807 :param stage: list of string with the content to write on db_nslcmop.detailed-status.
2808 this method will update only the index 2, but it will write on database the concatenated content of the list
2809 :return:
2810 """
2811 db_nsr_update = {}
2812 failed_detail = []
2813 ro_nsr_id = ro_delete_action = None
2814 if nsr_deployed and nsr_deployed.get("RO"):
2815 ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
2816 ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
2817 try:
2818 if ro_nsr_id:
2819 stage[2] = "Deleting ns from VIM."
2820 db_nsr_update["detailed-status"] = " ".join(stage)
2821 self._write_op_status(nslcmop_id, stage)
2822 self.logger.debug(logging_text + stage[2])
2823 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2824 self._write_op_status(nslcmop_id, stage)
2825 desc = await self.RO.delete("ns", ro_nsr_id)
2826 ro_delete_action = desc["action_id"]
2827 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = ro_delete_action
2828 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
2829 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2830 if ro_delete_action:
2831 # wait until NS is deleted from VIM
2832 stage[2] = "Waiting ns deleted from VIM."
2833 detailed_status_old = None
2834 self.logger.debug(logging_text + stage[2] + " RO_id={} ro_delete_action={}".format(ro_nsr_id,
2835 ro_delete_action))
2836 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2837 self._write_op_status(nslcmop_id, stage)
kuused124bfe2019-06-18 12:09:24 +02002838
tiernoe876f672020-02-13 14:34:48 +00002839 delete_timeout = 20 * 60 # 20 minutes
2840 while delete_timeout > 0:
2841 desc = await self.RO.show(
2842 "ns",
2843 item_id_name=ro_nsr_id,
2844 extra_item="action",
2845 extra_item_id=ro_delete_action)
2846
2847 # deploymentStatus
2848 self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
2849
2850 ns_status, ns_status_info = self.RO.check_action_status(desc)
2851 if ns_status == "ERROR":
2852 raise ROclient.ROClientException(ns_status_info)
2853 elif ns_status == "BUILD":
2854 stage[2] = "Deleting from VIM {}".format(ns_status_info)
2855 elif ns_status == "ACTIVE":
2856 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
2857 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2858 break
2859 else:
2860 assert False, "ROclient.check_action_status returns unknown {}".format(ns_status)
2861 if stage[2] != detailed_status_old:
2862 detailed_status_old = stage[2]
2863 db_nsr_update["detailed-status"] = " ".join(stage)
2864 self._write_op_status(nslcmop_id, stage)
2865 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2866 await asyncio.sleep(5, loop=self.loop)
2867 delete_timeout -= 5
2868 else: # delete_timeout <= 0:
2869 raise ROclient.ROClientException("Timeout waiting ns deleted from VIM")
2870
2871 except Exception as e:
2872 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2873 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2874 db_nsr_update["_admin.deployed.RO.nsr_id"] = None
2875 db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
2876 db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
2877 self.logger.debug(logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id))
2878 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
tiernoa2143262020-03-27 16:20:40 +00002879 failed_detail.append("delete conflict: {}".format(e))
2880 self.logger.debug(logging_text + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e))
tiernoe876f672020-02-13 14:34:48 +00002881 else:
tiernoa2143262020-03-27 16:20:40 +00002882 failed_detail.append("delete error: {}".format(e))
2883 self.logger.error(logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e))
tiernoe876f672020-02-13 14:34:48 +00002884
2885 # Delete nsd
2886 if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
2887 ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
2888 try:
2889 stage[2] = "Deleting nsd from RO."
2890 db_nsr_update["detailed-status"] = " ".join(stage)
2891 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2892 self._write_op_status(nslcmop_id, stage)
2893 await self.RO.delete("nsd", ro_nsd_id)
2894 self.logger.debug(logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id))
2895 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
2896 except Exception as e:
2897 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2898 db_nsr_update["_admin.deployed.RO.nsd_id"] = None
2899 self.logger.debug(logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id))
2900 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
2901 failed_detail.append("ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e))
2902 self.logger.debug(logging_text + failed_detail[-1])
2903 else:
2904 failed_detail.append("ro_nsd_id={} delete error: {}".format(ro_nsd_id, e))
2905 self.logger.error(logging_text + failed_detail[-1])
2906
2907 if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
2908 for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
2909 if not vnf_deployed or not vnf_deployed["id"]:
2910 continue
2911 try:
2912 ro_vnfd_id = vnf_deployed["id"]
2913 stage[2] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
2914 vnf_deployed["member-vnf-index"], ro_vnfd_id)
2915 db_nsr_update["detailed-status"] = " ".join(stage)
2916 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2917 self._write_op_status(nslcmop_id, stage)
2918 await self.RO.delete("vnfd", ro_vnfd_id)
2919 self.logger.debug(logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id))
2920 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
2921 except Exception as e:
2922 if isinstance(e, ROclient.ROClientException) and e.http_code == 404: # not found
2923 db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
2924 self.logger.debug(logging_text + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id))
2925 elif isinstance(e, ROclient.ROClientException) and e.http_code == 409: # conflict
2926 failed_detail.append("ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e))
2927 self.logger.debug(logging_text + failed_detail[-1])
2928 else:
2929 failed_detail.append("ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e))
2930 self.logger.error(logging_text + failed_detail[-1])
2931
tiernoa2143262020-03-27 16:20:40 +00002932 if failed_detail:
2933 stage[2] = "Error deleting from VIM"
2934 else:
2935 stage[2] = "Deleted from VIM"
tiernoe876f672020-02-13 14:34:48 +00002936 db_nsr_update["detailed-status"] = " ".join(stage)
2937 self.update_db_2("nsrs", nsr_id, db_nsr_update)
2938 self._write_op_status(nslcmop_id, stage)
2939
2940 if failed_detail:
tiernoa2143262020-03-27 16:20:40 +00002941 raise LcmException("; ".join(failed_detail))
tiernoe876f672020-02-13 14:34:48 +00002942
2943 async def terminate(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02002944 # Try to lock HA task here
2945 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
2946 if not task_is_locked_by_me:
2947 return
2948
tierno59d22d22018-09-25 18:10:19 +02002949 logging_text = "Task ns={} terminate={} ".format(nsr_id, nslcmop_id)
2950 self.logger.debug(logging_text + "Enter")
tiernoe876f672020-02-13 14:34:48 +00002951 timeout_ns_terminate = self.timeout_ns_terminate
tierno59d22d22018-09-25 18:10:19 +02002952 db_nsr = None
2953 db_nslcmop = None
tiernoa17d4f42020-04-28 09:59:23 +00002954 operation_params = None
tierno59d22d22018-09-25 18:10:19 +02002955 exc = None
tiernoe876f672020-02-13 14:34:48 +00002956 error_list = [] # annotates all failed error messages
tierno59d22d22018-09-25 18:10:19 +02002957 db_nslcmop_update = {}
tiernoc2564fe2019-01-28 16:18:56 +00002958 autoremove = False # autoremove after terminated
tiernoe876f672020-02-13 14:34:48 +00002959 tasks_dict_info = {}
2960 db_nsr_update = {}
2961 stage = ["Stage 1/3: Preparing task.", "Waiting for previous operations to terminate.", ""]
2962 # ^ contains [stage, step, VIM-status]
tierno59d22d22018-09-25 18:10:19 +02002963 try:
kuused124bfe2019-06-18 12:09:24 +02002964 # wait for any previous tasks in process
2965 await self.lcm_tasks.waitfor_related_HA("ns", 'nslcmops', nslcmop_id)
2966
tiernoe876f672020-02-13 14:34:48 +00002967 stage[1] = "Getting nslcmop={} from db.".format(nslcmop_id)
2968 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
2969 operation_params = db_nslcmop.get("operationParams") or {}
2970 if operation_params.get("timeout_ns_terminate"):
2971 timeout_ns_terminate = operation_params["timeout_ns_terminate"]
2972 stage[1] = "Getting nsr={} from db.".format(nsr_id)
2973 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
2974
2975 db_nsr_update["operational-status"] = "terminating"
2976 db_nsr_update["config-status"] = "terminating"
quilesj4cda56b2019-12-05 10:02:20 +00002977 self._write_ns_status(
2978 nsr_id=nsr_id,
2979 ns_state="TERMINATING",
2980 current_operation="TERMINATING",
tiernoe876f672020-02-13 14:34:48 +00002981 current_operation_id=nslcmop_id,
2982 other_update=db_nsr_update
quilesj4cda56b2019-12-05 10:02:20 +00002983 )
quilesj3655ae02019-12-12 16:08:35 +00002984 self._write_op_status(
2985 op_id=nslcmop_id,
tiernoe876f672020-02-13 14:34:48 +00002986 queuePosition=0,
2987 stage=stage
quilesj3655ae02019-12-12 16:08:35 +00002988 )
tiernoe876f672020-02-13 14:34:48 +00002989 nsr_deployed = deepcopy(db_nsr["_admin"].get("deployed")) or {}
tierno59d22d22018-09-25 18:10:19 +02002990 if db_nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
2991 return
tierno59d22d22018-09-25 18:10:19 +02002992
tiernoe876f672020-02-13 14:34:48 +00002993 stage[1] = "Getting vnf descriptors from db."
2994 db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
2995 db_vnfds_from_id = {}
2996 db_vnfds_from_member_index = {}
2997 # Loop over VNFRs
2998 for vnfr in db_vnfrs_list:
2999 vnfd_id = vnfr["vnfd-id"]
3000 if vnfd_id not in db_vnfds_from_id:
3001 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
3002 db_vnfds_from_id[vnfd_id] = vnfd
3003 db_vnfds_from_member_index[vnfr["member-vnf-index-ref"]] = db_vnfds_from_id[vnfd_id]
calvinosanch9f9c6f22019-11-04 13:37:39 +01003004
tiernoe876f672020-02-13 14:34:48 +00003005 # Destroy individual execution environments when there are terminating primitives.
3006 # Rest of EE will be deleted at once
tierno588547c2020-07-01 15:30:20 +00003007 # TODO - check before calling _destroy_N2VC
3008 # if not operation_params.get("skip_terminate_primitives"):#
3009 # or not vca.get("needed_terminate"):
3010 stage[0] = "Stage 2/3 execute terminating primitives."
3011 self.logger.debug(logging_text + stage[0])
3012 stage[1] = "Looking execution environment that needs terminate."
3013 self.logger.debug(logging_text + stage[1])
bravof922c4172020-11-24 21:21:43 -03003014
tierno588547c2020-07-01 15:30:20 +00003015 for vca_index, vca in enumerate(get_iterable(nsr_deployed, "VCA")):
tierno588547c2020-07-01 15:30:20 +00003016 config_descriptor = None
3017 if not vca or not vca.get("ee_id"):
3018 continue
3019 if not vca.get("member-vnf-index"):
3020 # ns
3021 config_descriptor = db_nsr.get("ns-configuration")
3022 elif vca.get("vdu_id"):
3023 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
3024 vdud = next((vdu for vdu in db_vnfd.get("vdu", ()) if vdu["id"] == vca.get("vdu_id")), None)
3025 if vdud:
3026 config_descriptor = vdud.get("vdu-configuration")
3027 elif vca.get("kdu_name"):
3028 db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
3029 kdud = next((kdu for kdu in db_vnfd.get("kdu", ()) if kdu["name"] == vca.get("kdu_name")), None)
3030 if kdud:
3031 config_descriptor = kdud.get("kdu-configuration")
3032 else:
3033 config_descriptor = db_vnfds_from_member_index[vca["member-vnf-index"]].get("vnf-configuration")
tierno588547c2020-07-01 15:30:20 +00003034 vca_type = vca.get("type")
3035 exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and
3036 vca.get("needed_terminate"))
tiernoaebd7da2020-08-07 06:36:38 +00003037 # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are
3038 # pending native charms
lloretgalleg18ebc3a2020-10-22 09:54:51 +00003039 destroy_ee = True if vca_type in ("helm", "helm-v3", "native_charm") else False
tierno86e33612020-09-16 14:13:06 +00003040 # self.logger.debug(logging_text + "vca_index: {}, ee_id: {}, vca_type: {} destroy_ee: {}".format(
3041 # vca_index, vca.get("ee_id"), vca_type, destroy_ee))
tiernob996d942020-07-03 14:52:28 +00003042 task = asyncio.ensure_future(
3043 self.destroy_N2VC(logging_text, db_nslcmop, vca, config_descriptor, vca_index,
3044 destroy_ee, exec_terminate_primitives))
tierno588547c2020-07-01 15:30:20 +00003045 tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
tierno59d22d22018-09-25 18:10:19 +02003046
tierno588547c2020-07-01 15:30:20 +00003047 # wait for pending tasks of terminate primitives
3048 if tasks_dict_info:
tierno86e33612020-09-16 14:13:06 +00003049 self.logger.debug(logging_text + 'Waiting for tasks {}'.format(list(tasks_dict_info.keys())))
tierno588547c2020-07-01 15:30:20 +00003050 error_list = await self._wait_for_tasks(logging_text, tasks_dict_info,
3051 min(self.timeout_charm_delete, timeout_ns_terminate),
3052 stage, nslcmop_id)
tierno86e33612020-09-16 14:13:06 +00003053 tasks_dict_info.clear()
tierno588547c2020-07-01 15:30:20 +00003054 if error_list:
3055 return # raise LcmException("; ".join(error_list))
tierno82974b22018-11-27 21:55:36 +00003056
tiernoe876f672020-02-13 14:34:48 +00003057 # remove All execution environments at once
3058 stage[0] = "Stage 3/3 delete all."
quilesj3655ae02019-12-12 16:08:35 +00003059
tierno49676be2020-04-07 16:34:35 +00003060 if nsr_deployed.get("VCA"):
3061 stage[1] = "Deleting all execution environments."
3062 self.logger.debug(logging_text + stage[1])
3063 task_delete_ee = asyncio.ensure_future(asyncio.wait_for(self._delete_all_N2VC(db_nsr=db_nsr),
3064 timeout=self.timeout_charm_delete))
3065 # task_delete_ee = asyncio.ensure_future(self.n2vc.delete_namespace(namespace="." + nsr_id))
3066 tasks_dict_info[task_delete_ee] = "Terminating all VCA"
tierno59d22d22018-09-25 18:10:19 +02003067
tiernoe876f672020-02-13 14:34:48 +00003068 # Delete from k8scluster
3069 stage[1] = "Deleting KDUs."
3070 self.logger.debug(logging_text + stage[1])
3071 # print(nsr_deployed)
3072 for kdu in get_iterable(nsr_deployed, "K8s"):
3073 if not kdu or not kdu.get("kdu-instance"):
3074 continue
3075 kdu_instance = kdu.get("kdu-instance")
tiernoa2143262020-03-27 16:20:40 +00003076 if kdu.get("k8scluster-type") in self.k8scluster_map:
tiernoe876f672020-02-13 14:34:48 +00003077 task_delete_kdu_instance = asyncio.ensure_future(
tiernoa2143262020-03-27 16:20:40 +00003078 self.k8scluster_map[kdu["k8scluster-type"]].uninstall(
3079 cluster_uuid=kdu.get("k8scluster-uuid"),
3080 kdu_instance=kdu_instance))
tiernoe876f672020-02-13 14:34:48 +00003081 else:
3082 self.logger.error(logging_text + "Unknown k8s deployment type {}".
3083 format(kdu.get("k8scluster-type")))
3084 continue
3085 tasks_dict_info[task_delete_kdu_instance] = "Terminating KDU '{}'".format(kdu.get("kdu-name"))
tierno59d22d22018-09-25 18:10:19 +02003086
3087 # remove from RO
tiernoe876f672020-02-13 14:34:48 +00003088 stage[1] = "Deleting ns from VIM."
tierno69f0d382020-05-07 13:08:09 +00003089 if self.ng_ro:
3090 task_delete_ro = asyncio.ensure_future(
3091 self._terminate_ng_ro(logging_text, nsr_deployed, nsr_id, nslcmop_id, stage))
3092 else:
3093 task_delete_ro = asyncio.ensure_future(
3094 self._terminate_RO(logging_text, nsr_deployed, nsr_id, nslcmop_id, stage))
tiernoe876f672020-02-13 14:34:48 +00003095 tasks_dict_info[task_delete_ro] = "Removing deployment from VIM"
tierno59d22d22018-09-25 18:10:19 +02003096
tiernoe876f672020-02-13 14:34:48 +00003097 # rest of staff will be done at finally
3098
3099 except (ROclient.ROClientException, DbException, LcmException, N2VCException) as e:
3100 self.logger.error(logging_text + "Exit Exception {}".format(e))
3101 exc = e
3102 except asyncio.CancelledError:
3103 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(stage[1]))
3104 exc = "Operation was cancelled"
3105 except Exception as e:
3106 exc = traceback.format_exc()
3107 self.logger.critical(logging_text + "Exit Exception while '{}': {}".format(stage[1], e), exc_info=True)
3108 finally:
3109 if exc:
3110 error_list.append(str(exc))
tierno59d22d22018-09-25 18:10:19 +02003111 try:
tiernoe876f672020-02-13 14:34:48 +00003112 # wait for pending tasks
3113 if tasks_dict_info:
3114 stage[1] = "Waiting for terminate pending tasks."
3115 self.logger.debug(logging_text + stage[1])
3116 error_list += await self._wait_for_tasks(logging_text, tasks_dict_info, timeout_ns_terminate,
3117 stage, nslcmop_id)
3118 stage[1] = stage[2] = ""
3119 except asyncio.CancelledError:
3120 error_list.append("Cancelled")
3121 # TODO cancell all tasks
3122 except Exception as exc:
3123 error_list.append(str(exc))
3124 # update status at database
3125 if error_list:
3126 error_detail = "; ".join(error_list)
3127 # self.logger.error(logging_text + error_detail)
tiernob5203912020-08-11 11:20:13 +00003128 error_description_nslcmop = '{} Detail: {}'.format(stage[0], error_detail)
3129 error_description_nsr = 'Operation: TERMINATING.{}, {}.'.format(nslcmop_id, stage[0])
tierno59d22d22018-09-25 18:10:19 +02003130
tierno59d22d22018-09-25 18:10:19 +02003131 db_nsr_update["operational-status"] = "failed"
tiernoa2143262020-03-27 16:20:40 +00003132 db_nsr_update["detailed-status"] = error_description_nsr + " Detail: " + error_detail
tiernoe876f672020-02-13 14:34:48 +00003133 db_nslcmop_update["detailed-status"] = error_detail
3134 nslcmop_operation_state = "FAILED"
3135 ns_state = "BROKEN"
tierno59d22d22018-09-25 18:10:19 +02003136 else:
tiernoa2143262020-03-27 16:20:40 +00003137 error_detail = None
tiernoe876f672020-02-13 14:34:48 +00003138 error_description_nsr = error_description_nslcmop = None
3139 ns_state = "NOT_INSTANTIATED"
tierno59d22d22018-09-25 18:10:19 +02003140 db_nsr_update["operational-status"] = "terminated"
3141 db_nsr_update["detailed-status"] = "Done"
3142 db_nsr_update["_admin.nsState"] = "NOT_INSTANTIATED"
3143 db_nslcmop_update["detailed-status"] = "Done"
tiernoe876f672020-02-13 14:34:48 +00003144 nslcmop_operation_state = "COMPLETED"
tierno59d22d22018-09-25 18:10:19 +02003145
tiernoe876f672020-02-13 14:34:48 +00003146 if db_nsr:
3147 self._write_ns_status(
3148 nsr_id=nsr_id,
3149 ns_state=ns_state,
3150 current_operation="IDLE",
3151 current_operation_id=None,
3152 error_description=error_description_nsr,
tiernoa2143262020-03-27 16:20:40 +00003153 error_detail=error_detail,
tiernoe876f672020-02-13 14:34:48 +00003154 other_update=db_nsr_update
3155 )
tiernoa17d4f42020-04-28 09:59:23 +00003156 self._write_op_status(
3157 op_id=nslcmop_id,
3158 stage="",
3159 error_message=error_description_nslcmop,
3160 operation_state=nslcmop_operation_state,
3161 other_update=db_nslcmop_update,
3162 )
lloretgalleg6d488782020-07-22 10:13:46 +00003163 if ns_state == "NOT_INSTANTIATED":
3164 try:
3165 self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "NOT_INSTANTIATED"})
3166 except DbException as e:
3167 self.logger.warn(logging_text + 'Error writing VNFR status for nsr-id-ref: {} -> {}'.
3168 format(nsr_id, e))
tiernoa17d4f42020-04-28 09:59:23 +00003169 if operation_params:
tiernoe876f672020-02-13 14:34:48 +00003170 autoremove = operation_params.get("autoremove", False)
tierno59d22d22018-09-25 18:10:19 +02003171 if nslcmop_operation_state:
3172 try:
3173 await self.msg.aiowrite("ns", "terminated", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tiernoc2564fe2019-01-28 16:18:56 +00003174 "operationState": nslcmop_operation_state,
3175 "autoremove": autoremove},
tierno8a518872018-12-21 13:42:14 +00003176 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003177 except Exception as e:
3178 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
quilesj7e13aeb2019-10-08 13:34:55 +02003179
tierno59d22d22018-09-25 18:10:19 +02003180 self.logger.debug(logging_text + "Exit")
3181 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_terminate")
3182
tiernoe876f672020-02-13 14:34:48 +00003183 async def _wait_for_tasks(self, logging_text, created_tasks_info, timeout, stage, nslcmop_id, nsr_id=None):
3184 time_start = time()
tiernoa2143262020-03-27 16:20:40 +00003185 error_detail_list = []
tiernoe876f672020-02-13 14:34:48 +00003186 error_list = []
3187 pending_tasks = list(created_tasks_info.keys())
3188 num_tasks = len(pending_tasks)
3189 num_done = 0
3190 stage[1] = "{}/{}.".format(num_done, num_tasks)
3191 self._write_op_status(nslcmop_id, stage)
tiernoe876f672020-02-13 14:34:48 +00003192 while pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00003193 new_error = None
tiernoe876f672020-02-13 14:34:48 +00003194 _timeout = timeout + time_start - time()
3195 done, pending_tasks = await asyncio.wait(pending_tasks, timeout=_timeout,
3196 return_when=asyncio.FIRST_COMPLETED)
3197 num_done += len(done)
3198 if not done: # Timeout
3199 for task in pending_tasks:
tiernoa2143262020-03-27 16:20:40 +00003200 new_error = created_tasks_info[task] + ": Timeout"
3201 error_detail_list.append(new_error)
3202 error_list.append(new_error)
tiernoe876f672020-02-13 14:34:48 +00003203 break
3204 for task in done:
3205 if task.cancelled():
tierno067e04a2020-03-31 12:53:13 +00003206 exc = "Cancelled"
tiernoe876f672020-02-13 14:34:48 +00003207 else:
3208 exc = task.exception()
tierno067e04a2020-03-31 12:53:13 +00003209 if exc:
3210 if isinstance(exc, asyncio.TimeoutError):
3211 exc = "Timeout"
3212 new_error = created_tasks_info[task] + ": {}".format(exc)
3213 error_list.append(created_tasks_info[task])
3214 error_detail_list.append(new_error)
tierno28c63da2020-04-20 16:28:56 +00003215 if isinstance(exc, (str, DbException, N2VCException, ROclient.ROClientException, LcmException,
tierno2357f4e2020-10-19 16:38:59 +00003216 K8sException, NgRoException)):
tierno067e04a2020-03-31 12:53:13 +00003217 self.logger.error(logging_text + new_error)
tiernoe876f672020-02-13 14:34:48 +00003218 else:
tierno067e04a2020-03-31 12:53:13 +00003219 exc_traceback = "".join(traceback.format_exception(None, exc, exc.__traceback__))
tierno2357f4e2020-10-19 16:38:59 +00003220 self.logger.error(logging_text + created_tasks_info[task] + " " + exc_traceback)
tierno067e04a2020-03-31 12:53:13 +00003221 else:
3222 self.logger.debug(logging_text + created_tasks_info[task] + ": Done")
tiernoe876f672020-02-13 14:34:48 +00003223 stage[1] = "{}/{}.".format(num_done, num_tasks)
3224 if new_error:
tiernoa2143262020-03-27 16:20:40 +00003225 stage[1] += " Errors: " + ". ".join(error_detail_list) + "."
tiernoe876f672020-02-13 14:34:48 +00003226 if nsr_id: # update also nsr
tiernoa2143262020-03-27 16:20:40 +00003227 self.update_db_2("nsrs", nsr_id, {"errorDescription": "Error at: " + ", ".join(error_list),
3228 "errorDetail": ". ".join(error_detail_list)})
tiernoe876f672020-02-13 14:34:48 +00003229 self._write_op_status(nslcmop_id, stage)
tiernoa2143262020-03-27 16:20:40 +00003230 return error_detail_list
tiernoe876f672020-02-13 14:34:48 +00003231
tiernoda1ff8c2020-10-22 14:12:46 +00003232 @staticmethod
3233 def _map_primitive_params(primitive_desc, params, instantiation_params):
tiernoda964822019-01-14 15:53:47 +00003234 """
3235 Generates the params to be provided to charm before executing primitive. If user does not provide a parameter,
3236 The default-value is used. If it is between < > it look for a value at instantiation_params
3237 :param primitive_desc: portion of VNFD/NSD that describes primitive
3238 :param params: Params provided by user
3239 :param instantiation_params: Instantiation params provided by user
3240 :return: a dictionary with the calculated params
3241 """
3242 calculated_params = {}
3243 for parameter in primitive_desc.get("parameter", ()):
3244 param_name = parameter["name"]
3245 if param_name in params:
3246 calculated_params[param_name] = params[param_name]
tierno98ad6ea2019-05-30 17:16:28 +00003247 elif "default-value" in parameter or "value" in parameter:
3248 if "value" in parameter:
3249 calculated_params[param_name] = parameter["value"]
3250 else:
3251 calculated_params[param_name] = parameter["default-value"]
3252 if isinstance(calculated_params[param_name], str) and calculated_params[param_name].startswith("<") \
3253 and calculated_params[param_name].endswith(">"):
3254 if calculated_params[param_name][1:-1] in instantiation_params:
3255 calculated_params[param_name] = instantiation_params[calculated_params[param_name][1:-1]]
tiernoda964822019-01-14 15:53:47 +00003256 else:
3257 raise LcmException("Parameter {} needed to execute primitive {} not provided".
tiernod8323042019-08-09 11:32:23 +00003258 format(calculated_params[param_name], primitive_desc["name"]))
tiernoda964822019-01-14 15:53:47 +00003259 else:
3260 raise LcmException("Parameter {} needed to execute primitive {} not provided".
3261 format(param_name, primitive_desc["name"]))
tierno59d22d22018-09-25 18:10:19 +02003262
tiernoda964822019-01-14 15:53:47 +00003263 if isinstance(calculated_params[param_name], (dict, list, tuple)):
bravof922c4172020-11-24 21:21:43 -03003264 calculated_params[param_name] = yaml.safe_dump(calculated_params[param_name],
3265 default_flow_style=True, width=256)
tiernoda964822019-01-14 15:53:47 +00003266 elif isinstance(calculated_params[param_name], str) and calculated_params[param_name].startswith("!!yaml "):
3267 calculated_params[param_name] = calculated_params[param_name][7:]
tiernofa40e692020-10-14 14:59:36 +00003268 if parameter.get("data-type") == "INTEGER":
3269 try:
3270 calculated_params[param_name] = int(calculated_params[param_name])
3271 except ValueError: # error converting string to int
3272 raise LcmException(
3273 "Parameter {} of primitive {} must be integer".format(param_name, primitive_desc["name"]))
3274 elif parameter.get("data-type") == "BOOLEAN":
3275 calculated_params[param_name] = not ((str(calculated_params[param_name])).lower() == 'false')
tiernoc3f2a822019-11-05 13:45:04 +00003276
3277 # add always ns_config_info if primitive name is config
3278 if primitive_desc["name"] == "config":
3279 if "ns_config_info" in instantiation_params:
3280 calculated_params["ns_config_info"] = instantiation_params["ns_config_info"]
tiernoda964822019-01-14 15:53:47 +00003281 return calculated_params
3282
tiernoa278b842020-07-08 15:33:55 +00003283 def _look_for_deployed_vca(self, deployed_vca, member_vnf_index, vdu_id, vdu_count_index, kdu_name=None,
3284 ee_descriptor_id=None):
tiernoe876f672020-02-13 14:34:48 +00003285 # find vca_deployed record for this action. Raise LcmException if not found or there is not any id.
3286 for vca in deployed_vca:
3287 if not vca:
3288 continue
3289 if member_vnf_index != vca["member-vnf-index"] or vdu_id != vca["vdu_id"]:
3290 continue
tiernoe876f672020-02-13 14:34:48 +00003291 if vdu_count_index is not None and vdu_count_index != vca["vdu_count_index"]:
3292 continue
3293 if kdu_name and kdu_name != vca["kdu_name"]:
3294 continue
tiernoa278b842020-07-08 15:33:55 +00003295 if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]:
3296 continue
tiernoe876f672020-02-13 14:34:48 +00003297 break
3298 else:
3299 # vca_deployed not found
tiernoa278b842020-07-08 15:33:55 +00003300 raise LcmException("charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}"
3301 " is not deployed".format(member_vnf_index, vdu_id, vdu_count_index, kdu_name,
3302 ee_descriptor_id))
tiernoe876f672020-02-13 14:34:48 +00003303 # get ee_id
3304 ee_id = vca.get("ee_id")
tierno588547c2020-07-01 15:30:20 +00003305 vca_type = vca.get("type", "lxc_proxy_charm") # default value for backward compatibility - proxy charm
tiernoe876f672020-02-13 14:34:48 +00003306 if not ee_id:
tierno067e04a2020-03-31 12:53:13 +00003307 raise LcmException("charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} has not "
tiernoe876f672020-02-13 14:34:48 +00003308 "execution environment"
tierno067e04a2020-03-31 12:53:13 +00003309 .format(member_vnf_index, vdu_id, kdu_name, vdu_count_index))
tierno588547c2020-07-01 15:30:20 +00003310 return ee_id, vca_type
tiernoe876f672020-02-13 14:34:48 +00003311
bravof922c4172020-11-24 21:21:43 -03003312 async def _ns_execute_primitive(self, ee_id, primitive, primitive_params, retries=0, retries_interval=30,
3313 timeout=None, vca_type=None, db_dict=None) -> (str, str):
tiernoda964822019-01-14 15:53:47 +00003314 try:
tierno98ad6ea2019-05-30 17:16:28 +00003315 if primitive == "config":
3316 primitive_params = {"params": primitive_params}
tierno2fc7ce52019-06-11 22:50:01 +00003317
tierno588547c2020-07-01 15:30:20 +00003318 vca_type = vca_type or "lxc_proxy_charm"
3319
quilesj7e13aeb2019-10-08 13:34:55 +02003320 while retries >= 0:
3321 try:
tierno067e04a2020-03-31 12:53:13 +00003322 output = await asyncio.wait_for(
tierno588547c2020-07-01 15:30:20 +00003323 self.vca_map[vca_type].exec_primitive(
tierno067e04a2020-03-31 12:53:13 +00003324 ee_id=ee_id,
3325 primitive_name=primitive,
3326 params_dict=primitive_params,
3327 progress_timeout=self.timeout_progress_primitive,
tierno588547c2020-07-01 15:30:20 +00003328 total_timeout=self.timeout_primitive,
3329 db_dict=db_dict),
tierno067e04a2020-03-31 12:53:13 +00003330 timeout=timeout or self.timeout_primitive)
quilesj7e13aeb2019-10-08 13:34:55 +02003331 # execution was OK
3332 break
tierno067e04a2020-03-31 12:53:13 +00003333 except asyncio.CancelledError:
3334 raise
3335 except Exception as e: # asyncio.TimeoutError
3336 if isinstance(e, asyncio.TimeoutError):
3337 e = "Timeout"
quilesj7e13aeb2019-10-08 13:34:55 +02003338 retries -= 1
3339 if retries >= 0:
tierno73d8bd02019-11-18 17:33:27 +00003340 self.logger.debug('Error executing action {} on {} -> {}'.format(primitive, ee_id, e))
quilesj7e13aeb2019-10-08 13:34:55 +02003341 # wait and retry
3342 await asyncio.sleep(retries_interval, loop=self.loop)
tierno73d8bd02019-11-18 17:33:27 +00003343 else:
tierno067e04a2020-03-31 12:53:13 +00003344 return 'FAILED', str(e)
quilesj7e13aeb2019-10-08 13:34:55 +02003345
tiernoe876f672020-02-13 14:34:48 +00003346 return 'COMPLETED', output
quilesj7e13aeb2019-10-08 13:34:55 +02003347
tierno067e04a2020-03-31 12:53:13 +00003348 except (LcmException, asyncio.CancelledError):
tiernoe876f672020-02-13 14:34:48 +00003349 raise
quilesj7e13aeb2019-10-08 13:34:55 +02003350 except Exception as e:
tiernoe876f672020-02-13 14:34:48 +00003351 return 'FAIL', 'Error executing action {}: {}'.format(primitive, e)
tierno59d22d22018-09-25 18:10:19 +02003352
3353 async def action(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003354 # Try to lock HA task here
3355 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3356 if not task_is_locked_by_me:
3357 return
3358
tierno59d22d22018-09-25 18:10:19 +02003359 logging_text = "Task ns={} action={} ".format(nsr_id, nslcmop_id)
3360 self.logger.debug(logging_text + "Enter")
3361 # get all needed from database
3362 db_nsr = None
3363 db_nslcmop = None
tiernoe876f672020-02-13 14:34:48 +00003364 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02003365 db_nslcmop_update = {}
3366 nslcmop_operation_state = None
tierno067e04a2020-03-31 12:53:13 +00003367 error_description_nslcmop = None
tierno59d22d22018-09-25 18:10:19 +02003368 exc = None
3369 try:
kuused124bfe2019-06-18 12:09:24 +02003370 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00003371 step = "Waiting for previous operations to terminate"
kuused124bfe2019-06-18 12:09:24 +02003372 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
3373
quilesj4cda56b2019-12-05 10:02:20 +00003374 self._write_ns_status(
3375 nsr_id=nsr_id,
3376 ns_state=None,
3377 current_operation="RUNNING ACTION",
3378 current_operation_id=nslcmop_id
3379 )
3380
tierno59d22d22018-09-25 18:10:19 +02003381 step = "Getting information from database"
3382 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
3383 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
tiernoda964822019-01-14 15:53:47 +00003384
tiernoe4f7e6c2018-11-27 14:55:30 +00003385 nsr_deployed = db_nsr["_admin"].get("deployed")
tierno1b633412019-02-25 16:48:23 +00003386 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tierno59d22d22018-09-25 18:10:19 +02003387 vdu_id = db_nslcmop["operationParams"].get("vdu_id")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003388 kdu_name = db_nslcmop["operationParams"].get("kdu_name")
tiernoe4f7e6c2018-11-27 14:55:30 +00003389 vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
tierno067e04a2020-03-31 12:53:13 +00003390 primitive = db_nslcmop["operationParams"]["primitive"]
3391 primitive_params = db_nslcmop["operationParams"]["primitive_params"]
3392 timeout_ns_action = db_nslcmop["operationParams"].get("timeout_ns_action", self.timeout_primitive)
tierno59d22d22018-09-25 18:10:19 +02003393
tierno1b633412019-02-25 16:48:23 +00003394 if vnf_index:
3395 step = "Getting vnfr from database"
3396 db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id})
3397 step = "Getting vnfd from database"
3398 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
3399 else:
tierno067e04a2020-03-31 12:53:13 +00003400 step = "Getting nsd from database"
3401 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
tiernoda964822019-01-14 15:53:47 +00003402
tierno82974b22018-11-27 21:55:36 +00003403 # for backward compatibility
3404 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
3405 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
3406 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
3407 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3408
tiernoda964822019-01-14 15:53:47 +00003409 # look for primitive
tiernoa278b842020-07-08 15:33:55 +00003410 config_primitive_desc = descriptor_configuration = None
tiernoda964822019-01-14 15:53:47 +00003411 if vdu_id:
bravof922c4172020-11-24 21:21:43 -03003412 descriptor_configuration = get_vdu_configuration(db_vnfd, vdu_id)
calvinosanch9f9c6f22019-11-04 13:37:39 +01003413 elif kdu_name:
bravof922c4172020-11-24 21:21:43 -03003414 descriptor_configuration = get_kdu_configuration(db_vnfd, kdu_name)
tierno1b633412019-02-25 16:48:23 +00003415 elif vnf_index:
bravof922c4172020-11-24 21:21:43 -03003416 descriptor_configuration = get_vnf_configuration(db_vnfd)
tierno1b633412019-02-25 16:48:23 +00003417 else:
tiernoa278b842020-07-08 15:33:55 +00003418 descriptor_configuration = db_nsd.get("ns-configuration")
3419
3420 if descriptor_configuration and descriptor_configuration.get("config-primitive"):
3421 for config_primitive in descriptor_configuration["config-primitive"]:
tierno1b633412019-02-25 16:48:23 +00003422 if config_primitive["name"] == primitive:
3423 config_primitive_desc = config_primitive
3424 break
tiernoda964822019-01-14 15:53:47 +00003425
garciadeblas6bed6b32020-07-20 11:05:42 +00003426 if not config_primitive_desc:
3427 if not (kdu_name and primitive in ("upgrade", "rollback", "status")):
3428 raise LcmException("Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ".
3429 format(primitive))
3430 primitive_name = primitive
3431 ee_descriptor_id = None
3432 else:
3433 primitive_name = config_primitive_desc.get("execution-environment-primitive", primitive)
3434 ee_descriptor_id = config_primitive_desc.get("execution-environment-ref")
tierno1b633412019-02-25 16:48:23 +00003435
tierno1b633412019-02-25 16:48:23 +00003436 if vnf_index:
tierno626e0152019-11-29 14:16:16 +00003437 if vdu_id:
3438 vdur = next((x for x in db_vnfr["vdur"] if x["vdu-id-ref"] == vdu_id), None)
bravof922c4172020-11-24 21:21:43 -03003439 desc_params = parse_yaml_strings(vdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00003440 elif kdu_name:
3441 kdur = next((x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name), None)
bravof922c4172020-11-24 21:21:43 -03003442 desc_params = parse_yaml_strings(kdur.get("additionalParams"))
tierno067e04a2020-03-31 12:53:13 +00003443 else:
bravof922c4172020-11-24 21:21:43 -03003444 desc_params = parse_yaml_strings(db_vnfr.get("additionalParamsForVnf"))
tierno1b633412019-02-25 16:48:23 +00003445 else:
bravof922c4172020-11-24 21:21:43 -03003446 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
David Garciad41dbd62020-12-10 12:52:52 +01003447 if kdu_name and get_kdu_configuration(db_vnfd, kdu_name):
3448 kdu_configuration = get_kdu_configuration(db_vnfd, kdu_name)
3449 actions = set()
David Garcia95cc9c52021-02-16 21:07:58 +01003450 for primitive in kdu_configuration.get("initial-config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01003451 actions.add(primitive["name"])
David Garcia95cc9c52021-02-16 21:07:58 +01003452 for primitive in kdu_configuration.get("config-primitive", []):
David Garciad41dbd62020-12-10 12:52:52 +01003453 actions.add(primitive["name"])
3454 kdu_action = True if primitive_name in actions else False
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003455
tiernoda964822019-01-14 15:53:47 +00003456 # TODO check if ns is in a proper status
tiernoa278b842020-07-08 15:33:55 +00003457 if kdu_name and (primitive_name in ("upgrade", "rollback", "status") or kdu_action):
tierno067e04a2020-03-31 12:53:13 +00003458 # kdur and desc_params already set from before
3459 if primitive_params:
3460 desc_params.update(primitive_params)
3461 # TODO Check if we will need something at vnf level
3462 for index, kdu in enumerate(get_iterable(nsr_deployed, "K8s")):
3463 if kdu_name == kdu["kdu-name"] and kdu["member-vnf-index"] == vnf_index:
3464 break
3465 else:
3466 raise LcmException("KDU '{}' for vnf '{}' not deployed".format(kdu_name, vnf_index))
quilesj7e13aeb2019-10-08 13:34:55 +02003467
tierno067e04a2020-03-31 12:53:13 +00003468 if kdu.get("k8scluster-type") not in self.k8scluster_map:
3469 msg = "unknown k8scluster-type '{}'".format(kdu.get("k8scluster-type"))
3470 raise LcmException(msg)
3471
3472 db_dict = {"collection": "nsrs",
3473 "filter": {"_id": nsr_id},
3474 "path": "_admin.deployed.K8s.{}".format(index)}
tiernoa278b842020-07-08 15:33:55 +00003475 self.logger.debug(logging_text + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name))
3476 step = "Executing kdu {}".format(primitive_name)
3477 if primitive_name == "upgrade":
tierno067e04a2020-03-31 12:53:13 +00003478 if desc_params.get("kdu_model"):
3479 kdu_model = desc_params.get("kdu_model")
3480 del desc_params["kdu_model"]
3481 else:
3482 kdu_model = kdu.get("kdu-model")
3483 parts = kdu_model.split(sep=":")
3484 if len(parts) == 2:
3485 kdu_model = parts[0]
3486
3487 detailed_status = await asyncio.wait_for(
3488 self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
3489 cluster_uuid=kdu.get("k8scluster-uuid"),
3490 kdu_instance=kdu.get("kdu-instance"),
3491 atomic=True, kdu_model=kdu_model,
3492 params=desc_params, db_dict=db_dict,
3493 timeout=timeout_ns_action),
3494 timeout=timeout_ns_action + 10)
3495 self.logger.debug(logging_text + " Upgrade of kdu {} done".format(detailed_status))
tiernoa278b842020-07-08 15:33:55 +00003496 elif primitive_name == "rollback":
tierno067e04a2020-03-31 12:53:13 +00003497 detailed_status = await asyncio.wait_for(
3498 self.k8scluster_map[kdu["k8scluster-type"]].rollback(
3499 cluster_uuid=kdu.get("k8scluster-uuid"),
3500 kdu_instance=kdu.get("kdu-instance"),
3501 db_dict=db_dict),
3502 timeout=timeout_ns_action)
tiernoa278b842020-07-08 15:33:55 +00003503 elif primitive_name == "status":
tierno067e04a2020-03-31 12:53:13 +00003504 detailed_status = await asyncio.wait_for(
3505 self.k8scluster_map[kdu["k8scluster-type"]].status_kdu(
3506 cluster_uuid=kdu.get("k8scluster-uuid"),
3507 kdu_instance=kdu.get("kdu-instance")),
3508 timeout=timeout_ns_action)
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003509 else:
3510 kdu_instance = kdu.get("kdu-instance") or "{}-{}".format(kdu["kdu-name"], nsr_id)
3511 params = self._map_primitive_params(config_primitive_desc, primitive_params, desc_params)
3512
3513 detailed_status = await asyncio.wait_for(
3514 self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive(
3515 cluster_uuid=kdu.get("k8scluster-uuid"),
3516 kdu_instance=kdu_instance,
tiernoa278b842020-07-08 15:33:55 +00003517 primitive_name=primitive_name,
Dominik Fleischmann771c32b2020-04-07 12:39:36 +02003518 params=params, db_dict=db_dict,
3519 timeout=timeout_ns_action),
3520 timeout=timeout_ns_action)
tierno067e04a2020-03-31 12:53:13 +00003521
3522 if detailed_status:
3523 nslcmop_operation_state = 'COMPLETED'
3524 else:
3525 detailed_status = ''
3526 nslcmop_operation_state = 'FAILED'
tierno067e04a2020-03-31 12:53:13 +00003527 else:
bravof922c4172020-11-24 21:21:43 -03003528 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"], member_vnf_index=vnf_index,
3529 vdu_id=vdu_id, vdu_count_index=vdu_count_index,
tiernoa278b842020-07-08 15:33:55 +00003530 ee_descriptor_id=ee_descriptor_id)
tierno588547c2020-07-01 15:30:20 +00003531 db_nslcmop_notif = {"collection": "nslcmops",
3532 "filter": {"_id": nslcmop_id},
3533 "path": "admin.VCA"}
tierno067e04a2020-03-31 12:53:13 +00003534 nslcmop_operation_state, detailed_status = await self._ns_execute_primitive(
tierno588547c2020-07-01 15:30:20 +00003535 ee_id,
tiernoa278b842020-07-08 15:33:55 +00003536 primitive=primitive_name,
tierno067e04a2020-03-31 12:53:13 +00003537 primitive_params=self._map_primitive_params(config_primitive_desc, primitive_params, desc_params),
tierno588547c2020-07-01 15:30:20 +00003538 timeout=timeout_ns_action,
3539 vca_type=vca_type,
3540 db_dict=db_nslcmop_notif)
tierno067e04a2020-03-31 12:53:13 +00003541
3542 db_nslcmop_update["detailed-status"] = detailed_status
3543 error_description_nslcmop = detailed_status if nslcmop_operation_state == "FAILED" else ""
3544 self.logger.debug(logging_text + " task Done with result {} {}".format(nslcmop_operation_state,
3545 detailed_status))
tierno59d22d22018-09-25 18:10:19 +02003546 return # database update is called inside finally
3547
tiernof59ad6c2020-04-08 12:50:52 +00003548 except (DbException, LcmException, N2VCException, K8sException) as e:
tierno59d22d22018-09-25 18:10:19 +02003549 self.logger.error(logging_text + "Exit Exception {}".format(e))
3550 exc = e
3551 except asyncio.CancelledError:
3552 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(step))
3553 exc = "Operation was cancelled"
tierno067e04a2020-03-31 12:53:13 +00003554 except asyncio.TimeoutError:
3555 self.logger.error(logging_text + "Timeout while '{}'".format(step))
3556 exc = "Timeout"
tierno59d22d22018-09-25 18:10:19 +02003557 except Exception as e:
3558 exc = traceback.format_exc()
3559 self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
3560 finally:
tierno067e04a2020-03-31 12:53:13 +00003561 if exc:
3562 db_nslcmop_update["detailed-status"] = detailed_status = error_description_nslcmop = \
kuuse0ca67472019-05-13 15:59:27 +02003563 "FAILED {}: {}".format(step, exc)
tierno067e04a2020-03-31 12:53:13 +00003564 nslcmop_operation_state = "FAILED"
3565 if db_nsr:
3566 self._write_ns_status(
3567 nsr_id=nsr_id,
3568 ns_state=db_nsr["nsState"], # TODO check if degraded. For the moment use previous status
3569 current_operation="IDLE",
3570 current_operation_id=None,
3571 # error_description=error_description_nsr,
3572 # error_detail=error_detail,
3573 other_update=db_nsr_update
3574 )
3575
bravof922c4172020-11-24 21:21:43 -03003576 self._write_op_status(op_id=nslcmop_id, stage="", error_message=error_description_nslcmop,
3577 operation_state=nslcmop_operation_state, other_update=db_nslcmop_update)
tierno067e04a2020-03-31 12:53:13 +00003578
tierno59d22d22018-09-25 18:10:19 +02003579 if nslcmop_operation_state:
3580 try:
3581 await self.msg.aiowrite("ns", "actioned", {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
tierno8a518872018-12-21 13:42:14 +00003582 "operationState": nslcmop_operation_state},
3583 loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003584 except Exception as e:
3585 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
3586 self.logger.debug(logging_text + "Exit")
3587 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_action")
tierno067e04a2020-03-31 12:53:13 +00003588 return nslcmop_operation_state, detailed_status
tierno59d22d22018-09-25 18:10:19 +02003589
3590 async def scale(self, nsr_id, nslcmop_id):
kuused124bfe2019-06-18 12:09:24 +02003591 # Try to lock HA task here
3592 task_is_locked_by_me = self.lcm_tasks.lock_HA('ns', 'nslcmops', nslcmop_id)
3593 if not task_is_locked_by_me:
3594 return
3595
tierno59d22d22018-09-25 18:10:19 +02003596 logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
tierno2357f4e2020-10-19 16:38:59 +00003597 stage = ['', '', '']
3598 # ^ stage, step, VIM progress
tierno59d22d22018-09-25 18:10:19 +02003599 self.logger.debug(logging_text + "Enter")
3600 # get all needed from database
3601 db_nsr = None
tierno59d22d22018-09-25 18:10:19 +02003602 db_nslcmop_update = {}
tiernoe876f672020-02-13 14:34:48 +00003603 db_nsr_update = {}
tierno59d22d22018-09-25 18:10:19 +02003604 exc = None
tierno9ab95942018-10-10 16:44:22 +02003605 # in case of error, indicates what part of scale was failed to put nsr at error status
3606 scale_process = None
tiernod6de1992018-10-11 13:05:52 +02003607 old_operational_status = ""
3608 old_config_status = ""
tierno59d22d22018-09-25 18:10:19 +02003609 try:
kuused124bfe2019-06-18 12:09:24 +02003610 # wait for any previous tasks in process
tierno3cf81a32019-11-11 17:07:00 +00003611 step = "Waiting for previous operations to terminate"
kuused124bfe2019-06-18 12:09:24 +02003612 await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
bravof922c4172020-11-24 21:21:43 -03003613 self._write_ns_status(nsr_id=nsr_id, ns_state=None,
3614 current_operation="SCALING", current_operation_id=nslcmop_id)
quilesj4cda56b2019-12-05 10:02:20 +00003615
ikalyvas02d9e7b2019-05-27 18:16:01 +03003616 step = "Getting nslcmop from database"
ikalyvas02d9e7b2019-05-27 18:16:01 +03003617 self.logger.debug(step + " after having waited for previous tasks to be completed")
3618 db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
bravof922c4172020-11-24 21:21:43 -03003619
ikalyvas02d9e7b2019-05-27 18:16:01 +03003620 step = "Getting nsr from database"
3621 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
ikalyvas02d9e7b2019-05-27 18:16:01 +03003622 old_operational_status = db_nsr["operational-status"]
3623 old_config_status = db_nsr["config-status"]
bravof922c4172020-11-24 21:21:43 -03003624
tierno59d22d22018-09-25 18:10:19 +02003625 step = "Parsing scaling parameters"
3626 db_nsr_update["operational-status"] = "scaling"
3627 self.update_db_2("nsrs", nsr_id, db_nsr_update)
tiernoe4f7e6c2018-11-27 14:55:30 +00003628 nsr_deployed = db_nsr["_admin"].get("deployed")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003629
3630 #######
3631 nsr_deployed = db_nsr["_admin"].get("deployed")
3632 vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
tiernoda6fb102019-11-23 00:36:52 +00003633 # vdu_id = db_nslcmop["operationParams"].get("vdu_id")
3634 # vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
3635 # vdu_name = db_nslcmop["operationParams"].get("vdu_name")
calvinosanch9f9c6f22019-11-04 13:37:39 +01003636 #######
3637
tierno59d22d22018-09-25 18:10:19 +02003638 vnf_index = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["member-vnf-index"]
3639 scaling_group = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"]
3640 scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
tierno82974b22018-11-27 21:55:36 +00003641 # for backward compatibility
3642 if nsr_deployed and isinstance(nsr_deployed.get("VCA"), dict):
3643 nsr_deployed["VCA"] = list(nsr_deployed["VCA"].values())
3644 db_nsr_update["_admin.deployed.VCA"] = nsr_deployed["VCA"]
3645 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3646
tierno59d22d22018-09-25 18:10:19 +02003647 step = "Getting vnfr from database"
3648 db_vnfr = self.db.get_one("vnfrs", {"member-vnf-index-ref": vnf_index, "nsr-id-ref": nsr_id})
bravof922c4172020-11-24 21:21:43 -03003649
tierno59d22d22018-09-25 18:10:19 +02003650 step = "Getting vnfd from database"
3651 db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
ikalyvas02d9e7b2019-05-27 18:16:01 +03003652
tierno59d22d22018-09-25 18:10:19 +02003653 step = "Getting scaling-group-descriptor"
bravof832f8992020-12-07 12:57:31 -03003654 scaling_descriptor = find_in_list(
3655 get_scaling_aspect(
3656 db_vnfd
3657 ),
3658 lambda scale_desc: scale_desc["name"] == scaling_group
3659 )
3660 if not scaling_descriptor:
tierno59d22d22018-09-25 18:10:19 +02003661 raise LcmException("input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
3662 "at vnfd:scaling-group-descriptor".format(scaling_group))
ikalyvas02d9e7b2019-05-27 18:16:01 +03003663
tierno15b1cf12019-08-29 13:21:40 +00003664 step = "Sending scale order to VIM"
bravof922c4172020-11-24 21:21:43 -03003665 # TODO check if ns is in a proper status
tierno59d22d22018-09-25 18:10:19 +02003666 nb_scale_op = 0
3667 if not db_nsr["_admin"].get("scaling-group"):
3668 self.update_db_2("nsrs", nsr_id, {"_admin.scaling-group": [{"name": scaling_group, "nb-scale-op": 0}]})
3669 admin_scale_index = 0
3670 else:
3671 for admin_scale_index, admin_scale_info in enumerate(db_nsr["_admin"]["scaling-group"]):
3672 if admin_scale_info["name"] == scaling_group:
3673 nb_scale_op = admin_scale_info.get("nb-scale-op", 0)
3674 break
tierno9ab95942018-10-10 16:44:22 +02003675 else: # not found, set index one plus last element and add new entry with the name
3676 admin_scale_index += 1
3677 db_nsr_update["_admin.scaling-group.{}.name".format(admin_scale_index)] = scaling_group
tierno59d22d22018-09-25 18:10:19 +02003678 RO_scaling_info = []
3679 vdu_scaling_info = {"scaling_group_name": scaling_group, "vdu": []}
3680 if scaling_type == "SCALE_OUT":
bravof832f8992020-12-07 12:57:31 -03003681 if "aspect-delta-details" not in scaling_descriptor:
3682 raise LcmException(
3683 "Aspect delta details not fount in scaling descriptor {}".format(
3684 scaling_descriptor["name"]
3685 )
3686 )
tierno59d22d22018-09-25 18:10:19 +02003687 # count if max-instance-count is reached
bravof832f8992020-12-07 12:57:31 -03003688 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
kuuse8b998e42019-07-30 15:22:16 +02003689
tierno59d22d22018-09-25 18:10:19 +02003690 vdu_scaling_info["scaling_direction"] = "OUT"
3691 vdu_scaling_info["vdu-create"] = {}
bravof832f8992020-12-07 12:57:31 -03003692 for delta in deltas:
3693 for vdu_delta in delta["vdu-delta"]:
3694 vdud = get_vdu(db_vnfd, vdu_delta["id"])
3695 vdu_index = get_vdu_index(db_vnfr, vdu_delta["id"])
3696 cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
tierno72ef84f2020-10-06 08:22:07 +00003697 if cloud_init_text:
bravof832f8992020-12-07 12:57:31 -03003698 additional_params = self._get_vdu_additional_params(db_vnfr, vdud["id"]) or {}
3699 cloud_init_list = []
3700
3701 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
3702 max_instance_count = 10
3703 if vdu_profile and "max-number-of-instances" in vdu_profile:
3704 max_instance_count = vdu_profile.get("max-number-of-instances", 10)
3705
3706 deafult_instance_num = get_number_of_instances(db_vnfd, vdud["id"])
3707
3708 nb_scale_op += vdu_delta.get("number-of-instances", 1)
3709
3710 if nb_scale_op + deafult_instance_num > max_instance_count:
3711 raise LcmException(
3712 "reached the limit of {} (max-instance-count) "
3713 "scaling-out operations for the "
3714 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
bravof922c4172020-11-24 21:21:43 -03003715 )
bravof832f8992020-12-07 12:57:31 -03003716 for x in range(vdu_delta.get("number-of-instances", 1)):
3717 if cloud_init_text:
3718 # TODO Information of its own ip is not available because db_vnfr is not updated.
3719 additional_params["OSM"] = get_osm_params(
3720 db_vnfr,
3721 vdu_delta["id"],
3722 vdu_index + x
bravof922c4172020-11-24 21:21:43 -03003723 )
bravof832f8992020-12-07 12:57:31 -03003724 cloud_init_list.append(
3725 self._parse_cloud_init(
3726 cloud_init_text,
3727 additional_params,
3728 db_vnfd["id"],
3729 vdud["id"]
3730 )
3731 )
3732 RO_scaling_info.append(
3733 {
3734 "osm_vdu_id": vdu_delta["id"],
3735 "member-vnf-index": vnf_index,
3736 "type": "create",
3737 "count": vdu_delta.get("number-of-instances", 1)
3738 }
3739 )
3740 if cloud_init_list:
3741 RO_scaling_info[-1]["cloud_init"] = cloud_init_list
3742 vdu_scaling_info["vdu-create"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
ikalyvas02d9e7b2019-05-27 18:16:01 +03003743
tierno59d22d22018-09-25 18:10:19 +02003744 elif scaling_type == "SCALE_IN":
tierno59d22d22018-09-25 18:10:19 +02003745 if "min-instance-count" in scaling_descriptor and scaling_descriptor["min-instance-count"] is not None:
3746 min_instance_count = int(scaling_descriptor["min-instance-count"])
bravof832f8992020-12-07 12:57:31 -03003747
tierno59d22d22018-09-25 18:10:19 +02003748 vdu_scaling_info["scaling_direction"] = "IN"
3749 vdu_scaling_info["vdu-delete"] = {}
bravof832f8992020-12-07 12:57:31 -03003750 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
3751 for delta in deltas:
3752 for vdu_delta in delta["vdu-delta"]:
3753 min_instance_count = 0
3754 vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
3755 if vdu_profile and "min-number-of-instances" in vdu_profile:
3756 min_instance_count = vdu_profile["min-number-of-instances"]
3757
3758 deafult_instance_num = get_number_of_instances(db_vnfd, vdu_delta["id"])
3759
3760 nb_scale_op -= vdu_delta.get("number-of-instances", 1)
3761 if nb_scale_op + deafult_instance_num < min_instance_count:
3762 raise LcmException(
3763 "reached the limit of {} (min-instance-count) scaling-in operations for the "
3764 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
3765 )
3766 RO_scaling_info.append({"osm_vdu_id": vdu_delta["id"], "member-vnf-index": vnf_index,
3767 "type": "delete", "count": vdu_delta.get("number-of-instances", 1)})
3768 vdu_scaling_info["vdu-delete"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
tierno59d22d22018-09-25 18:10:19 +02003769
3770 # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
tierno27246d82018-09-27 15:59:09 +02003771 vdu_delete = copy(vdu_scaling_info.get("vdu-delete"))
tierno59d22d22018-09-25 18:10:19 +02003772 if vdu_scaling_info["scaling_direction"] == "IN":
3773 for vdur in reversed(db_vnfr["vdur"]):
tierno27246d82018-09-27 15:59:09 +02003774 if vdu_delete.get(vdur["vdu-id-ref"]):
3775 vdu_delete[vdur["vdu-id-ref"]] -= 1
tierno59d22d22018-09-25 18:10:19 +02003776 vdu_scaling_info["vdu"].append({
tierno2357f4e2020-10-19 16:38:59 +00003777 "name": vdur.get("name") or vdur.get("vdu-name"),
tierno59d22d22018-09-25 18:10:19 +02003778 "vdu_id": vdur["vdu-id-ref"],
3779 "interface": []
3780 })
3781 for interface in vdur["interfaces"]:
3782 vdu_scaling_info["vdu"][-1]["interface"].append({
3783 "name": interface["name"],
3784 "ip_address": interface["ip-address"],
3785 "mac_address": interface.get("mac-address"),
3786 })
tierno2357f4e2020-10-19 16:38:59 +00003787 # vdu_delete = vdu_scaling_info.pop("vdu-delete")
tierno59d22d22018-09-25 18:10:19 +02003788
kuuseac3a8882019-10-03 10:48:06 +02003789 # PRE-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02003790 step = "Executing pre-scale vnf-config-primitive"
3791 if scaling_descriptor.get("scaling-config-action"):
3792 for scaling_config_action in scaling_descriptor["scaling-config-action"]:
kuuseac3a8882019-10-03 10:48:06 +02003793 if (scaling_config_action.get("trigger") == "pre-scale-in" and scaling_type == "SCALE_IN") \
3794 or (scaling_config_action.get("trigger") == "pre-scale-out" and scaling_type == "SCALE_OUT"):
tierno59d22d22018-09-25 18:10:19 +02003795 vnf_config_primitive = scaling_config_action["vnf-config-primitive-name-ref"]
3796 step = db_nslcmop_update["detailed-status"] = \
3797 "executing pre-scale scaling-config-action '{}'".format(vnf_config_primitive)
tiernoda964822019-01-14 15:53:47 +00003798
tierno59d22d22018-09-25 18:10:19 +02003799 # look for primitive
tierno59d22d22018-09-25 18:10:19 +02003800 for config_primitive in db_vnfd.get("vnf-configuration", {}).get("config-primitive", ()):
3801 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02003802 break
3803 else:
3804 raise LcmException(
3805 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action"
tiernoda964822019-01-14 15:53:47 +00003806 "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-"
tiernoa278b842020-07-08 15:33:55 +00003807 "primitive".format(scaling_group, vnf_config_primitive))
tiernoda964822019-01-14 15:53:47 +00003808
tierno16fedf52019-05-24 08:38:26 +00003809 vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
tiernoda964822019-01-14 15:53:47 +00003810 if db_vnfr.get("additionalParamsForVnf"):
3811 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
quilesj7e13aeb2019-10-08 13:34:55 +02003812
tierno9ab95942018-10-10 16:44:22 +02003813 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02003814 db_nsr_update["config-status"] = "configuring pre-scaling"
kuuseac3a8882019-10-03 10:48:06 +02003815 primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params)
3816
tierno7c4e24c2020-05-13 08:41:35 +00003817 # Pre-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02003818 op_index = self._check_or_add_scale_suboperation(
3819 db_nslcmop, nslcmop_id, vnf_index, vnf_config_primitive, primitive_params, 'PRE-SCALE')
tierno7c4e24c2020-05-13 08:41:35 +00003820 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02003821 # Skip sub-operation
3822 result = 'COMPLETED'
3823 result_detail = 'Done'
3824 self.logger.debug(logging_text +
3825 "vnf_config_primitive={} Skipped sub-operation, result {} {}".format(
3826 vnf_config_primitive, result, result_detail))
3827 else:
tierno7c4e24c2020-05-13 08:41:35 +00003828 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02003829 # New sub-operation: Get index of this sub-operation
3830 op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
3831 self.logger.debug(logging_text + "vnf_config_primitive={} New sub-operation".
3832 format(vnf_config_primitive))
3833 else:
tierno7c4e24c2020-05-13 08:41:35 +00003834 # retry: Get registered params for this existing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003835 op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
3836 vnf_index = op.get('member_vnf_index')
3837 vnf_config_primitive = op.get('primitive')
3838 primitive_params = op.get('primitive_params')
tierno7c4e24c2020-05-13 08:41:35 +00003839 self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry".
kuuseac3a8882019-10-03 10:48:06 +02003840 format(vnf_config_primitive))
tierno588547c2020-07-01 15:30:20 +00003841 # Execute the primitive, either with new (first-time) or registered (reintent) args
tiernoa278b842020-07-08 15:33:55 +00003842 ee_descriptor_id = config_primitive.get("execution-environment-ref")
3843 primitive_name = config_primitive.get("execution-environment-primitive",
3844 vnf_config_primitive)
tierno588547c2020-07-01 15:30:20 +00003845 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"],
3846 member_vnf_index=vnf_index,
3847 vdu_id=None,
tiernoa278b842020-07-08 15:33:55 +00003848 vdu_count_index=None,
3849 ee_descriptor_id=ee_descriptor_id)
kuuseac3a8882019-10-03 10:48:06 +02003850 result, result_detail = await self._ns_execute_primitive(
tiernoa278b842020-07-08 15:33:55 +00003851 ee_id, primitive_name, primitive_params, vca_type)
kuuseac3a8882019-10-03 10:48:06 +02003852 self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format(
3853 vnf_config_primitive, result, result_detail))
3854 # Update operationState = COMPLETED | FAILED
3855 self._update_suboperation_status(
3856 db_nslcmop, op_index, result, result_detail)
3857
tierno59d22d22018-09-25 18:10:19 +02003858 if result == "FAILED":
3859 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02003860 db_nsr_update["config-status"] = old_config_status
3861 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02003862 # PRE-SCALE END
tierno59d22d22018-09-25 18:10:19 +02003863
tierno2357f4e2020-10-19 16:38:59 +00003864 db_nsr_update["_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)] = nb_scale_op
3865 db_nsr_update["_admin.scaling-group.{}.time".format(admin_scale_index)] = time()
3866
kuuseac3a8882019-10-03 10:48:06 +02003867 # SCALE RO - BEGIN
tierno59d22d22018-09-25 18:10:19 +02003868 if RO_scaling_info:
tierno9ab95942018-10-10 16:44:22 +02003869 scale_process = "RO"
tierno2357f4e2020-10-19 16:38:59 +00003870 if self.ro_config.get("ng"):
3871 await self._scale_ng_ro(logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage)
tierno2357f4e2020-10-19 16:38:59 +00003872 vdu_scaling_info.pop("vdu-create", None)
3873 vdu_scaling_info.pop("vdu-delete", None)
tierno59d22d22018-09-25 18:10:19 +02003874
tierno9ab95942018-10-10 16:44:22 +02003875 scale_process = None
tierno59d22d22018-09-25 18:10:19 +02003876 if db_nsr_update:
3877 self.update_db_2("nsrs", nsr_id, db_nsr_update)
3878
kuuseac3a8882019-10-03 10:48:06 +02003879 # POST-SCALE BEGIN
tierno59d22d22018-09-25 18:10:19 +02003880 # execute primitive service POST-SCALING
3881 step = "Executing post-scale vnf-config-primitive"
3882 if scaling_descriptor.get("scaling-config-action"):
3883 for scaling_config_action in scaling_descriptor["scaling-config-action"]:
kuuseac3a8882019-10-03 10:48:06 +02003884 if (scaling_config_action.get("trigger") == "post-scale-in" and scaling_type == "SCALE_IN") \
3885 or (scaling_config_action.get("trigger") == "post-scale-out" and scaling_type == "SCALE_OUT"):
tierno59d22d22018-09-25 18:10:19 +02003886 vnf_config_primitive = scaling_config_action["vnf-config-primitive-name-ref"]
3887 step = db_nslcmop_update["detailed-status"] = \
3888 "executing post-scale scaling-config-action '{}'".format(vnf_config_primitive)
tiernoda964822019-01-14 15:53:47 +00003889
tierno589befb2019-05-29 07:06:23 +00003890 vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
tiernoda964822019-01-14 15:53:47 +00003891 if db_vnfr.get("additionalParamsForVnf"):
3892 vnfr_params.update(db_vnfr["additionalParamsForVnf"])
3893
tierno59d22d22018-09-25 18:10:19 +02003894 # look for primitive
tierno59d22d22018-09-25 18:10:19 +02003895 for config_primitive in db_vnfd.get("vnf-configuration", {}).get("config-primitive", ()):
3896 if config_primitive["name"] == vnf_config_primitive:
tierno59d22d22018-09-25 18:10:19 +02003897 break
3898 else:
tiernoa278b842020-07-08 15:33:55 +00003899 raise LcmException(
3900 "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-"
3901 "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:"
3902 "config-primitive".format(scaling_group, vnf_config_primitive))
tierno9ab95942018-10-10 16:44:22 +02003903 scale_process = "VCA"
tiernod6de1992018-10-11 13:05:52 +02003904 db_nsr_update["config-status"] = "configuring post-scaling"
kuuseac3a8882019-10-03 10:48:06 +02003905 primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params)
tiernod6de1992018-10-11 13:05:52 +02003906
tierno7c4e24c2020-05-13 08:41:35 +00003907 # Post-scale retry check: Check if this sub-operation has been executed before
kuuseac3a8882019-10-03 10:48:06 +02003908 op_index = self._check_or_add_scale_suboperation(
3909 db_nslcmop, nslcmop_id, vnf_index, vnf_config_primitive, primitive_params, 'POST-SCALE')
quilesj4cda56b2019-12-05 10:02:20 +00003910 if op_index == self.SUBOPERATION_STATUS_SKIP:
kuuseac3a8882019-10-03 10:48:06 +02003911 # Skip sub-operation
3912 result = 'COMPLETED'
3913 result_detail = 'Done'
3914 self.logger.debug(logging_text +
3915 "vnf_config_primitive={} Skipped sub-operation, result {} {}".
3916 format(vnf_config_primitive, result, result_detail))
3917 else:
quilesj4cda56b2019-12-05 10:02:20 +00003918 if op_index == self.SUBOPERATION_STATUS_NEW:
kuuseac3a8882019-10-03 10:48:06 +02003919 # New sub-operation: Get index of this sub-operation
3920 op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
3921 self.logger.debug(logging_text + "vnf_config_primitive={} New sub-operation".
3922 format(vnf_config_primitive))
3923 else:
tierno7c4e24c2020-05-13 08:41:35 +00003924 # retry: Get registered params for this existing sub-operation
kuuseac3a8882019-10-03 10:48:06 +02003925 op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
3926 vnf_index = op.get('member_vnf_index')
3927 vnf_config_primitive = op.get('primitive')
3928 primitive_params = op.get('primitive_params')
tierno7c4e24c2020-05-13 08:41:35 +00003929 self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry".
kuuseac3a8882019-10-03 10:48:06 +02003930 format(vnf_config_primitive))
tierno588547c2020-07-01 15:30:20 +00003931 # Execute the primitive, either with new (first-time) or registered (reintent) args
tiernoa278b842020-07-08 15:33:55 +00003932 ee_descriptor_id = config_primitive.get("execution-environment-ref")
3933 primitive_name = config_primitive.get("execution-environment-primitive",
3934 vnf_config_primitive)
tierno588547c2020-07-01 15:30:20 +00003935 ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"],
3936 member_vnf_index=vnf_index,
3937 vdu_id=None,
tiernoa278b842020-07-08 15:33:55 +00003938 vdu_count_index=None,
3939 ee_descriptor_id=ee_descriptor_id)
kuuseac3a8882019-10-03 10:48:06 +02003940 result, result_detail = await self._ns_execute_primitive(
tiernoa278b842020-07-08 15:33:55 +00003941 ee_id, primitive_name, primitive_params, vca_type)
kuuseac3a8882019-10-03 10:48:06 +02003942 self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format(
3943 vnf_config_primitive, result, result_detail))
3944 # Update operationState = COMPLETED | FAILED
3945 self._update_suboperation_status(
3946 db_nslcmop, op_index, result, result_detail)
3947
tierno59d22d22018-09-25 18:10:19 +02003948 if result == "FAILED":
3949 raise LcmException(result_detail)
tiernod6de1992018-10-11 13:05:52 +02003950 db_nsr_update["config-status"] = old_config_status
3951 scale_process = None
kuuseac3a8882019-10-03 10:48:06 +02003952 # POST-SCALE END
tierno59d22d22018-09-25 18:10:19 +02003953
tiernod6de1992018-10-11 13:05:52 +02003954 db_nsr_update["detailed-status"] = "" # "scaled {} {}".format(scaling_group, scaling_type)
ikalyvas02d9e7b2019-05-27 18:16:01 +03003955 db_nsr_update["operational-status"] = "running" if old_operational_status == "failed" \
3956 else old_operational_status
tiernod6de1992018-10-11 13:05:52 +02003957 db_nsr_update["config-status"] = old_config_status
tierno59d22d22018-09-25 18:10:19 +02003958 return
tierno2357f4e2020-10-19 16:38:59 +00003959 except (ROclient.ROClientException, DbException, LcmException, NgRoException) as e:
tierno59d22d22018-09-25 18:10:19 +02003960 self.logger.error(logging_text + "Exit Exception {}".format(e))
3961 exc = e
3962 except asyncio.CancelledError:
3963 self.logger.error(logging_text + "Cancelled Exception while '{}'".format(step))
3964 exc = "Operation was cancelled"
3965 except Exception as e:
3966 exc = traceback.format_exc()
3967 self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
3968 finally:
bravof922c4172020-11-24 21:21:43 -03003969 self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE", current_operation_id=None)
tierno59d22d22018-09-25 18:10:19 +02003970 if exc:
tiernoa17d4f42020-04-28 09:59:23 +00003971 db_nslcmop_update["detailed-status"] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
3972 nslcmop_operation_state = "FAILED"
tierno59d22d22018-09-25 18:10:19 +02003973 if db_nsr:
tiernod6de1992018-10-11 13:05:52 +02003974 db_nsr_update["operational-status"] = old_operational_status
3975 db_nsr_update["config-status"] = old_config_status
3976 db_nsr_update["detailed-status"] = ""
3977 if scale_process:
3978 if "VCA" in scale_process:
3979 db_nsr_update["config-status"] = "failed"
3980 if "RO" in scale_process:
3981 db_nsr_update["operational-status"] = "failed"
3982 db_nsr_update["detailed-status"] = "FAILED scaling nslcmop={} {}: {}".format(nslcmop_id, step,
3983 exc)
tiernoa17d4f42020-04-28 09:59:23 +00003984 else:
3985 error_description_nslcmop = None
3986 nslcmop_operation_state = "COMPLETED"
3987 db_nslcmop_update["detailed-status"] = "Done"
quilesj4cda56b2019-12-05 10:02:20 +00003988
bravof922c4172020-11-24 21:21:43 -03003989 self._write_op_status(op_id=nslcmop_id, stage="", error_message=error_description_nslcmop,
3990 operation_state=nslcmop_operation_state, other_update=db_nslcmop_update)
tiernoa17d4f42020-04-28 09:59:23 +00003991 if db_nsr:
bravof922c4172020-11-24 21:21:43 -03003992 self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE",
3993 current_operation_id=None, other_update=db_nsr_update)
tiernoa17d4f42020-04-28 09:59:23 +00003994
tierno59d22d22018-09-25 18:10:19 +02003995 if nslcmop_operation_state:
3996 try:
bravof922c4172020-11-24 21:21:43 -03003997 msg = {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id, "operationState": nslcmop_operation_state}
3998 await self.msg.aiowrite("ns", "scaled", msg, loop=self.loop)
tierno59d22d22018-09-25 18:10:19 +02003999 except Exception as e:
4000 self.logger.error(logging_text + "kafka_write notification Exception {}".format(e))
4001 self.logger.debug(logging_text + "Exit")
4002 self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
tiernob996d942020-07-03 14:52:28 +00004003
tierno2357f4e2020-10-19 16:38:59 +00004004 async def _scale_ng_ro(self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage):
4005 nsr_id = db_nslcmop["nsInstanceId"]
4006 db_nsd = self.db.get_one("nsds", {"_id": db_nsr["nsd-id"]})
4007 db_vnfrs = {}
4008
4009 # read from db: vnfd's for every vnf
bravof832f8992020-12-07 12:57:31 -03004010 db_vnfds = []
tierno2357f4e2020-10-19 16:38:59 +00004011
4012 # for each vnf in ns, read vnfd
4013 for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
4014 db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
4015 vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf
tierno2357f4e2020-10-19 16:38:59 +00004016 # if we haven't this vnfd, read it from db
bravof832f8992020-12-07 12:57:31 -03004017 if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
tierno2357f4e2020-10-19 16:38:59 +00004018 # read from db
4019 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
bravof832f8992020-12-07 12:57:31 -03004020 db_vnfds.append(vnfd)
tierno2357f4e2020-10-19 16:38:59 +00004021 n2vc_key = self.n2vc.get_public_key()
4022 n2vc_key_list = [n2vc_key]
4023 self.scale_vnfr(db_vnfr, vdu_scaling_info.get("vdu-create"), vdu_scaling_info.get("vdu-delete"),
4024 mark_delete=True)
4025 # db_vnfr has been updated, update db_vnfrs to use it
4026 db_vnfrs[db_vnfr["member-vnf-index-ref"]] = db_vnfr
4027 await self._instantiate_ng_ro(logging_text, nsr_id, db_nsd, db_nsr, db_nslcmop, db_vnfrs,
bravof922c4172020-11-24 21:21:43 -03004028 db_vnfds, n2vc_key_list, stage=stage, start_deploy=time(),
tierno2357f4e2020-10-19 16:38:59 +00004029 timeout_ns_deploy=self.timeout_ns_deploy)
4030 if vdu_scaling_info.get("vdu-delete"):
4031 self.scale_vnfr(db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False)
4032
tiernob996d942020-07-03 14:52:28 +00004033 async def add_prometheus_metrics(self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip):
4034 if not self.prometheus:
4035 return
4036 # look if exist a file called 'prometheus*.j2' and
4037 artifact_content = self.fs.dir_ls(artifact_path)
4038 job_file = next((f for f in artifact_content if f.startswith("prometheus") and f.endswith(".j2")), None)
4039 if not job_file:
4040 return
4041 with self.fs.file_open((artifact_path, job_file), "r") as f:
4042 job_data = f.read()
4043
4044 # TODO get_service
4045 _, _, service = ee_id.partition(".") # remove prefix "namespace."
4046 host_name = "{}-{}".format(service, ee_config_descriptor["metric-service"])
4047 host_port = "80"
4048 vnfr_id = vnfr_id.replace("-", "")
4049 variables = {
4050 "JOB_NAME": vnfr_id,
4051 "TARGET_IP": target_ip,
4052 "EXPORTER_POD_IP": host_name,
4053 "EXPORTER_POD_PORT": host_port,
4054 }
4055 job_list = self.prometheus.parse_job(job_data, variables)
4056 # ensure job_name is using the vnfr_id. Adding the metadata nsr_id
4057 for job in job_list:
4058 if not isinstance(job.get("job_name"), str) or vnfr_id not in job["job_name"]:
4059 job["job_name"] = vnfr_id + "_" + str(randint(1, 10000))
4060 job["nsr_id"] = nsr_id
4061 job_dict = {jl["job_name"]: jl for jl in job_list}
4062 if await self.prometheus.update(job_dict):
4063 return list(job_dict.keys())
David Garciaaae391f2020-11-09 11:12:54 +01004064
4065 def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
4066 """
4067 Get VCA Cloud and VCA Cloud Credentials for the VIM account
4068
4069 :param: vim_account_id: VIM Account ID
4070
4071 :return: (cloud_name, cloud_credential)
4072 """
bravof922c4172020-11-24 21:21:43 -03004073 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01004074 return config.get("vca_cloud"), config.get("vca_cloud_credential")
4075
4076 def get_vca_k8s_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
4077 """
4078 Get VCA K8s Cloud and VCA K8s Cloud Credentials for the VIM account
4079
4080 :param: vim_account_id: VIM Account ID
4081
4082 :return: (cloud_name, cloud_credential)
4083 """
bravof922c4172020-11-24 21:21:43 -03004084 config = VimAccountDB.get_vim_account_with_id(vim_account_id).get("config", {})
David Garciaaae391f2020-11-09 11:12:54 +01004085 return config.get("vca_k8s_cloud"), config.get("vca_k8s_cloud_credential")