ns_heal,
nsi_instantiate,
ns_migrate,
- ns_verticalscale,
+ nslcmop_cancel,
)
from osm_nbi.base_topic import (
BaseTopic,
"nsds", {"_id": used_nsd_id}, {"_admin.usageState": "NOT_IN_USE"}
)
+ # Set NS CONFIG TEMPLATE usageState
+ if nsr.get("instantiate_params", {}).get("nsConfigTemplateId"):
+ nsconfigtemplate_id = nsr.get("instantiate_params", {}).get(
+ "nsConfigTemplateId"
+ )
+ nsconfigtemplate_list = self.db.get_one(
+ "nsrs",
+ {"instantiate_params.nsConfigTemplateId": nsconfigtemplate_id},
+ fail_on_empty=False,
+ fail_on_more=False,
+ )
+ if not nsconfigtemplate_list:
+ self.db.set_one(
+ "ns_config_template",
+ {"_id": nsconfigtemplate_id},
+ {"_admin.usageState": "NOT_IN_USE"},
+ )
+
# Set VNFD usageState
used_vnfd_id_list = nsr.get("vnfd-id")
if used_vnfd_id_list:
nsd = self._get_nsd_from_db(ns_request["nsdId"], session)
ns_k8s_namespace = self._get_ns_k8s_namespace(nsd, ns_request, session)
+ # Uploading the instantiation parameters to ns_request from ns config template
+ if ns_request.get("nsConfigTemplateId"):
+ step = "getting ns_config_template is='{}' from database".format(
+ ns_request.get("nsConfigTemplateId")
+ )
+ ns_config_template_db = self._get_nsConfigTemplate_from_db(
+ ns_request.get("nsConfigTemplateId"), session
+ )
+ ns_config_params = ns_config_template_db.get("config")
+ for key, value in ns_config_params.items():
+ if key == "vnf":
+ ns_request["vnf"] = ns_config_params.get("vnf")
+ elif key == "additionalParamsForVnf":
+ ns_request["additionalParamsForVnf"] = ns_config_params.get(
+ "additionalParamsForVnf"
+ )
+ elif key == "additionalParamsForNs":
+ ns_request["additionalParamsForNs"] = ns_config_params.get(
+ "additionalParamsForNs"
+ )
+ elif key == "vld":
+ ns_request["vld"] = ns_config_params.get("vld")
+ step = "checking ns_config_templateOperationalState"
+ self._check_ns_config_template_operational_state(
+ ns_config_template_db, ns_request
+ )
+
+ step = "Updating NSCONFIG TEMPLATE usageState"
+ update_descriptor_usage_state(
+ ns_config_template_db, "ns_config_template", self.db
+ )
+
step = "checking nsdOperationalState"
self._check_nsd_operational_state(nsd, ns_request)
_filter["_id"] = nsd_id
return self.db.get_one("nsds", _filter)
+ def _get_nsConfigTemplate_from_db(self, nsConfigTemplate_id, session):
+ _filter = self._get_project_filter(session)
+ _filter["_id"] = nsConfigTemplate_id
+ ns_config_template_db = self.db.get_one(
+ "ns_config_template", _filter, fail_on_empty=False
+ )
+ return ns_config_template_db
+
def _get_vnfd_from_db(self, vnfd_id, session):
_filter = self._get_project_filter(session)
_filter["id"] = vnfd_id
http_code=HTTPStatus.CONFLICT,
)
+ def _check_ns_config_template_operational_state(
+ self, ns_config_template_db, ns_request
+ ):
+ if ns_config_template_db["_admin"]["operationalState"] == "DISABLED":
+ raise EngineException(
+ "ns_config_template with id '{}' is DISABLED, and thus cannot be used to create "
+ "a network service".format(ns_request["nsConfigTemplateId"]),
+ http_code=HTTPStatus.CONFLICT,
+ )
+
def _get_ns_k8s_namespace(self, nsd, ns_request, session):
additional_params, _ = self._format_additional_params(
ns_request, descriptor=nsd
return ns_k8s_namespace
+ def _add_shared_volumes_to_nsr(
+ self, vdu, vnfd, nsr_descriptor, member_vnf_index, revision=None
+ ):
+ svsd = []
+ for vsd in vnfd.get("virtual-storage-desc", ()):
+ if vsd.get("vdu-storage-requirements"):
+ if (
+ vsd.get("vdu-storage-requirements")[0].get("key") == "multiattach"
+ and vsd.get("vdu-storage-requirements")[0].get("value") == "True"
+ ):
+ # Avoid setting the volume name multiple times
+ if not match(f"shared-.*-{vnfd['id']}", vsd["id"]):
+ vsd["id"] = f"shared-{vsd['id']}-{vnfd['id']}"
+ svsd.append(vsd)
+ if svsd:
+ nsr_descriptor["shared-volumes"] = svsd
+
def _add_flavor_to_nsr(
self, vdu, vnfd, nsr_descriptor, member_vnf_index, revision=None
):
"flavor": [],
"image": [],
"affinity-or-anti-affinity-group": [],
+ "shared-volumes": [],
+ "vnffgd": [],
}
if "revision" in nsd["_admin"]:
nsr_descriptor["revision"] = nsd["_admin"]["revision"]
for vdu in vnfd.get("vdu", ()):
member_vnf_index = vnf_profile.get("id")
self._add_flavor_to_nsr(vdu, vnfd, nsr_descriptor, member_vnf_index)
+ self._add_shared_volumes_to_nsr(
+ vdu, vnfd, nsr_descriptor, member_vnf_index
+ )
sw_image_id = vdu.get("sw-image-desc")
if sw_image_id:
image_data = self._get_image_data_from_vnfd(vnfd, sw_image_id)
)
vld["name"] = vld["id"]
nsr_descriptor["vld"] = nsr_vld
+ if nsd.get("vnffgd"):
+ vnffgd = nsd.get("vnffgd")
+ for vnffg in vnffgd:
+ info = {}
+ for k, v in vnffg.items():
+ if k == "id":
+ info.update({k: v})
+ if k == "nfpd":
+ info.update({k: v})
+ nsr_descriptor["vnffgd"].append(info)
return nsr_descriptor
if (
cpd.get("constituent-cpd-id")
== iface_ext_cp
- ):
+ ) and vnf_profile.get("id") == vnf_index:
vdu_iface["ns-vld-id"] = vlc.get(
"virtual-link-profile-id"
)
if nsr_flavor_desc:
vdur["ns-flavor-id"] = nsr_flavor_desc["id"]
+ # Adding Shared Volume information to vdur
+ if vdur.get("virtual-storages"):
+ nsr_sv = []
+ for vsd in vdur["virtual-storages"]:
+ if vsd.get("vdu-storage-requirements"):
+ if (
+ vsd["vdu-storage-requirements"][0].get("key")
+ == "multiattach"
+ and vsd["vdu-storage-requirements"][0].get("value")
+ == "True"
+ ):
+ nsr_sv.append(vsd["id"])
+ if nsr_sv:
+ vdur["shared-volumes-id"] = nsr_sv
+
# Adding Affinity groups information to vdur
try:
vdu_profile_affinity_group = utils.find_in_list(
vdur["id"] = vdur["_id"]
vdur["count-index"] = index
vnfr_descriptor["vdur"].append(vdur)
-
return vnfr_descriptor
def vca_status_refresh(self, session, ns_instance_content, filter_q):
"heal": ns_heal,
"terminate": ns_terminate,
"migrate": ns_migrate,
- "verticalscale": ns_verticalscale,
+ "cancel": nslcmop_cancel,
}
def __init__(self, db, fs, msg, auth):
If updateType is REMOVE_VNF:
- it checks if the vnfInstanceId is available in the ns instance
- Otherwise exception will be raised.
+ If updateType is OPERATE_VNF
+ - it checks if the vdu-id is persent in the descriptor or not
+ - it checks if the changeStateTo is either start, stop or rebuild
+ If updateType is VERTICAL_SCALE
+ - it checks if the vdu-id is persent in the descriptor or not
Args:
indata: includes updateType such as CHANGE_VNFPKG,
"Invalid VNF Instance Id. '{}' is not "
"present in the NS '{}'".format(vnf_instance_id, ns_instance_id)
)
+ elif indata["updateType"] == "OPERATE_VNF":
+ if indata.get("operateVnfData"):
+ if indata["operateVnfData"]["changeStateTo"] not in (
+ "start",
+ "stop",
+ "rebuild",
+ ):
+ raise EngineException(
+ f"The operate type should be either start, stop or rebuild not {indata['operateVnfData']['changeStateTo']}",
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY,
+ )
+ if indata["operateVnfData"].get("additionalParam"):
+ vdu_id = indata["operateVnfData"]["additionalParam"]["vdu_id"]
+ vnfinstance_id = indata["operateVnfData"]["vnfInstanceId"]
+ vnf = self.db.get_one("vnfrs", {"_id": vnfinstance_id})
+ vnfd_member_vnf_index = vnf.get("member-vnf-index-ref")
+ vnfd = self._get_vnfd_from_vnf_member_index(
+ vnfd_member_vnf_index, nsr["_id"]
+ )
+ self._check_valid_vdu(vnfd, vdu_id)
+ elif indata["updateType"] == "VERTICAL_SCALE":
+ if indata.get("verticalScaleVnf"):
+ vdu_id = indata["verticalScaleVnf"]["vduId"]
+ vnfinstance_id = indata["verticalScaleVnf"]["vnfInstanceId"]
+ vnf = self.db.get_one("vnfrs", {"_id": vnfinstance_id})
+ vnfd_member_vnf_index = vnf.get("member-vnf-index-ref")
+ vnfd = self._get_vnfd_from_vnf_member_index(
+ vnfd_member_vnf_index, nsr["_id"]
+ )
+ self._check_valid_vdu(vnfd, vdu_id)
except (
DbException,
return (
None,
None,
+ None,
) # a none in this case is used to indicate not instantiated. It can be removed
if operation != "instantiate":
raise EngineException(
new_sw_version = vnfd.get("software-version", "1.0")
if new_sw_version != old_sw_version:
vnf_index = vnfr["member-vnf-index-ref"]
- self.logger.info("nsr {}".format(nsr))
for vdu in vnfd["vdu"]:
+ self.nsrtopic._add_shared_volumes_to_nsr(
+ vdu, vnfd, nsr, vnf_index, latest_vnfd_revision
+ )
self.nsrtopic._add_flavor_to_nsr(
vdu, vnfd, nsr, vnf_index, latest_vnfd_revision
)
self.nsrtopic._add_image_to_nsr(nsr, image_data)
nsr_update["image"] = nsr["image"]
nsr_update["flavor"] = nsr["flavor"]
+ nsr_update["shared-volumes"] = nsr["shared-volumes"]
self.db.set_one("nsrs", {"_id": nsr["_id"]}, nsr_update)
ns_k8s_namespace = self.nsrtopic._get_ns_k8s_namespace(
nsd, ns_request, session
indata["newVdur"] = vnfr_descriptor["vdur"]
nslcmop_desc = self._create_nslcmop(nsInstanceId, operation, indata)
_id = nslcmop_desc["_id"]
+ nsName = nsr.get("name")
self.format_on_new(
nslcmop_desc, session["project_id"], make_public=session["public"]
)
rollback.append({"topic": "nslcmops", "_id": _id})
if not slice_object:
self.msg.write("ns", operation, nslcmop_desc)
- return _id, None
+ return _id, nsName, None
except ValidationError as e: # TODO remove try Except, it is captured at nbi.py
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
# except DbException as e:
# raise EngineException("Cannot get ns_instance '{}': {}".format(e), HTTPStatus.NOT_FOUND)
+ def cancel(self, rollback, session, indata=None, kwargs=None, headers=None):
+ validate_input(indata, self.operation_schema["cancel"])
+ # Override descriptor with query string kwargs
+ self._update_input_with_kwargs(indata, kwargs, yaml_format=True)
+ nsLcmOpOccId = indata["nsLcmOpOccId"]
+ cancelMode = indata["cancelMode"]
+ # get nslcmop from nsLcmOpOccId
+ _filter = BaseTopic._get_project_filter(session)
+ _filter["_id"] = nsLcmOpOccId
+ nslcmop = self.db.get_one("nslcmops", _filter)
+ # Fail is this is not an ongoing nslcmop
+ if nslcmop.get("operationState") not in [
+ "STARTING",
+ "PROCESSING",
+ "ROLLING_BACK",
+ ]:
+ raise EngineException(
+ "Operation is not in STARTING, PROCESSING or ROLLING_BACK state",
+ http_code=HTTPStatus.CONFLICT,
+ )
+ nsInstanceId = nslcmop["nsInstanceId"]
+ update_dict = {
+ "isCancelPending": True,
+ "cancelMode": cancelMode,
+ }
+ self.db.set_one(
+ "nslcmops", q_filter=_filter, update_dict=update_dict, fail_on_empty=False
+ )
+ data = {
+ "_id": nsLcmOpOccId,
+ "nsInstanceId": nsInstanceId,
+ "cancelMode": cancelMode,
+ }
+ self.msg.write("nslcmops", "cancel", data)
+
def delete(self, session, _id, dry_run=False, not_send_msg=None):
raise EngineException(
"Method delete called directly", HTTPStatus.INTERNAL_SERVER_ERROR
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
except Exception as e: # TODO remove try Except, it is captured at nbi.py
- self.logger.exception(
- "Exception {} at NsiTopic.new()".format(e), exc_info=True
- )
+ # self.logger.exception(
+ # "Exception {} at NsiTopic.new()".format(e), exc_info=True
+ # )
raise EngineException("Error {}: {}".format(step, e))
def edit(self, session, _id, indata=None, kwargs=None, content=None):
_filter = self._get_project_filter(session)
_filter["_id"] = netsliceInstanceId
nsir = self.db.get_one("nsis", _filter)
- logging_prefix = "nsi={} {} ".format(netsliceInstanceId, operation)
+ # logging_prefix = "nsi={} {} ".format(netsliceInstanceId, operation)
del _filter["_id"]
# initial checking
# Creating NS_LCM_OP with the flag slice_object=True to not trigger the service instantiation
# message via kafka bus
- nslcmop, _ = self.nsi_NsLcmOpTopic.new(
+ nslcmop, _, _ = self.nsi_NsLcmOpTopic.new(
rollback, session, indata_ns, None, headers, slice_object=True
)
nslcmops.append(nslcmop)
self.db.set_one("nsis", {"_id": nsir["_id"]}, _update)
except (DbException, EngineException) as e:
if e.http_code == HTTPStatus.NOT_FOUND:
- self.logger.info(
- logging_prefix
- + "skipping NS={} because not found".format(nsr_id)
- )
pass
else:
raise