+ self.logger.debug(
+ logging_text
+ + " vca_index: {}, vca_deployed: {}, config_descriptor: {}, destroy_ee: {}".format(
+ vca_index, vca_deployed, config_descriptor, destroy_ee
+ )
+ )
+
+ vca_type = vca_deployed.get("type", "lxc_proxy_charm")
+
+ # execute terminate_primitives
+ if exec_primitives:
+ terminate_primitives = get_ee_sorted_terminate_config_primitive_list(
+ config_descriptor.get("terminate-config-primitive"),
+ vca_deployed.get("ee_descriptor_id"),
+ )
+ 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"):
+ 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(
+ vnf_index, seq.get("name")
+ )
+ self.logger.debug(logging_text + step)
+ # 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
+ )
+
+ # Add sub-operation
+ self._add_suboperation(
+ db_nslcmop,
+ vnf_index,
+ vdu_id,
+ vdu_count_index,
+ vdu_name,
+ primitive,
+ mapped_primitive_params,
+ )
+ # Sub-operations: Call _ns_execute_primitive() instead of action()
+ try:
+ result, result_detail = await self._ns_execute_primitive(
+ vca_deployed["ee_id"],
+ primitive,
+ mapped_primitive_params,
+ vca_type=vca_type,
+ vca_id=vca_id,
+ )
+ except LcmException:
+ # this happens when VCA is not deployed. In this case it is not needed to terminate
+ continue
+ result_ok = ["COMPLETED", "PARTIALLY_COMPLETED"]
+ if result not in result_ok:
+ raise LcmException(
+ "terminate_primitive {} for vnf_member_index={} fails with "
+ "error {}".format(seq.get("name"), vnf_index, result_detail)
+ )
+ # set that this VCA do not need terminated
+ db_update_entry = "_admin.deployed.VCA.{}.needed_terminate".format(
+ vca_index
+ )
+ self.update_db_2(
+ "nsrs", db_nslcmop["nsInstanceId"], {db_update_entry: False}
+ )
+
+ if vca_deployed.get("prometheus_jobs") and self.prometheus:
+ await self.prometheus.update(remove_jobs=vca_deployed["prometheus_jobs"])
+
+ if destroy_ee:
+ await self.vca_map[vca_type].delete_execution_environment(
+ vca_deployed["ee_id"],
+ scaling_in=scaling_in,
+ vca_type=vca_type,
+ vca_id=vca_id,
+ )
+
+ async def _delete_all_N2VC(self, db_nsr: dict, vca_id: str = None):
+ self._write_all_config_status(db_nsr=db_nsr, status="TERMINATING")
+ namespace = "." + db_nsr["_id"]
+ try:
+ await self.n2vc.delete_namespace(
+ namespace=namespace,
+ total_timeout=self.timeout_charm_delete,
+ vca_id=vca_id,
+ )
+ except N2VCNotFound: # already deleted. Skip
+ pass
+ self._write_all_config_status(db_nsr=db_nsr, status="DELETED")
+
+ async def _terminate_RO(
+ self, logging_text, nsr_deployed, nsr_id, nslcmop_id, stage
+ ):
+ """
+ Terminates a deployment from RO
+ :param logging_text:
+ :param nsr_deployed: db_nsr._admin.deployed
+ :param nsr_id:
+ :param nslcmop_id:
+ :param stage: list of string with the content to write on db_nslcmop.detailed-status.
+ this method will update only the index 2, but it will write on database the concatenated content of the list
+ :return:
+ """
+ db_nsr_update = {}
+ failed_detail = []
+ ro_nsr_id = ro_delete_action = None
+ if nsr_deployed and nsr_deployed.get("RO"):
+ ro_nsr_id = nsr_deployed["RO"].get("nsr_id")
+ ro_delete_action = nsr_deployed["RO"].get("nsr_delete_action_id")
+ try:
+ if ro_nsr_id:
+ stage[2] = "Deleting ns from VIM."
+ db_nsr_update["detailed-status"] = " ".join(stage)
+ self._write_op_status(nslcmop_id, stage)
+ self.logger.debug(logging_text + stage[2])
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ self._write_op_status(nslcmop_id, stage)
+ desc = await self.RO.delete("ns", ro_nsr_id)
+ ro_delete_action = desc["action_id"]
+ db_nsr_update[
+ "_admin.deployed.RO.nsr_delete_action_id"
+ ] = ro_delete_action
+ db_nsr_update["_admin.deployed.RO.nsr_id"] = None
+ db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
+ if ro_delete_action:
+ # wait until NS is deleted from VIM
+ stage[2] = "Waiting ns deleted from VIM."
+ detailed_status_old = None
+ self.logger.debug(
+ logging_text
+ + stage[2]
+ + " RO_id={} ro_delete_action={}".format(
+ ro_nsr_id, ro_delete_action
+ )
+ )
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ self._write_op_status(nslcmop_id, stage)
+
+ delete_timeout = 20 * 60 # 20 minutes
+ while delete_timeout > 0:
+ desc = await self.RO.show(
+ "ns",
+ item_id_name=ro_nsr_id,
+ extra_item="action",
+ extra_item_id=ro_delete_action,
+ )
+
+ # deploymentStatus
+ self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
+
+ ns_status, ns_status_info = self.RO.check_action_status(desc)
+ if ns_status == "ERROR":
+ raise ROclient.ROClientException(ns_status_info)
+ elif ns_status == "BUILD":
+ stage[2] = "Deleting from VIM {}".format(ns_status_info)
+ elif ns_status == "ACTIVE":
+ db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
+ db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
+ break
+ else:
+ assert (
+ False
+ ), "ROclient.check_action_status returns unknown {}".format(
+ ns_status
+ )
+ if stage[2] != detailed_status_old:
+ detailed_status_old = stage[2]
+ db_nsr_update["detailed-status"] = " ".join(stage)
+ self._write_op_status(nslcmop_id, stage)
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ await asyncio.sleep(5, loop=self.loop)
+ delete_timeout -= 5
+ else: # delete_timeout <= 0:
+ raise ROclient.ROClientException(
+ "Timeout waiting ns deleted from VIM"
+ )
+
+ except Exception as e:
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ if (
+ isinstance(e, ROclient.ROClientException) and e.http_code == 404
+ ): # not found
+ db_nsr_update["_admin.deployed.RO.nsr_id"] = None
+ db_nsr_update["_admin.deployed.RO.nsr_status"] = "DELETED"
+ db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
+ self.logger.debug(
+ logging_text + "RO_ns_id={} already deleted".format(ro_nsr_id)
+ )
+ elif (
+ isinstance(e, ROclient.ROClientException) and e.http_code == 409
+ ): # conflict
+ failed_detail.append("delete conflict: {}".format(e))
+ self.logger.debug(
+ logging_text
+ + "RO_ns_id={} delete conflict: {}".format(ro_nsr_id, e)
+ )
+ else:
+ failed_detail.append("delete error: {}".format(e))
+ self.logger.error(
+ logging_text + "RO_ns_id={} delete error: {}".format(ro_nsr_id, e)
+ )
+
+ # Delete nsd
+ if not failed_detail and deep_get(nsr_deployed, ("RO", "nsd_id")):
+ ro_nsd_id = nsr_deployed["RO"]["nsd_id"]
+ try:
+ stage[2] = "Deleting nsd from RO."
+ db_nsr_update["detailed-status"] = " ".join(stage)
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ self._write_op_status(nslcmop_id, stage)
+ await self.RO.delete("nsd", ro_nsd_id)
+ self.logger.debug(
+ logging_text + "ro_nsd_id={} deleted".format(ro_nsd_id)
+ )
+ db_nsr_update["_admin.deployed.RO.nsd_id"] = None
+ except Exception as e:
+ if (
+ isinstance(e, ROclient.ROClientException) and e.http_code == 404
+ ): # not found
+ db_nsr_update["_admin.deployed.RO.nsd_id"] = None
+ self.logger.debug(
+ logging_text + "ro_nsd_id={} already deleted".format(ro_nsd_id)
+ )
+ elif (
+ isinstance(e, ROclient.ROClientException) and e.http_code == 409
+ ): # conflict
+ failed_detail.append(
+ "ro_nsd_id={} delete conflict: {}".format(ro_nsd_id, e)
+ )
+ self.logger.debug(logging_text + failed_detail[-1])
+ else:
+ failed_detail.append(
+ "ro_nsd_id={} delete error: {}".format(ro_nsd_id, e)
+ )
+ self.logger.error(logging_text + failed_detail[-1])
+
+ if not failed_detail and deep_get(nsr_deployed, ("RO", "vnfd")):
+ for index, vnf_deployed in enumerate(nsr_deployed["RO"]["vnfd"]):
+ if not vnf_deployed or not vnf_deployed["id"]:
+ continue
+ try:
+ ro_vnfd_id = vnf_deployed["id"]
+ stage[
+ 2
+ ] = "Deleting member_vnf_index={} ro_vnfd_id={} from RO.".format(
+ vnf_deployed["member-vnf-index"], ro_vnfd_id
+ )
+ db_nsr_update["detailed-status"] = " ".join(stage)
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ self._write_op_status(nslcmop_id, stage)
+ await self.RO.delete("vnfd", ro_vnfd_id)
+ self.logger.debug(
+ logging_text + "ro_vnfd_id={} deleted".format(ro_vnfd_id)
+ )
+ db_nsr_update["_admin.deployed.RO.vnfd.{}.id".format(index)] = None
+ except Exception as e:
+ if (
+ isinstance(e, ROclient.ROClientException) and e.http_code == 404
+ ): # not found
+ db_nsr_update[
+ "_admin.deployed.RO.vnfd.{}.id".format(index)
+ ] = None
+ self.logger.debug(
+ logging_text
+ + "ro_vnfd_id={} already deleted ".format(ro_vnfd_id)
+ )
+ elif (
+ isinstance(e, ROclient.ROClientException) and e.http_code == 409
+ ): # conflict
+ failed_detail.append(
+ "ro_vnfd_id={} delete conflict: {}".format(ro_vnfd_id, e)
+ )
+ self.logger.debug(logging_text + failed_detail[-1])
+ else:
+ failed_detail.append(
+ "ro_vnfd_id={} delete error: {}".format(ro_vnfd_id, e)
+ )
+ self.logger.error(logging_text + failed_detail[-1])
+
+ if failed_detail:
+ stage[2] = "Error deleting from VIM"
+ else:
+ stage[2] = "Deleted from VIM"
+ db_nsr_update["detailed-status"] = " ".join(stage)
+ self.update_db_2("nsrs", nsr_id, db_nsr_update)
+ self._write_op_status(nslcmop_id, stage)
+
+ if failed_detail:
+ raise LcmException("; ".join(failed_detail))