X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_lcm%2Fns.py;h=d267065928f53731030f5bc6c07a50d7ff03d3fe;hb=28b0bf87c3fe2bd99cd3d5665eae484df8c3b44c;hp=5345d78b32a53620ada42f48a7d95e8362991319;hpb=07f4e4cc95d17c613f5557e65781b8d4599ed20f;p=osm%2FLCM.git diff --git a/osm_lcm/ns.py b/osm_lcm/ns.py index 5345d78..d267065 100644 --- a/osm_lcm/ns.py +++ b/osm_lcm/ns.py @@ -30,6 +30,7 @@ from jinja2 import ( TemplateNotFound, StrictUndefined, UndefinedError, + select_autoescape, ) from osm_lcm import ROclient @@ -133,7 +134,8 @@ class NsLcm(LcmBase): 10 * 60 ) # timeout for some progress in a primitive execution timeout_migrate = 1800 # default global timeout for migrating vnfs - + timeout_operate = 1800 # default global timeout for migrating vnfs + timeout_verticalscale = 1800 # default global timeout for Vertical Sclaing SUBOPERATION_STATUS_NOT_FOUND = -1 SUBOPERATION_STATUS_NEW = -2 SUBOPERATION_STATUS_SKIP = -3 @@ -224,6 +226,8 @@ class NsLcm(LcmBase): "termination": self.RO.status, "migrate": self.RO.status, "healing": self.RO.recreate_status, + "verticalscale": self.RO.status, + "start_stop_rebuild": self.RO.status, } @staticmethod @@ -290,7 +294,6 @@ class NsLcm(LcmBase): # vcaStatus db_dict = dict() db_dict["vcaStatus"] = status_dict - await self.n2vc.update_vca_status(db_dict["vcaStatus"], vca_id=vca_id) # update configurationStatus for this VCA try: @@ -398,15 +401,6 @@ class NsLcm(LcmBase): db_dict = dict() db_dict["vcaStatus"] = {nsr_id: vca_status} - if cluster_type in ("juju-bundle", "juju"): - # TODO -> this should be done in a more uniform way, I think in N2VC, in order to update the K8s VCA - # status in a similar way between Juju Bundles and Helm Charts on this side - await self.k8sclusterjuju.update_vca_status( - db_dict["vcaStatus"], - kdu_instance, - vca_id=vca_id, - ) - self.logger.debug( f"Obtained VCA status for cluster type '{cluster_type}': {vca_status}" ) @@ -421,7 +415,10 @@ class NsLcm(LcmBase): @staticmethod def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id): try: - env = Environment(undefined=StrictUndefined) + env = Environment( + undefined=StrictUndefined, + autoescape=select_autoescape(default_for_string=True, default=True), + ) template = env.from_string(cloud_init_text) return template.render(additional_params or {}) except UndefinedError as e: @@ -897,18 +894,55 @@ class NsLcm(LcmBase): get_iterable(vdur, "interfaces"), lambda iface: iface.get("ns-vld-id") == a_vld["name"], ) + + vld_params = find_in_list( + get_iterable(ns_params, "vld"), + lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]), + ) if target_vld: + if vnf_params.get("vimAccountId") not in a_vld.get( "vim_info", {} ): + target_vim_network_list = [ + v for _, v in a_vld.get("vim_info").items() + ] + target_vim_network_name = next( + ( + item.get("vim_network_name", "") + for item in target_vim_network_list + ), + "", + ) + target["ns"]["vld"][a_index].get("vim_info").update( { "vim:{}".format(vnf_params["vimAccountId"]): { - "vim_network_name": "" + "vim_network_name": target_vim_network_name, } } ) + if vld_params: + for param in ("vim-network-name", "vim-network-id"): + if vld_params.get(param) and isinstance( + vld_params[param], dict + ): + for vim, vim_net in vld_params[ + param + ].items(): + other_target_vim = "vim:" + vim + populate_dict( + target["ns"]["vld"][a_index].get( + "vim_info" + ), + ( + other_target_vim, + param.replace("-", "_"), + ), + vim_net, + ) + nslcmop_id = db_nslcmop["_id"] target = { "name": db_nsr["name"], @@ -1252,8 +1286,13 @@ class NsLcm(LcmBase): self.logger.debug("RO return > {}".format(desc)) action_id = desc["action_id"] await self._wait_ng_ro( - nsr_id, action_id, nslcmop_id, start_deploy, timeout_ns_deploy, stage, - operation="instantiation" + nsr_id, + action_id, + nslcmop_id, + start_deploy, + timeout_ns_deploy, + stage, + operation="instantiation", ) # Updating NSR @@ -1334,8 +1373,13 @@ class NsLcm(LcmBase): # wait until done delete_timeout = 20 * 60 # 20 minutes await self._wait_ng_ro( - nsr_id, action_id, nslcmop_id, start_deploy, delete_timeout, stage, - operation="termination" + nsr_id, + action_id, + nslcmop_id, + start_deploy, + delete_timeout, + stage, + operation="termination", ) db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None @@ -1609,7 +1653,9 @@ class NsLcm(LcmBase): } desc = await self.RO.deploy(nsr_id, target) action_id = desc["action_id"] - await self._wait_ng_ro(nsr_id, action_id, timeout=600, operation="instantiation") + await self._wait_ng_ro( + nsr_id, action_id, timeout=600, operation="instantiation" + ) break else: # wait until NS is deployed at RO @@ -2058,7 +2104,7 @@ class NsLcm(LcmBase): # for a KNF and not for its KDUs, the previous verification gives False, and the code # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF # or it is a KNF) - elif db_vnfr.get('vdur'): + elif db_vnfr.get("vdur"): rw_mgmt_ip = await self.wait_vm_up_insert_key_ro( logging_text, nsr_id, @@ -3701,10 +3747,16 @@ class NsLcm(LcmBase): self.logger.debug( logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id) ) + + charm_name = "" + get_charm_name = False if "execution-environment-list" in descriptor_config: ee_list = descriptor_config.get("execution-environment-list", []) elif "juju" in descriptor_config: ee_list = [descriptor_config] # ns charms + if "execution-environment-list" not in descriptor_config: + # charm name is only required for ns charms + get_charm_name = True else: # other types as script are not supported ee_list = [] @@ -3718,6 +3770,8 @@ class NsLcm(LcmBase): ee_descriptor_id = ee_item.get("id") if ee_item.get("juju"): vca_name = ee_item["juju"].get("charm") + if get_charm_name: + charm_name = self.find_charm_name(db_nsr, str(vca_name)) vca_type = ( "lxc_proxy_charm" if ee_item["juju"].get("charm") is not None @@ -3776,6 +3830,7 @@ class NsLcm(LcmBase): "vdu_name": vdu_name, "type": vca_type, "ee_descriptor_id": ee_descriptor_id, + "charm_name": charm_name, } vca_index += 1 @@ -4947,9 +5002,7 @@ class NsLcm(LcmBase): break except asyncio.CancelledError: raise - except Exception as e: # asyncio.TimeoutError - if isinstance(e, asyncio.TimeoutError): - e = "Timeout" + except Exception as e: retries -= 1 if retries >= 0: self.logger.debug( @@ -4960,7 +5013,11 @@ class NsLcm(LcmBase): # wait and retry await asyncio.sleep(retries_interval, loop=self.loop) else: - return "FAILED", str(e) + if isinstance(e, asyncio.TimeoutError): + e = N2VCException( + message="Timed out waiting for action to complete" + ) + return "FAILED", getattr(e, "message", repr(e)) return "COMPLETED", output @@ -5295,7 +5352,7 @@ class NsLcm(LcmBase): ) self.logger.debug( logging_text - + " task Done with result {} {}".format( + + "Done with result {} {}".format( nslcmop_operation_state, detailed_status ) ) @@ -5393,33 +5450,39 @@ class NsLcm(LcmBase): "member-vnf-index": member_vnf_index, "type": "delete", "vdu_index": count_index, - }) + } + ) scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index scaling_info["vdu"].append( { "name": vdu.get("name") or vdu.get("vdu-name"), "vdu_id": vdu["vdu-id-ref"], "interface": [], - }) + } + ) for interface in vdu["interfaces"]: scaling_info["vdu"][index]["interface"].append( { "name": interface["name"], "ip_address": interface["ip-address"], "mac_address": interface.get("mac-address"), - }) + } + ) self.logger.info("NS update scaling info{}".format(scaling_info)) stage[2] = "Terminating VDUs" if scaling_info.get("vdu-delete"): # scale_process = "RO" if self.ro_config.get("ng"): await self._scale_ng_ro( - logging_text, db_nsr, update_db_nslcmops, db_vnfr, scaling_info, stage + logging_text, + db_nsr, + update_db_nslcmops, + db_vnfr, + scaling_info, + stage, ) - async def remove_vnf( - self, nsr_id, nslcmop_id, vnf_instance_id - ): + async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id): """This method is to Remove VNF instances from NS. Args: @@ -5438,7 +5501,9 @@ class NsLcm(LcmBase): if check_vnfr_count > 1: stage = ["", "", ""] step = "Getting nslcmop from database" - self.logger.debug(step + " after having waited for previous tasks to be completed") + self.logger.debug( + step + " after having waited for previous tasks to be completed" + ) # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id}) db_nsr = self.db.get_one("nsrs", {"_id": nsr_id}) db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id}) @@ -5447,19 +5512,31 @@ class NsLcm(LcmBase): "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """ update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id}) - await self.terminate_vdus(db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text) + await self.terminate_vdus( + db_vnfr, + member_vnf_index, + db_nsr, + update_db_nslcmops, + stage, + logging_text, + ) constituent_vnfr = db_nsr.get("constituent-vnfr-ref") constituent_vnfr.remove(db_vnfr.get("_id")) - db_nsr_update["constituent-vnfr-ref"] = db_nsr.get("constituent-vnfr-ref") + db_nsr_update["constituent-vnfr-ref"] = db_nsr.get( + "constituent-vnfr-ref" + ) self.update_db_2("nsrs", nsr_id, db_nsr_update) self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")}) self.update_db_2("nsrs", nsr_id, db_nsr_update) return "COMPLETED", "Done" else: step = "Terminate VNF Failed with" - raise LcmException("{} Cannot terminate the last VNF in this NS.".format( - vnf_instance_id)) + raise LcmException( + "{} Cannot terminate the last VNF in this NS.".format( + vnf_instance_id + ) + ) except (LcmException, asyncio.CancelledError): raise except Exception as e: @@ -5467,7 +5544,12 @@ class NsLcm(LcmBase): return "FAILED", "Error removing VNF {}".format(e) async def _ns_redeploy_vnf( - self, nsr_id, nslcmop_id, db_vnfd, db_vnfr, db_nsr, + self, + nsr_id, + nslcmop_id, + db_vnfd, + db_vnfr, + db_nsr, ): """This method updates and redeploys VNF instances @@ -5490,7 +5572,14 @@ class NsLcm(LcmBase): # Terminate old VNF resources update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id}) - await self.terminate_vdus(db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text) + await self.terminate_vdus( + db_vnfr, + member_vnf_index, + db_nsr, + update_db_nslcmops, + stage, + logging_text, + ) # old_vnfd_id = db_vnfr["vnfd-id"] # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id}) @@ -5511,10 +5600,16 @@ class NsLcm(LcmBase): new_vdur = update_db_nslcmops["operationParams"]["newVdur"] # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index) # new_vnfr_update = {"vnfd-ref": new_vnfd_ref, "vnfd-id": new_vnfd_id, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""} - new_vnfr_update = {"revision": latest_vnfd_revision, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""} + new_vnfr_update = { + "revision": latest_vnfd_revision, + "connection-point": new_vnfr_cp, + "vdur": new_vdur, + "ip-address": "", + } self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update) updated_db_vnfr = self.db.get_one( - "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id} + "vnfrs", + {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}, ) # Instantiate new VNF resources @@ -5526,9 +5621,7 @@ class NsLcm(LcmBase): scaling_info["kdu-create"] = {} vdud_instantiate_list = db_vnfd["vdu"] for index, vdud in enumerate(vdud_instantiate_list): - cloud_init_text = self._get_vdu_cloud_init_content( - vdud, db_vnfd - ) + cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd) if cloud_init_text: additional_params = ( self._get_vdu_additional_params(updated_db_vnfr, vdud["id"]) @@ -5559,9 +5652,15 @@ class NsLcm(LcmBase): scaling_info["vdu-create"][vdud["id"]] = count_index if self.ro_config.get("ng"): self.logger.debug( - "New Resources to be deployed: {}".format(scaling_info)) + "New Resources to be deployed: {}".format(scaling_info) + ) await self._scale_ng_ro( - logging_text, db_nsr, update_db_nslcmops, updated_db_vnfr, scaling_info, stage + logging_text, + db_nsr, + update_db_nslcmops, + updated_db_vnfr, + scaling_info, + stage, ) return "COMPLETED", "Done" except (LcmException, asyncio.CancelledError): @@ -5803,15 +5902,8 @@ class NsLcm(LcmBase): # based on new descriptor step = "Redeploying VNF" member_vnf_index = db_vnfr["member-vnf-index-ref"] - ( - result, - detailed_status - ) = await self._ns_redeploy_vnf( - nsr_id, - nslcmop_id, - latest_vnfd, - db_vnfr, - db_nsr + (result, detailed_status) = await self._ns_redeploy_vnf( + nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr ) if result == "FAILED": nslcmop_operation_state = result @@ -5898,7 +5990,9 @@ class NsLcm(LcmBase): db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id}) member_vnf_index = db_vnfr["member-vnf-index-ref"] step = "Removing VNF" - (result, detailed_status) = await self.remove_vnf(nsr_id, nslcmop_id, vnf_instance_id) + (result, detailed_status) = await self.remove_vnf( + nsr_id, nslcmop_id, vnf_instance_id + ) if result == "FAILED": nslcmop_operation_state = result error_description_nslcmop = detailed_status @@ -5913,6 +6007,32 @@ class NsLcm(LcmBase): ) ) + elif update_type == "OPERATE_VNF": + vnf_id = db_nslcmop["operationParams"]["operateVnfData"][ + "vnfInstanceId" + ] + operation_type = db_nslcmop["operationParams"]["operateVnfData"][ + "changeStateTo" + ] + additional_param = db_nslcmop["operationParams"]["operateVnfData"][ + "additionalParam" + ] + (result, detailed_status) = await self.rebuild_start_stop( + nsr_id, nslcmop_id, vnf_id, additional_param, operation_type + ) + if result == "FAILED": + nslcmop_operation_state = result + error_description_nslcmop = detailed_status + db_nslcmop_update["detailed-status"] = detailed_status + if not nslcmop_operation_state: + nslcmop_operation_state = "COMPLETED" + self.logger.debug( + logging_text + + " task Done with result {} {}".format( + nslcmop_operation_state, detailed_status + ) + ) + # If nslcmop_operation_state is None, so any operation is not failed. # All operations are executed in overall. if not nslcmop_operation_state: @@ -7202,6 +7322,93 @@ class NsLcm(LcmBase): job["vnfr_id"] = vnfr_id return job_list + async def rebuild_start_stop( + self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type + ): + logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id) + self.logger.info(logging_text + "Enter") + stage = ["Preparing the environment", ""] + # database nsrs record + db_nsr_update = {} + vdu_vim_name = None + vim_vm_id = None + # in case of error, indicates what part of scale was failed to put nsr at error status + start_deploy = time() + try: + db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id}) + vim_account_id = db_vnfr.get("vim-account-id") + vim_info_key = "vim:" + vim_account_id + vdu_id = additional_param["vdu_id"] + vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id] + vdur = find_in_list( + vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"] + ) + if vdur: + vdu_vim_name = vdur["name"] + vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"] + target_vim, _ = next(k_v for k_v in vdur["vim_info"].items()) + else: + raise LcmException("Target vdu is not found") + self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name)) + # wait for any previous tasks in process + stage[1] = "Waiting for previous operations to terminate" + self.logger.info(stage[1]) + await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id) + + stage[1] = "Reading from database." + self.logger.info(stage[1]) + self._write_ns_status( + nsr_id=nsr_id, + ns_state=None, + current_operation=operation_type.upper(), + current_operation_id=nslcmop_id, + ) + self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0) + + # read from db: ns + stage[1] = "Getting nsr={} from db.".format(nsr_id) + db_nsr_update["operational-status"] = operation_type + self.update_db_2("nsrs", nsr_id, db_nsr_update) + # Payload for RO + desc = { + operation_type: { + "vim_vm_id": vim_vm_id, + "vnf_id": vnf_id, + "vdu_index": additional_param["count-index"], + "vdu_id": vdur["id"], + "target_vim": target_vim, + "vim_account_id": vim_account_id, + } + } + stage[1] = "Sending rebuild request to RO... {}".format(desc) + self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0) + self.logger.info("ro nsr id: {}".format(nsr_id)) + result_dict = await self.RO.operate(nsr_id, desc, operation_type) + self.logger.info("response from RO: {}".format(result_dict)) + action_id = result_dict["action_id"] + await self._wait_ng_ro( + nsr_id, + action_id, + nslcmop_id, + start_deploy, + self.timeout_operate, + None, + "start_stop_rebuild", + ) + return "COMPLETED", "Done" + except (ROclient.ROClientException, DbException, LcmException) as e: + self.logger.error("Exit Exception {}".format(e)) + exc = e + except asyncio.CancelledError: + self.logger.error("Cancelled Exception while '{}'".format(stage)) + exc = "Operation was cancelled" + except Exception as e: + exc = traceback.format_exc() + self.logger.critical( + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True + ) + return "FAILED", "Error in operate VNF {}".format(exc) + def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str): """ Get VCA Cloud and VCA Cloud Credentials for the VIM account @@ -7272,8 +7479,12 @@ class NsLcm(LcmBase): self.logger.debug("RO return > {}".format(desc)) action_id = desc["action_id"] await self._wait_ng_ro( - nsr_id, action_id, nslcmop_id, start_deploy, self.timeout_migrate, - operation="migrate" + nsr_id, + action_id, + nslcmop_id, + start_deploy, + self.timeout_migrate, + operation="migrate", ) except (ROclient.ROClientException, DbException, LcmException) as e: self.logger.error("Exit Exception {}".format(e)) @@ -7323,7 +7534,6 @@ class NsLcm(LcmBase): self.logger.debug(logging_text + "Exit") self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate") - async def heal(self, nsr_id, nslcmop_id): """ Heal NS @@ -7424,17 +7634,39 @@ class NsLcm(LcmBase): member_vnf_index = db_vnfr.get("member-vnf-index-ref") # Check each target VDU and deploy N2VC - for target_vdu in target_vnf["additionalParams"].get("vdu", None): + target_vdu_list = target_vnf.get("additionalParams", {}).get( + "vdu", [] + ) + if not target_vdu_list: + # Codigo nuevo para crear diccionario + target_vdu_list = [] + for existing_vdu in db_vnfr.get("vdur"): + vdu_name = existing_vdu.get("vdu-name", None) + vdu_index = existing_vdu.get("count-index", 0) + vdu_run_day1 = target_vnf.get("additionalParams", {}).get( + "run-day1", False + ) + vdu_to_be_healed = { + "vdu-id": vdu_name, + "count-index": vdu_index, + "run-day1": vdu_run_day1, + } + target_vdu_list.append(vdu_to_be_healed) + for target_vdu in target_vdu_list: deploy_params_vdu = target_vdu # Set run-day1 vnf level value if not vdu level value exists - if not deploy_params_vdu.get("run-day1") and target_vnf["additionalParams"].get("run-day1"): - deploy_params_vdu["run-day1"] = target_vnf["additionalParams"].get("run-day1") + if not deploy_params_vdu.get("run-day1") and target_vnf[ + "additionalParams" + ].get("run-day1"): + deploy_params_vdu["run-day1"] = target_vnf[ + "additionalParams" + ].get("run-day1") vdu_name = target_vdu.get("vdu-id", None) # TODO: Get vdu_id from vdud. vdu_id = vdu_name # For multi instance VDU count-index is mandatory # For single session VDU count-indes is 0 - vdu_index = target_vdu.get("count-index",0) + vdu_index = target_vdu.get("count-index", 0) # n2vc_redesign STEP 3 to 6 Deploy N2VC stage[1] = "Deploying Execution Environments." @@ -7448,32 +7680,35 @@ class NsLcm(LcmBase): vnf_ip_address = db_vnfr.get("ip-address") target_instance = None for instance in db_vnfr.get("vdur", None): - if ( instance["vdu-name"] == vdu_name and instance["count-index"] == vdu_index ): + if ( + instance["vdu-name"] == vdu_name + and instance["count-index"] == vdu_index + ): target_instance = instance break if vnf_ip_address == target_instance.get("ip-address"): self._heal_n2vc( - logging_text=logging_text - + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format( - member_vnf_index, vdu_name, vdu_index - ), - db_nsr=db_nsr, - db_vnfr=db_vnfr, - nslcmop_id=nslcmop_id, - nsr_id=nsr_id, - nsi_id=nsi_id, - vnfd_id=vnfd_ref, - vdu_id=None, - kdu_name=None, - member_vnf_index=member_vnf_index, - vdu_index=0, - vdu_name=None, - deploy_params=deploy_params_vdu, - descriptor_config=descriptor_config, - base_folder=base_folder, - task_instantiation_info=tasks_dict_info, - stage=stage, - ) + logging_text=logging_text + + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format( + member_vnf_index, vdu_name, vdu_index + ), + db_nsr=db_nsr, + db_vnfr=db_vnfr, + nslcmop_id=nslcmop_id, + nsr_id=nsr_id, + nsi_id=nsi_id, + vnfd_id=vnfd_ref, + vdu_id=None, + kdu_name=None, + member_vnf_index=member_vnf_index, + vdu_index=0, + vdu_name=None, + deploy_params=deploy_params_vdu, + descriptor_config=descriptor_config, + base_folder=base_folder, + task_instantiation_info=tasks_dict_info, + stage=stage, + ) # VDU Level charm. Normal case with native charms. descriptor_config = get_configuration(vnfd, vdu_name) @@ -7542,9 +7777,7 @@ class NsLcm(LcmBase): db_nsr_update["config-status"] = old_config_status db_nsr_update[ "detailed-status" - ] = "FAILED healing nslcmop={} {}: {}".format( - nslcmop_id, step, exc - ) + ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc) for task, task_name in tasks_dict_info.items(): if not task.done() or task.cancelled() or task.exception(): if task_name.startswith(self.task_name_deploy_vca): @@ -7607,6 +7840,7 @@ class NsLcm(LcmBase): :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific :return: None or exception """ + def get_vim_account(vim_account_id): nonlocal db_vims if vim_account_id in db_vims: @@ -7621,9 +7855,7 @@ class NsLcm(LcmBase): if ns_params and ns_params.get("timeout_ns_heal"): timeout_ns_heal = ns_params["timeout_ns_heal"] else: - timeout_ns_heal = self.timeout.get( - "ns_heal", self.timeout_ns_heal - ) + timeout_ns_heal = self.timeout.get("ns_heal", self.timeout_ns_heal) db_vims = {} @@ -7631,7 +7863,11 @@ class NsLcm(LcmBase): target = { "action_id": nslcmop_id, } - self.logger.warning("db_nslcmop={} and timeout_ns_heal={}".format(db_nslcmop,timeout_ns_heal)) + self.logger.warning( + "db_nslcmop={} and timeout_ns_heal={}".format( + db_nslcmop, timeout_ns_heal + ) + ) target.update(db_nslcmop.get("operationParams", {})) self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target)) @@ -7640,8 +7876,13 @@ class NsLcm(LcmBase): action_id = desc["action_id"] # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted await self._wait_ng_ro( - nsr_id, action_id, nslcmop_id, start_heal, timeout_ns_heal, stage, - operation="healing" + nsr_id, + action_id, + nslcmop_id, + start_heal, + timeout_ns_heal, + stage, + operation="healing", ) # Updating NSR @@ -7657,7 +7898,7 @@ class NsLcm(LcmBase): except Exception as e: stage[2] = "ERROR healing at VIM" - #self.set_vnfr_at_error(db_vnfrs, str(e)) + # self.set_vnfr_at_error(db_vnfrs, str(e)) self.logger.error( "Error healing at VIM {}".format(e), exc_info=not isinstance( @@ -7700,10 +7941,16 @@ class NsLcm(LcmBase): self.logger.debug( logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id) ) + + charm_name = "" + get_charm_name = False if "execution-environment-list" in descriptor_config: ee_list = descriptor_config.get("execution-environment-list", []) elif "juju" in descriptor_config: ee_list = [descriptor_config] # ns charms + if "execution-environment-list" not in descriptor_config: + # charm name is only required for ns charms + get_charm_name = True else: # other types as script are not supported ee_list = [] @@ -7717,6 +7964,8 @@ class NsLcm(LcmBase): ee_descriptor_id = ee_item.get("id") if ee_item.get("juju"): vca_name = ee_item["juju"].get("charm") + if get_charm_name: + charm_name = self.find_charm_name(db_nsr, str(vca_name)) vca_type = ( "lxc_proxy_charm" if ee_item["juju"].get("charm") is not None @@ -7775,6 +8024,7 @@ class NsLcm(LcmBase): "vdu_name": vdu_name, "type": vca_type, "ee_descriptor_id": ee_descriptor_id, + "charm_name": charm_name, } vca_index += 1 @@ -8019,7 +8269,7 @@ class NsLcm(LcmBase): status="INSTALLING SW", element_under_configuration=element_under_configuration, element_type=element_type, - #other_update=db_nsr_update, + # other_update=db_nsr_update, other_update=None, ) @@ -8092,7 +8342,7 @@ class NsLcm(LcmBase): # n2vc_redesign STEP 5.1 # wait for RO (ip-address) Insert pub_key into VM # IMPORTANT: We need do wait for RO to complete healing operation. - await self._wait_heal_ro(nsr_id,self.timeout_ns_heal) + await self._wait_heal_ro(nsr_id, self.timeout_ns_heal) if vnfr_id: if kdu_name: rw_mgmt_ip = await self.wait_kdu_up( @@ -8118,15 +8368,19 @@ class NsLcm(LcmBase): # Day1 operations. # get run-day1 operation parameter - runDay1 = deploy_params.get("run-day1",False) - self.logger.debug(" Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id,vdu_id,runDay1)) + runDay1 = deploy_params.get("run-day1", False) + self.logger.debug( + "Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1) + ) if runDay1: # n2vc_redesign STEP 6 Execute initial config primitive step = "execute initial config primitive" # wait for dependent primitives execution (NS -> VNF -> VDU) if initial_config_primitive_list: - await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index) + await self._wait_dependent_n2vc( + nsr_id, vca_deployed_list, vca_index + ) # stage, in function of element type: vdu, kdu, vnf or ns my_vca = vca_deployed_list[vca_index] @@ -8174,7 +8428,9 @@ class NsLcm(LcmBase): if check_if_terminated_needed: if config_descriptor.get("terminate-config-primitive"): self.update_db_2( - "nsrs", nsr_id, {db_update_entry + "needed_terminate": True} + "nsrs", + nsr_id, + {db_update_entry + "needed_terminate": True}, ) check_if_terminated_needed = False @@ -8237,10 +8493,114 @@ class NsLcm(LcmBase): start_time = time() while time() <= start_time + timeout: db_nsr = self.db.get_one("nsrs", {"_id": nsr_id}) - operational_status_ro = db_nsr["_admin"]["deployed"]["RO"]["operational-status"] + operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][ + "operational-status" + ] self.logger.debug("Wait Heal RO > {}".format(operational_status_ro)) if operational_status_ro != "healing": break await asyncio.sleep(15, loop=self.loop) else: # timeout_ns_deploy raise NgRoException("Timeout waiting ns to deploy") + + async def vertical_scale(self, nsr_id, nslcmop_id): + """ + Vertical Scale the VDUs in a NS + + :param: nsr_id: NS Instance ID + :param: nslcmop_id: nslcmop ID of migrate + + """ + # Try to lock HA task here + task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id) + if not task_is_locked_by_me: + return + logging_text = "Task ns={} vertical scale ".format(nsr_id) + self.logger.debug(logging_text + "Enter") + # get all needed from database + db_nslcmop = None + db_nslcmop_update = {} + nslcmop_operation_state = None + db_nsr_update = {} + target = {} + exc = None + # in case of error, indicates what part of scale was failed to put nsr at error status + start_deploy = time() + + try: + # wait for any previous tasks in process + step = "Waiting for previous operations to terminate" + await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id) + + self._write_ns_status( + nsr_id=nsr_id, + ns_state=None, + current_operation="VerticalScale", + current_operation_id=nslcmop_id, + ) + step = "Getting nslcmop from database" + self.logger.debug( + step + " after having waited for previous tasks to be completed" + ) + db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id}) + operationParams = db_nslcmop.get("operationParams") + target = {} + target.update(operationParams) + desc = await self.RO.vertical_scale(nsr_id, target) + self.logger.debug("RO return > {}".format(desc)) + action_id = desc["action_id"] + await self._wait_ng_ro( + nsr_id, + action_id, + nslcmop_id, + start_deploy, + self.timeout_verticalscale, + operation="verticalscale", + ) + except (ROclient.ROClientException, DbException, LcmException) as e: + self.logger.error("Exit Exception {}".format(e)) + exc = e + except asyncio.CancelledError: + self.logger.error("Cancelled Exception while '{}'".format(step)) + exc = "Operation was cancelled" + except Exception as e: + exc = traceback.format_exc() + self.logger.critical( + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True + ) + finally: + self._write_ns_status( + nsr_id=nsr_id, + ns_state=None, + current_operation="IDLE", + current_operation_id=None, + ) + if exc: + db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc) + nslcmop_operation_state = "FAILED" + else: + nslcmop_operation_state = "COMPLETED" + db_nslcmop_update["detailed-status"] = "Done" + db_nsr_update["detailed-status"] = "Done" + + self._write_op_status( + op_id=nslcmop_id, + stage="", + error_message="", + operation_state=nslcmop_operation_state, + other_update=db_nslcmop_update, + ) + if nslcmop_operation_state: + try: + msg = { + "nsr_id": nsr_id, + "nslcmop_id": nslcmop_id, + "operationState": nslcmop_operation_state, + } + await self.msg.aiowrite("ns", "verticalscaled", msg, loop=self.loop) + except Exception as e: + self.logger.error( + logging_text + "kafka_write notification Exception {}".format(e) + ) + self.logger.debug(logging_text + "Exit") + self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")