X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_lcm%2Fns.py;h=4bed2c6523609b3655ce050fa11dc45304d62532;hb=aebd7da39850e4e7edac17417350256a2a571ec4;hp=62f010f1b25800b297c673eeb10205b881b9e0d7;hpb=b996d94c0f74b1922d7f93a51ec328c6f370ff86;p=osm%2FLCM.git diff --git a/osm_lcm/ns.py b/osm_lcm/ns.py index 62f010f..4bed2c6 100644 --- a/osm_lcm/ns.py +++ b/osm_lcm/ns.py @@ -42,7 +42,7 @@ from copy import copy, deepcopy from http import HTTPStatus from time import time from uuid import uuid4 -from functools import partial + from random import randint __author__ = "Alfonso Tierno " @@ -56,7 +56,7 @@ class N2VCJujuConnectorLCM(N2VCJujuConnector): vca_type: str = None) -> (str, dict): # admit two new parameters, artifact_path and vca_type if vca_type == "k8s_proxy_charm": - ee_id = await self.n2vc.install_k8s_proxy_charm( + ee_id = await self.install_k8s_proxy_charm( charm_name=artifact_path[artifact_path.rfind("/") + 1:], namespace=namespace, artifact_path=artifact_path, @@ -785,19 +785,27 @@ class NsLcm(LcmBase): return ns_config_info @staticmethod - def _get_initial_config_primitive_list(desc_primitive_list, vca_deployed): + def _get_initial_config_primitive_list(desc_primitive_list, vca_deployed, ee_descriptor_id): """ Generates a list of initial-config-primitive based on the list provided by the descriptor. It includes internal primitives as verify-ssh-credentials, or config when needed :param desc_primitive_list: information of the descriptor :param vca_deployed: information of the deployed, needed for known if it is related to an NS, VNF, VDU and if this element contains a ssh public key + :param ee_descriptor_id: execution environment descriptor id. It is the value of + XXX_configuration.execution-environment-list.INDEX.id; it can be None :return: The modified list. Can ba an empty list, but always a list """ - if desc_primitive_list: - primitive_list = desc_primitive_list.copy() - else: - primitive_list = [] + + primitive_list = desc_primitive_list or [] + + # filter primitives by ee_id + primitive_list = [p for p in primitive_list if p.get("execution-environment-ref") == ee_descriptor_id] + + # sort by 'seq' + if primitive_list: + primitive_list.sort(key=lambda val: int(val['seq'])) + # look for primitive config, and get the position. None if not present config_position = None for index, primitive in enumerate(primitive_list): @@ -809,7 +817,7 @@ class NsLcm(LcmBase): if not vca_deployed["member-vnf-index"] and config_position is None: primitive_list.insert(0, {"name": "config", "parameter": []}) config_position = 0 - # for VNF/VDU add verify-ssh-credentials after config + # TODO revise if needed: for VNF/VDU add verify-ssh-credentials after config if vca_deployed["member-vnf-index"] and config_position is not None and vca_deployed.get("ssh-public-key"): primitive_list.insert(config_position + 1, {"name": "verify-ssh-credentials", "parameter": []}) return primitive_list @@ -1422,9 +1430,15 @@ class NsLcm(LcmBase): "charms" if vca_type in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm") else "helm-charts", vca_name ) + # get initial_config_primitive_list that applies to this element + initial_config_primitive_list = config_descriptor.get('initial-config-primitive') - # n2vc_redesign STEP 3.1 + # add config if not present for NS charm + ee_descriptor_id = ee_config_descriptor.get("id") + initial_config_primitive_list = self._get_initial_config_primitive_list(initial_config_primitive_list, + vca_deployed, ee_descriptor_id) + # n2vc_redesign STEP 3.1 # find old ee_id if exists ee_id = vca_deployed.get("ee_id") @@ -1459,14 +1473,14 @@ class NsLcm(LcmBase): username = deep_get(config_descriptor, ("config-access", "ssh-access", "default-user")) # TODO remove this when changes on IM regarding config-access:ssh-access:default-user were # merged. Meanwhile let's get username from initial-config-primitive - if not username and config_descriptor.get("initial-config-primitive"): - for config_primitive in config_descriptor["initial-config-primitive"]: + if not username and initial_config_primitive_list: + for config_primitive in initial_config_primitive_list: for param in config_primitive.get("parameter", ()): if param["name"] == "ssh-username": username = param["value"] break if not username: - raise LcmException("Cannot determine the username neither with 'initial-config-promitive' nor with " + raise LcmException("Cannot determine the username neither with 'initial-config-primitive' nor with " "'config-access.ssh-access.default-user'") credentials["username"] = username # n2vc_redesign STEP 3.2 @@ -1510,16 +1524,13 @@ class NsLcm(LcmBase): self.logger.debug(logging_text + step) config = None if vca_type == "native_charm": - initial_config_primitive_list = config_descriptor.get('initial-config-primitive') - if initial_config_primitive_list: - for primitive in initial_config_primitive_list: - if primitive["name"] == "config": - config = self._map_primitive_params( - primitive, - {}, - deploy_params - ) - break + config_primitive = next((p for p in initial_config_primitive_list if p["name"] == "config"), None) + if config_primitive: + config = self._map_primitive_params( + config_primitive, + {}, + deploy_params + ) num_units = 1 if vca_type == "lxc_proxy_charm": if element_type == "NS": @@ -1549,7 +1560,8 @@ class NsLcm(LcmBase): vca_index=vca_index, vca_type=vca_type) # if SSH access is required, then get execution environment SSH public - if vca_type in ("lxc_proxy_charm", "helm"): # if native charm we have waited already to VM be UP + # if native charm we have waited already to VM be UP + if vca_type in ("k8s_proxy_charm", "lxc_proxy_charm", "helm"): pub_key = None user = None # self.logger.debug("get ssh key block") @@ -1581,20 +1593,6 @@ class NsLcm(LcmBase): # n2vc_redesign STEP 6 Execute initial config primitive step = 'execute initial config primitive' - initial_config_primitive_list = config_descriptor.get('initial-config-primitive') - - # sort initial config primitives by 'seq' - if initial_config_primitive_list: - try: - initial_config_primitive_list.sort(key=lambda val: int(val['seq'])) - except Exception as e: - self.logger.error(logging_text + step + ": " + str(e)) - else: - self.logger.debug(logging_text + step + ": No initial-config-primitive") - - # add config if not present for NS charm - initial_config_primitive_list = self._get_initial_config_primitive_list(initial_config_primitive_list, - vca_deployed) # wait for dependent primitives execution (NS -> VNF -> VDU) if initial_config_primitive_list: @@ -1827,9 +1825,6 @@ class NsLcm(LcmBase): logging_text = "Task ns={} instantiate={} ".format(nsr_id, nslcmop_id) self.logger.debug(logging_text + "Enter") - # Sync from FSMongo - self.fs.sync() - # get all needed from database # database nsrs record @@ -1855,8 +1850,11 @@ class NsLcm(LcmBase): # wait for any previous tasks in process await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id) + stage[1] = "Sync filesystem from database" + self.fs.sync() # TODO, make use of partial sync, only for the needed packages + # STEP 0: Reading database (nslcmops, nsrs, nsds, vnfrs, vnfds) - stage[1] = "Reading from database," + stage[1] = "Reading from database" # nsState="BUILDING", currentOperation="INSTANTIATING", currentOperationID=nslcmop_id db_nsr_update["detailed-status"] = "creating" db_nsr_update["operational-status"] = "init" @@ -1905,6 +1903,7 @@ class NsLcm(LcmBase): db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr # vnf's dict indexed by member-index: '1', '2', etc vnfd_id = vnfr["vnfd-id"] # vnfd uuid for this vnf vnfd_ref = vnfr["vnfd-ref"] # vnfd name for this vnf + # if we haven't this vnfd, read it from db if vnfd_id not in db_vnfds: # read from db @@ -1941,6 +1940,7 @@ class NsLcm(LcmBase): # set state to INSTANTIATED. When instantiated NBI will not delete directly db_nsr_update["_admin.nsState"] = "INSTANTIATED" self.update_db_2("nsrs", nsr_id, db_nsr_update) + self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "INSTANTIATED"}) # n2vc_redesign STEP 2 Deploy Network Scenario stage[0] = 'Stage 2/5: deployment of KDUs, VMs and execution environments.' @@ -2397,41 +2397,96 @@ class NsLcm(LcmBase): self.logger.warn(logging_text + ' ERROR adding relations: {}'.format(e)) return False - def _write_db_callback(self, task, item, _id, on_done=None, on_exc=None): - """ - callback for kdu install intended to store the returned kdu_instance at database - :return: None - """ - db_update = {} + async def _install_kdu(self, nsr_id: str, nsr_db_path: str, vnfr_data: dict, kdu_index: int, kdur: dict, kdud: dict, + vnfd: dict, k8s_instance_info: dict, k8params: dict = None, timeout: int = 600): + try: - result = task.result() - if on_done: - db_update[on_done] = str(result) + k8sclustertype = k8s_instance_info["k8scluster-type"] + # Instantiate kdu + db_dict_install = {"collection": "nsrs", + "filter": {"_id": nsr_id}, + "path": nsr_db_path} + + kdu_instance = await self.k8scluster_map[k8sclustertype].install( + cluster_uuid=k8s_instance_info["k8scluster-uuid"], + kdu_model=k8s_instance_info["kdu-model"], + atomic=True, + params=k8params, + db_dict=db_dict_install, + timeout=timeout, + kdu_name=k8s_instance_info["kdu-name"], + namespace=k8s_instance_info["namespace"]) + self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance}) + + # Obtain services to obtain management service ip + services = await self.k8scluster_map[k8sclustertype].get_services( + cluster_uuid=k8s_instance_info["k8scluster-uuid"], + kdu_instance=kdu_instance, + namespace=k8s_instance_info["namespace"]) + + # Obtain management service info (if exists) + if services: + vnfr_update_dict = {"kdur.{}.services".format(kdu_index): services} + mgmt_services = [service for service in kdud.get("service", []) if service.get("mgmt-service")] + for mgmt_service in mgmt_services: + for service in services: + if service["name"].startswith(mgmt_service["name"]): + # Mgmt service found, Obtain service ip + ip = service.get("external_ip", service.get("cluster_ip")) + if isinstance(ip, list) and len(ip) == 1: + ip = ip[0] + + vnfr_update_dict["kdur.{}.ip-address".format(kdu_index)] = ip + + # Check if must update also mgmt ip at the vnf + service_external_cp = mgmt_service.get("external-connection-point-ref") + if service_external_cp: + if deep_get(vnfd, ("mgmt-interface", "cp")) == service_external_cp: + vnfr_update_dict["ip-address"] = ip + + break + else: + self.logger.warn("Mgmt service name: {} not found".format(mgmt_service["name"])) + + self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict) + except Exception as e: - if on_exc: - db_update[on_exc] = str(e) - if db_update: + # Prepare update db with error and raise exception try: - self.update_db_2(item, _id, db_update) + self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".detailed-status": str(e)}) except Exception: + # ignore to keep original exception pass + # reraise original error + raise + + return kdu_instance async def deploy_kdus(self, logging_text, nsr_id, nslcmop_id, db_vnfrs, db_vnfds, task_instantiation_info): # Launch kdus if present in the descriptor k8scluster_id_2_uuic = {"helm-chart": {}, "juju-bundle": {}} - def _get_cluster_id(cluster_id, cluster_type): + async def _get_cluster_id(cluster_id, cluster_type): nonlocal k8scluster_id_2_uuic if cluster_id in k8scluster_id_2_uuic[cluster_type]: return k8scluster_id_2_uuic[cluster_type][cluster_id] + # check if K8scluster is creating and wait look if previous tasks in process + task_name, task_dependency = self.lcm_tasks.lookfor_related("k8scluster", cluster_id) + if task_dependency: + text = "Waiting for related tasks '{}' on k8scluster {} to be completed".format(task_name, cluster_id) + self.logger.debug(logging_text + text) + await asyncio.wait(task_dependency, timeout=3600) + db_k8scluster = self.db.get_one("k8sclusters", {"_id": cluster_id}, fail_on_empty=False) if not db_k8scluster: raise LcmException("K8s cluster {} cannot be found".format(cluster_id)) + k8s_id = deep_get(db_k8scluster, ("_admin", cluster_type, "id")) if not k8s_id: - raise LcmException("K8s cluster '{}' has not been initilized for '{}'".format(cluster_id, cluster_type)) + raise LcmException("K8s cluster '{}' has not been initialized for '{}'".format(cluster_id, + cluster_type)) k8scluster_id_2_uuic[cluster_type][cluster_id] = k8s_id return k8s_id @@ -2445,9 +2500,11 @@ class NsLcm(LcmBase): updated_cluster_list = [] for vnfr_data in db_vnfrs.values(): - for kdur in get_iterable(vnfr_data, "kdur"): + for kdu_index, kdur in enumerate(get_iterable(vnfr_data, "kdur")): + # Step 0: Prepare and set parameters desc_params = self._format_additional_params(kdur.get("additionalParams")) vnfd_id = vnfr_data.get('vnfd-id') + kdud = next(kdud for kdud in db_vnfds[vnfd_id]["kdu"] if kdud["name"] == kdur["kdu-name"]) namespace = kdur.get("k8s-namespace") if kdur.get("helm-chart"): kdumodel = kdur["helm-chart"] @@ -2475,8 +2532,9 @@ class NsLcm(LcmBase): k8s_cluster_id = kdur["k8s-cluster"]["id"] step = "Synchronize repos for k8s cluster '{}'".format(k8s_cluster_id) - cluster_uuid = _get_cluster_id(k8s_cluster_id, k8sclustertype) + cluster_uuid = await _get_cluster_id(k8s_cluster_id, k8sclustertype) + # Synchronize repos if k8sclustertype == "helm-chart" and cluster_uuid not in updated_cluster_list: del_repo_list, added_repo_dict = await asyncio.ensure_future( self.k8sclusterhelm.synchronize_repos(cluster_uuid=cluster_uuid)) @@ -2490,33 +2548,23 @@ class NsLcm(LcmBase): self.db.set_one("k8sclusters", {"_id": k8s_cluster_id}, updated, unset=unset) updated_cluster_list.append(cluster_uuid) + # Instantiate kdu step = "Instantiating KDU {}.{} in k8s cluster {}".format(vnfr_data["member-vnf-index-ref"], kdur["kdu-name"], k8s_cluster_id) - - k8s_instace_info = {"kdu-instance": None, - "k8scluster-uuid": cluster_uuid, - "k8scluster-type": k8sclustertype, - "member-vnf-index": vnfr_data["member-vnf-index-ref"], - "kdu-name": kdur["kdu-name"], - "kdu-model": kdumodel, - "namespace": namespace} + k8s_instance_info = {"kdu-instance": None, + "k8scluster-uuid": cluster_uuid, + "k8scluster-type": k8sclustertype, + "member-vnf-index": vnfr_data["member-vnf-index-ref"], + "kdu-name": kdur["kdu-name"], + "kdu-model": kdumodel, + "namespace": namespace} db_path = "_admin.deployed.K8s.{}".format(index) - db_nsr_update[db_path] = k8s_instace_info + db_nsr_update[db_path] = k8s_instance_info self.update_db_2("nsrs", nsr_id, db_nsr_update) - db_dict = {"collection": "nsrs", - "filter": {"_id": nsr_id}, - "path": db_path} - task = asyncio.ensure_future( - self.k8scluster_map[k8sclustertype].install(cluster_uuid=cluster_uuid, kdu_model=kdumodel, - atomic=True, params=desc_params, - db_dict=db_dict, timeout=600, - kdu_name=kdur["kdu-name"], namespace=namespace)) - - task.add_done_callback(partial(self._write_db_callback, item="nsrs", _id=nsr_id, - on_done=db_path + ".kdu-instance", - on_exc=db_path + ".detailed-status")) + self._install_kdu(nsr_id, db_path, vnfr_data, kdu_index, kdur, kdud, db_vnfds[vnfd_id], + k8s_instance_info, k8params=desc_params, timeout=600)) self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "instantiate_KDU-{}".format(index), task) task_instantiation_info[task] = "Deploying KDU {}".format(kdur["kdu-name"]) @@ -2554,6 +2602,7 @@ class NsLcm(LcmBase): for ee_item in ee_list: self.logger.debug(logging_text + "_deploy_n2vc ee_item juju={}, helm={}".format(ee_item.get('juju'), ee_item.get("helm-chart"))) + ee_descriptor_id = ee_item.get("id") if ee_item.get("juju"): vca_name = ee_item['juju'].get('charm') vca_type = "lxc_proxy_charm" if ee_item['juju'].get('charm') is not None else "native_charm" @@ -2575,11 +2624,19 @@ class NsLcm(LcmBase): if vca_deployed.get("member-vnf-index") == member_vnf_index and \ vca_deployed.get("vdu_id") == vdu_id and \ vca_deployed.get("kdu_name") == kdu_name and \ - vca_deployed.get("vdu_count_index", 0) == vdu_index: + vca_deployed.get("vdu_count_index", 0) == vdu_index and \ + vca_deployed.get("ee_descriptor_id") == ee_descriptor_id: break else: # not found, create one. + target = "ns" if not member_vnf_index else "vnf/{}".format(member_vnf_index) + if vdu_id: + target += "/vdu/{}/{}".format(vdu_id, vdu_index or 0) + elif kdu_name: + target += "/kdu/{}".format(kdu_name) vca_deployed = { + "target_element": target, + # ^ target_element will replace member-vnf-index, kdu_name, vdu_id ... in a single string "member-vnf-index": member_vnf_index, "vdu_id": vdu_id, "kdu_name": kdu_name, @@ -2589,7 +2646,8 @@ class NsLcm(LcmBase): "step": "initial-deploy", # TODO revise "vnfd_id": vnfd_id, "vdu_name": vdu_name, - "type": vca_type + "type": vca_type, + "ee_descriptor_id": ee_descriptor_id } vca_index += 1 @@ -2627,23 +2685,20 @@ class NsLcm(LcmBase): task_instantiation_info[task_n2vc] = self.task_name_deploy_vca + " {}.{}".format( member_vnf_index or "", vdu_id or "") - # Check if this VNFD has a configured terminate action - def _has_terminate_config_primitive(self, vnfd): - vnf_config = vnfd.get("vnf-configuration") - if vnf_config and vnf_config.get("terminate-config-primitive"): - return True - else: - return False - @staticmethod - def _get_terminate_config_primitive_seq_list(vnfd): - """ Get a numerically sorted list of the sequences for this VNFD's terminate action """ - # No need to check for existing primitive twice, already done before - vnf_config = vnfd.get("vnf-configuration") - seq_list = vnf_config.get("terminate-config-primitive") - # Get all 'seq' tags in seq_list, order sequences numerically, ascending. - seq_list_sorted = sorted(seq_list, key=lambda x: int(x['seq'])) - return seq_list_sorted + def _get_terminate_config_primitive(primitive_list, vca_deployed): + """ Get a sorted terminate config primitive list. In case ee_descriptor_id is present at vca_deployed, + it get only those primitives for this execution envirom""" + + primitive_list = primitive_list or [] + # filter primitives by ee_descriptor_id + ee_descriptor_id = vca_deployed.get("ee_descriptor_id") + primitive_list = [p for p in primitive_list if p.get("execution-environment-ref") == ee_descriptor_id] + + if primitive_list: + primitive_list.sort(key=lambda val: int(val['seq'])) + + return primitive_list @staticmethod def _create_nslcmop(nsr_id, operation, params): @@ -2877,14 +2932,13 @@ class NsLcm(LcmBase): # execute terminate_primitives if exec_primitives: - terminate_primitives = config_descriptor.get("terminate-config-primitive") + terminate_primitives = self._get_terminate_config_primitive( + config_descriptor.get("terminate-config-primitive"), vca_deployed) vdu_id = vca_deployed.get("vdu_id") vdu_count_index = vca_deployed.get("vdu_count_index") vdu_name = vca_deployed.get("vdu_name") vnf_index = vca_deployed.get("member-vnf-index") if terminate_primitives and vca_deployed.get("needed_terminate"): - # Get all 'seq' tags in seq_list, order sequences numerically, ascending. - terminate_primitives = sorted(terminate_primitives, key=lambda x: int(x['seq'])) for seq in terminate_primitives: # For each sequence in list, get primitive and call _ns_execute_primitive() step = "Calling terminate action for vnf_member_index={} primitive={}".format( @@ -2893,8 +2947,6 @@ class NsLcm(LcmBase): # Create the primitive for each sequence, i.e. "primitive": "touch" primitive = seq.get('name') mapped_primitive_params = self._get_terminate_primitive_params(seq, vnf_index) - # The following 3 parameters are currently set to None for 'terminate': - # vdu_id, vdu_count_index, vdu_name # Add sub-operation self._add_suboperation(db_nslcmop, @@ -3173,8 +3225,9 @@ class NsLcm(LcmBase): vca_type = vca.get("type") exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and vca.get("needed_terminate")) - # For helm we must destroy_ee - destroy_ee = "True" if vca_type == "helm" else "False" + # For helm we must destroy_ee. Also for native_charm, as juju_model cannot be deleted if there are + # pending native charms + destroy_ee = "True" if vca_type in ("helm", "native_charm") else "False" task = asyncio.ensure_future( self.destroy_N2VC(logging_text, db_nslcmop, vca, config_descriptor, vca_index, destroy_ee, exec_terminate_primitives)) @@ -3296,6 +3349,12 @@ class NsLcm(LcmBase): operation_state=nslcmop_operation_state, other_update=db_nslcmop_update, ) + if ns_state == "NOT_INSTANTIATED": + try: + self.db.set_list("vnfrs", {"nsr-id-ref": nsr_id}, {"_admin.nsState": "NOT_INSTANTIATED"}) + except DbException as e: + self.logger.warn(logging_text + 'Error writing VNFR status for nsr-id-ref: {} -> {}'. + format(nsr_id, e)) if operation_params: autoremove = operation_params.get("autoremove", False) if nslcmop_operation_state: @@ -3402,7 +3461,8 @@ class NsLcm(LcmBase): calculated_params["ns_config_info"] = instantiation_params["ns_config_info"] return calculated_params - def _look_for_deployed_vca(self, deployed_vca, member_vnf_index, vdu_id, vdu_count_index, kdu_name=None): + def _look_for_deployed_vca(self, deployed_vca, member_vnf_index, vdu_id, vdu_count_index, kdu_name=None, + ee_descriptor_id=None): # find vca_deployed record for this action. Raise LcmException if not found or there is not any id. for vca in deployed_vca: if not vca: @@ -3413,11 +3473,14 @@ class NsLcm(LcmBase): continue if kdu_name and kdu_name != vca["kdu_name"]: continue + if ee_descriptor_id and ee_descriptor_id != vca["ee_descriptor_id"]: + continue break else: # vca_deployed not found - raise LcmException("charm for member_vnf_index={} vdu_id={} kdu_name={} vdu_count_index={} is not " - "deployed".format(member_vnf_index, vdu_id, kdu_name, vdu_count_index)) + raise LcmException("charm for member_vnf_index={} vdu_id={}.{} kdu_name={} execution-environment-list.id={}" + " is not deployed".format(member_vnf_index, vdu_id, vdu_count_index, kdu_name, + ee_descriptor_id)) # get ee_id ee_id = vca.get("ee_id") @@ -3528,37 +3591,37 @@ class NsLcm(LcmBase): self.update_db_2("nsrs", nsr_id, db_nsr_update) # look for primitive - config_primitive_desc = None + config_primitive_desc = descriptor_configuration = None if vdu_id: for vdu in get_iterable(db_vnfd, "vdu"): if vdu_id == vdu["id"]: - for config_primitive in deep_get(vdu, ("vdu-configuration", "config-primitive"), ()): - if config_primitive["name"] == primitive: - config_primitive_desc = config_primitive - break + descriptor_configuration = vdu.get("vdu-configuration") break elif kdu_name: for kdu in get_iterable(db_vnfd, "kdu"): if kdu_name == kdu["name"]: - for config_primitive in deep_get(kdu, ("kdu-configuration", "config-primitive"), ()): - if config_primitive["name"] == primitive: - config_primitive_desc = config_primitive - break + descriptor_configuration = kdu.get("kdu-configuration") break elif vnf_index: - for config_primitive in deep_get(db_vnfd, ("vnf-configuration", "config-primitive"), ()): - if config_primitive["name"] == primitive: - config_primitive_desc = config_primitive - break + descriptor_configuration = db_vnfd.get("vnf-configuration") else: - for config_primitive in deep_get(db_nsd, ("ns-configuration", "config-primitive"), ()): + descriptor_configuration = db_nsd.get("ns-configuration") + + if descriptor_configuration and descriptor_configuration.get("config-primitive"): + for config_primitive in descriptor_configuration["config-primitive"]: if config_primitive["name"] == primitive: config_primitive_desc = config_primitive break - if not config_primitive_desc and not (kdu_name and primitive in ("upgrade", "rollback", "status")): - raise LcmException("Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ". - format(primitive)) + if not config_primitive_desc: + if not (kdu_name and primitive in ("upgrade", "rollback", "status")): + raise LcmException("Primitive {} not found at [ns|vnf|vdu]-configuration:config-primitive ". + format(primitive)) + primitive_name = primitive + ee_descriptor_id = None + else: + primitive_name = config_primitive_desc.get("execution-environment-primitive", primitive) + ee_descriptor_id = config_primitive_desc.get("execution-environment-ref") if vnf_index: if vdu_id: @@ -3576,7 +3639,7 @@ class NsLcm(LcmBase): kdu_action = True if not deep_get(kdu, ("kdu-configuration", "juju")) else False # TODO check if ns is in a proper status - if kdu_name and (primitive in ("upgrade", "rollback", "status") or kdu_action): + if kdu_name and (primitive_name in ("upgrade", "rollback", "status") or kdu_action): # kdur and desc_params already set from before if primitive_params: desc_params.update(primitive_params) @@ -3594,9 +3657,9 @@ class NsLcm(LcmBase): db_dict = {"collection": "nsrs", "filter": {"_id": nsr_id}, "path": "_admin.deployed.K8s.{}".format(index)} - self.logger.debug(logging_text + "Exec k8s {} on {}.{}".format(primitive, vnf_index, kdu_name)) - step = "Executing kdu {}".format(primitive) - if primitive == "upgrade": + self.logger.debug(logging_text + "Exec k8s {} on {}.{}".format(primitive_name, vnf_index, kdu_name)) + step = "Executing kdu {}".format(primitive_name) + if primitive_name == "upgrade": if desc_params.get("kdu_model"): kdu_model = desc_params.get("kdu_model") del desc_params["kdu_model"] @@ -3615,14 +3678,14 @@ class NsLcm(LcmBase): timeout=timeout_ns_action), timeout=timeout_ns_action + 10) self.logger.debug(logging_text + " Upgrade of kdu {} done".format(detailed_status)) - elif primitive == "rollback": + elif primitive_name == "rollback": detailed_status = await asyncio.wait_for( self.k8scluster_map[kdu["k8scluster-type"]].rollback( cluster_uuid=kdu.get("k8scluster-uuid"), kdu_instance=kdu.get("kdu-instance"), db_dict=db_dict), timeout=timeout_ns_action) - elif primitive == "status": + elif primitive_name == "status": detailed_status = await asyncio.wait_for( self.k8scluster_map[kdu["k8scluster-type"]].status_kdu( cluster_uuid=kdu.get("k8scluster-uuid"), @@ -3636,7 +3699,7 @@ class NsLcm(LcmBase): self.k8scluster_map[kdu["k8scluster-type"]].exec_primitive( cluster_uuid=kdu.get("k8scluster-uuid"), kdu_instance=kdu_instance, - primitive_name=primitive, + primitive_name=primitive_name, params=params, db_dict=db_dict, timeout=timeout_ns_action), timeout=timeout_ns_action) @@ -3650,13 +3713,14 @@ class NsLcm(LcmBase): ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"], member_vnf_index=vnf_index, vdu_id=vdu_id, - vdu_count_index=vdu_count_index) + vdu_count_index=vdu_count_index, + ee_descriptor_id=ee_descriptor_id) db_nslcmop_notif = {"collection": "nslcmops", "filter": {"_id": nslcmop_id}, "path": "admin.VCA"} nslcmop_operation_state, detailed_status = await self._ns_execute_primitive( ee_id, - primitive=primitive, + primitive=primitive_name, primitive_params=self._map_primitive_params(config_primitive_desc, primitive_params, desc_params), timeout=timeout_ns_action, vca_type=vca_type, @@ -3888,7 +3952,7 @@ class NsLcm(LcmBase): raise LcmException( "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-action" "[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:config-" - "primitive".format(scaling_group, config_primitive)) + "primitive".format(scaling_group, vnf_config_primitive)) vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info} if db_vnfr.get("additionalParamsForVnf"): @@ -3923,12 +3987,16 @@ class NsLcm(LcmBase): self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry". format(vnf_config_primitive)) # Execute the primitive, either with new (first-time) or registered (reintent) args + ee_descriptor_id = config_primitive.get("execution-environment-ref") + primitive_name = config_primitive.get("execution-environment-primitive", + vnf_config_primitive) ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"], member_vnf_index=vnf_index, vdu_id=None, - vdu_count_index=None) + vdu_count_index=None, + ee_descriptor_id=ee_descriptor_id) result, result_detail = await self._ns_execute_primitive( - ee_id, vnf_config_primitive, primitive_params, vca_type) + ee_id, primitive_name, primitive_params, vca_type) self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format( vnf_config_primitive, result, result_detail)) # Update operationState = COMPLETED | FAILED @@ -4083,10 +4151,10 @@ class NsLcm(LcmBase): if config_primitive["name"] == vnf_config_primitive: break else: - raise LcmException("Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:" - "scaling-config-action[vnf-config-primitive-name-ref='{}'] does not " - "match any vnf-configuration:config-primitive".format(scaling_group, - config_primitive)) + raise LcmException( + "Invalid vnfd descriptor at scaling-group-descriptor[name='{}']:scaling-config-" + "action[vnf-config-primitive-name-ref='{}'] does not match any vnf-configuration:" + "config-primitive".format(scaling_group, vnf_config_primitive)) scale_process = "VCA" db_nsr_update["config-status"] = "configuring post-scaling" primitive_params = self._map_primitive_params(config_primitive, {}, vnfr_params) @@ -4116,12 +4184,16 @@ class NsLcm(LcmBase): self.logger.debug(logging_text + "vnf_config_primitive={} Sub-operation retry". format(vnf_config_primitive)) # Execute the primitive, either with new (first-time) or registered (reintent) args + ee_descriptor_id = config_primitive.get("execution-environment-ref") + primitive_name = config_primitive.get("execution-environment-primitive", + vnf_config_primitive) ee_id, vca_type = self._look_for_deployed_vca(nsr_deployed["VCA"], member_vnf_index=vnf_index, vdu_id=None, - vdu_count_index=None) + vdu_count_index=None, + ee_descriptor_id=ee_descriptor_id) result, result_detail = await self._ns_execute_primitive( - ee_id, vnf_config_primitive, primitive_params, vca_type) + ee_id, primitive_name, primitive_params, vca_type) self.logger.debug(logging_text + "vnf_config_primitive={} Done with result {} {}".format( vnf_config_primitive, result, result_detail)) # Update operationState = COMPLETED | FAILED