+ raise type(e)("{} while '{}'".format(e, step), http_code=e.http_code)
+
+ def _get_nsd_from_db(self, nsd_id, session):
+ _filter = self._get_project_filter(session)
+ _filter["_id"] = nsd_id
+ return self.db.get_one("nsds", _filter)
+
+ def _get_vnfd_from_db(self, vnfd_id, session):
+ _filter = self._get_project_filter(session)
+ _filter["id"] = vnfd_id
+ vnfd = self.db.get_one("vnfds", _filter, fail_on_empty=True, fail_on_more=True)
+ vnfd.pop("_admin")
+ return vnfd
+
+ def _add_nsr_to_db(self, nsr_descriptor, rollback, session):
+ self.format_on_new(nsr_descriptor, session["project_id"], make_public=session["public"])
+ self.db.create("nsrs", nsr_descriptor)
+ rollback.append({"topic": "nsrs", "_id": nsr_descriptor["id"]})
+
+ def _add_vnfr_to_db(self, vnfr_descriptor, rollback, session):
+ self.format_on_new(vnfr_descriptor, session["project_id"], make_public=session["public"])
+ self.db.create("vnfrs", vnfr_descriptor)
+ rollback.append({"topic": "vnfrs", "_id": vnfr_descriptor["id"]})
+
+ def _check_nsd_operational_state(self, nsd, ns_request):
+ if nsd["_admin"]["operationalState"] == "DISABLED":
+ raise EngineException("nsd with id '{}' is DISABLED, and thus cannot be used to create "
+ "a network service".format(ns_request["nsdId"]), http_code=HTTPStatus.CONFLICT)
+
+ def _get_ns_k8s_namespace(self, nsd, ns_request, session):
+ additional_params, _ = self._format_additional_params(ns_request, descriptor=nsd)
+ # use for k8s-namespace from ns_request or additionalParamsForNs. By default, the project_id
+ ns_k8s_namespace = session["project_id"][0] if session["project_id"] else None
+ if ns_request and ns_request.get("k8s-namespace"):
+ ns_k8s_namespace = ns_request["k8s-namespace"]
+ if additional_params and additional_params.get("k8s-namespace"):
+ ns_k8s_namespace = additional_params["k8s-namespace"]
+
+ return ns_k8s_namespace
+
+ def _create_nsr_descriptor_from_nsd(self, nsd, ns_request, nsr_id, session):
+ now = time()
+ additional_params, _ = self._format_additional_params(ns_request, descriptor=nsd)
+
+ nsr_descriptor = {
+ "name": ns_request["nsName"],
+ "name-ref": ns_request["nsName"],
+ "short-name": ns_request["nsName"],
+ "admin-status": "ENABLED",
+ "nsState": "NOT_INSTANTIATED",
+ "currentOperation": "IDLE",
+ "currentOperationID": None,
+ "errorDescription": None,
+ "errorDetail": None,
+ "deploymentStatus": None,
+ "configurationStatus": None,
+ "vcaStatus": None,
+ "nsd": {k: v for k, v in nsd.items()},
+ "datacenter": ns_request["vimAccountId"],
+ "resource-orchestrator": "osmopenmano",
+ "description": ns_request.get("nsDescription", ""),
+ "constituent-vnfr-ref": [],
+ "operational-status": "init", # typedef ns-operational-
+ "config-status": "init", # typedef config-states
+ "detailed-status": "scheduled",
+ "orchestration-progress": {},
+ "create-time": now,
+ "nsd-name-ref": nsd["name"],
+ "operational-events": [], # "id", "timestamp", "description", "event",
+ "nsd-ref": nsd["id"],
+ "nsd-id": nsd["_id"],
+ "vnfd-id": [],
+ "instantiate_params": self._format_ns_request(ns_request),
+ "additionalParamsForNs": additional_params,
+ "ns-instance-config-ref": nsr_id,
+ "id": nsr_id,
+ "_id": nsr_id,
+ "ssh-authorized-key": ns_request.get("ssh_keys"), # TODO remove
+ "flavor": [],
+ "image": [],
+ }
+ ns_request["nsr_id"] = nsr_id
+ if ns_request and ns_request.get("config-units"):
+ nsr_descriptor["config-units"] = ns_request["config-units"]
+
+ # Create vld
+ if nsd.get("virtual-link-desc"):
+ nsr_vld = deepcopy(nsd.get("virtual-link-desc", []))
+ # Fill each vld with vnfd-connection-point-ref data
+ # TODO: Change for multiple df support
+ all_vld_connection_point_data = {vld.get("id"): [] for vld in nsr_vld}
+ vnf_profiles = nsd.get("df", [[]])[0].get("vnf-profile", ())
+ for vnf_profile in vnf_profiles:
+ for vlc in vnf_profile.get("virtual-link-connectivity", ()):
+ for cpd in vlc.get("constituent-cpd-id", ()):
+ all_vld_connection_point_data[vlc.get("virtual-link-profile-id")].append({
+ "member-vnf-index-ref": cpd.get("constituent-base-element-id"),
+ "vnfd-connection-point-ref": cpd.get("constituent-cpd-id"),
+ "vnfd-id-ref": vnf_profile.get("vnfd-id")
+ })
+
+ vnfd = self._get_vnfd_from_db(vnf_profile.get("vnfd-id"), session)
+
+ for vdu in vnfd.get("vdu", ()):
+ flavor_data = {}
+ guest_epa = {}
+ # Find this vdu compute and storage descriptors
+ vdu_virtual_compute = {}
+ vdu_virtual_storage = {}
+ for vcd in vnfd.get("virtual-compute-desc", ()):
+ if vcd.get("id") == vdu.get("virtual-compute-desc"):
+ vdu_virtual_compute = vcd
+ for vsd in vnfd.get("virtual-storage-desc", ()):
+ if vsd.get("id") == vdu.get("virtual-storage-desc", [[]])[0]:
+ vdu_virtual_storage = vsd
+ # Get this vdu vcpus, memory and storage info for flavor_data
+ if vdu_virtual_compute.get("virtual-cpu", {}).get("num-virtual-cpu"):
+ flavor_data["vcpu-count"] = vdu_virtual_compute["virtual-cpu"]["num-virtual-cpu"]
+ if vdu_virtual_compute.get("virtual-memory", {}).get("size"):
+ flavor_data["memory-mb"] = float(vdu_virtual_compute["virtual-memory"]["size"]) * 1024.0
+ if vdu_virtual_storage.get("size-of-storage"):
+ flavor_data["storage-gb"] = vdu_virtual_storage["size-of-storage"]
+ # Get this vdu EPA info for guest_epa
+ if vdu_virtual_compute.get("virtual-cpu", {}).get("cpu-quota"):
+ guest_epa["cpu-quota"] = vdu_virtual_compute["virtual-cpu"]["cpu-quota"]
+ if vdu_virtual_compute.get("virtual-cpu", {}).get("pinning"):
+ vcpu_pinning = vdu_virtual_compute["virtual-cpu"]["pinning"]
+ if vcpu_pinning.get("thread-policy"):
+ guest_epa["cpu-thread-pinning-policy"] = vcpu_pinning["thread-policy"]
+ if vcpu_pinning.get("policy"):
+ cpu_policy = "SHARED" if vcpu_pinning["policy"] == "dynamic" else "DEDICATED"
+ guest_epa["cpu-pinning-policy"] = cpu_policy
+ if vdu_virtual_compute.get("virtual-memory", {}).get("mem-quota"):
+ guest_epa["mem-quota"] = vdu_virtual_compute["virtual-memory"]["mem-quota"]
+ if vdu_virtual_compute.get("virtual-memory", {}).get("mempage-size"):
+ guest_epa["mempage-size"] = vdu_virtual_compute["virtual-memory"]["mempage-size"]
+ if vdu_virtual_compute.get("virtual-memory", {}).get("numa-node-policy"):
+ guest_epa["numa-node-policy"] = vdu_virtual_compute["virtual-memory"]["numa-node-policy"]
+ if vdu_virtual_storage.get("disk-io-quota"):
+ guest_epa["disk-io-quota"] = vdu_virtual_storage["disk-io-quota"]
+
+ if guest_epa:
+ flavor_data["guest-epa"] = guest_epa
+
+ flavor_data["name"] = vdu["id"][:56] + "-flv"
+ flavor_data["id"] = str(len(nsr_descriptor["flavor"]))
+ nsr_descriptor["flavor"].append(flavor_data)
+
+ sw_image_id = vdu.get("sw-image-desc")
+ if sw_image_id:
+ image_data = self._get_image_data_from_vnfd(vnfd, sw_image_id)
+ self._add_image_to_nsr(nsr_descriptor, image_data)
+
+ # also add alternative images to the list of images
+ for alt_image in vdu.get("alternative-sw-image-desc", ()):
+ image_data = self._get_image_data_from_vnfd(vnfd, alt_image)
+ self._add_image_to_nsr(nsr_descriptor, image_data)
+
+ for vld in nsr_vld:
+ vld["vnfd-connection-point-ref"] = all_vld_connection_point_data.get(vld.get("id"), [])
+ vld["name"] = vld["id"]
+ nsr_descriptor["vld"] = nsr_vld
+
+ return nsr_descriptor
+
+ def _get_image_data_from_vnfd(self, vnfd, sw_image_id):
+ sw_image_desc = utils.find_in_list(vnfd.get("sw-image-desc", ()),
+ lambda sw: sw["id"] == sw_image_id)
+ image_data = {}
+ if sw_image_desc.get("image"):
+ image_data["image"] = sw_image_desc["image"]
+ if sw_image_desc.get("checksum"):
+ image_data["image_checksum"] = sw_image_desc["checksum"]["hash"]
+ if sw_image_desc.get("vim-type"):
+ image_data["vim-type"] = sw_image_desc["vim-type"]
+ return image_data
+
+ def _add_image_to_nsr(self, nsr_descriptor, image_data):
+ """
+ Adds image to nsr checking first it is not already added
+ """
+ img = next((f for f in nsr_descriptor["image"] if
+ all(f.get(k) == image_data[k] for k in image_data)), None)
+ if not img:
+ image_data["id"] = str(len(nsr_descriptor["image"]))
+ nsr_descriptor["image"].append(image_data)
+
+ def _create_vnfr_descriptor_from_vnfd(self, nsd, vnfd, vnfd_id, vnf_index, nsr_descriptor,
+ ns_request, ns_k8s_namespace):
+ vnfr_id = str(uuid4())
+ nsr_id = nsr_descriptor["id"]
+ now = time()
+ additional_params, vnf_params = self._format_additional_params(ns_request, vnf_index, descriptor=vnfd)
+
+ vnfr_descriptor = {
+ "id": vnfr_id,
+ "_id": vnfr_id,
+ "nsr-id-ref": nsr_id,
+ "member-vnf-index-ref": vnf_index,
+ "additionalParamsForVnf": additional_params,
+ "created-time": now,
+ # "vnfd": vnfd, # at OSM model.but removed to avoid data duplication TODO: revise
+ "vnfd-ref": vnfd_id,
+ "vnfd-id": vnfd["_id"], # not at OSM model, but useful
+ "vim-account-id": None,
+ "vca-id": None,
+ "vdur": [],
+ "connection-point": [],
+ "ip-address": None, # mgmt-interface filled by LCM
+ }
+ vnf_k8s_namespace = ns_k8s_namespace
+ if vnf_params:
+ if vnf_params.get("k8s-namespace"):
+ vnf_k8s_namespace = vnf_params["k8s-namespace"]
+ if vnf_params.get("config-units"):
+ vnfr_descriptor["config-units"] = vnf_params["config-units"]
+
+ # Create vld
+ if vnfd.get("int-virtual-link-desc"):
+ vnfr_descriptor["vld"] = []
+ for vnfd_vld in vnfd.get("int-virtual-link-desc"):
+ vnfr_descriptor["vld"].append({key: vnfd_vld[key] for key in vnfd_vld})
+
+ for cp in vnfd.get("ext-cpd", ()):
+ vnf_cp = {
+ "name": cp.get("id"),
+ "connection-point-id": cp.get("int-cpd", {}).get("cpd"),
+ "connection-point-vdu-id": cp.get("int-cpd", {}).get("vdu-id"),
+ "id": cp.get("id"),
+ # "ip-address", "mac-address" # filled by LCM
+ # vim-id # TODO it would be nice having a vim port id
+ }
+ vnfr_descriptor["connection-point"].append(vnf_cp)
+
+ # Create k8s-cluster information
+ # TODO: Validate if a k8s-cluster net can have more than one ext-cpd ?
+ if vnfd.get("k8s-cluster"):
+ vnfr_descriptor["k8s-cluster"] = vnfd["k8s-cluster"]
+ all_k8s_cluster_nets_cpds = {}
+ for cpd in get_iterable(vnfd.get("ext-cpd")):
+ if cpd.get("k8s-cluster-net"):
+ all_k8s_cluster_nets_cpds[cpd.get("k8s-cluster-net")] = cpd.get("id")
+ for net in get_iterable(vnfr_descriptor["k8s-cluster"].get("nets")):
+ if net.get("id") in all_k8s_cluster_nets_cpds:
+ net["external-connection-point-ref"] = all_k8s_cluster_nets_cpds[net.get("id")]
+
+ # update kdus
+ for kdu in get_iterable(vnfd.get("kdu")):
+ additional_params, kdu_params = self._format_additional_params(ns_request,
+ vnf_index,
+ kdu_name=kdu["name"],
+ descriptor=vnfd)
+ kdu_k8s_namespace = vnf_k8s_namespace
+ kdu_model = kdu_params.get("kdu_model") if kdu_params else None
+ if kdu_params and kdu_params.get("k8s-namespace"):
+ kdu_k8s_namespace = kdu_params["k8s-namespace"]
+
+ kdur = {
+ "additionalParams": additional_params,
+ "k8s-namespace": kdu_k8s_namespace,
+ "kdu-name": kdu["name"],
+ # TODO "name": "" Name of the VDU in the VIM
+ "ip-address": None, # mgmt-interface filled by LCM
+ "k8s-cluster": {},
+ }
+ if kdu_params and kdu_params.get("config-units"):
+ kdur["config-units"] = kdu_params["config-units"]
+ if kdu.get("helm-version"):
+ kdur["helm-version"] = kdu["helm-version"]
+ for k8s_type in ("helm-chart", "juju-bundle"):
+ if kdu.get(k8s_type):
+ kdur[k8s_type] = kdu_model or kdu[k8s_type]
+ if not vnfr_descriptor.get("kdur"):
+ vnfr_descriptor["kdur"] = []
+ vnfr_descriptor["kdur"].append(kdur)
+
+ vnfd_mgmt_cp = vnfd.get("mgmt-cp")
+
+ for vdu in vnfd.get("vdu", ()):
+ vdu_mgmt_cp = []
+ try:
+ configs = vnfd.get("df")[0]["lcm-operations-configuration"]["operate-vnf-op-config"]["day1-2"]
+ vdu_config = utils.find_in_list(configs, lambda config: config["id"] == vdu["id"])
+ except Exception:
+ vdu_config = None
+
+ try:
+ vdu_instantiation_level = utils.find_in_list(
+ vnfd.get("df")[0]["instantiation-level"][0]["vdu-level"],
+ lambda a_vdu_profile: a_vdu_profile["vdu-id"] == vdu["id"]
+ )
+ except Exception:
+ vdu_instantiation_level = None
+
+ if vdu_config:
+ external_connection_ee = utils.filter_in_list(
+ vdu_config.get("execution-environment-list", []),
+ lambda ee: "external-connection-point-ref" in ee
+ )
+ for ee in external_connection_ee:
+ vdu_mgmt_cp.append(ee["external-connection-point-ref"])
+
+ additional_params, vdu_params = self._format_additional_params(
+ ns_request, vnf_index, vdu_id=vdu["id"], descriptor=vnfd)
+ vdur = {
+ "vdu-id-ref": vdu["id"],
+ # TODO "name": "" Name of the VDU in the VIM
+ "ip-address": None, # mgmt-interface filled by LCM
+ # "vim-id", "flavor-id", "image-id", "management-ip" # filled by LCM
+ "internal-connection-point": [],
+ "interfaces": [],
+ "additionalParams": additional_params,
+ "vdu-name": vdu["name"]
+ }
+ if vdu_params and vdu_params.get("config-units"):
+ vdur["config-units"] = vdu_params["config-units"]
+ if deep_get(vdu, ("supplemental-boot-data", "boot-data-drive")):
+ vdur["boot-data-drive"] = vdu["supplemental-boot-data"]["boot-data-drive"]
+ if vdu.get("pdu-type"):
+ vdur["pdu-type"] = vdu["pdu-type"]
+ vdur["name"] = vdu["pdu-type"]
+ # TODO volumes: name, volume-id
+ for icp in vdu.get("int-cpd", ()):
+ vdu_icp = {
+ "id": icp["id"],
+ "connection-point-id": icp["id"],
+ "name": icp.get("id"),
+ }
+
+ vdur["internal-connection-point"].append(vdu_icp)
+
+ for iface in icp.get("virtual-network-interface-requirement", ()):
+ iface_fields = ("name", "mac-address")
+ vdu_iface = {x: iface[x] for x in iface_fields if iface.get(x) is not None}
+
+ vdu_iface["internal-connection-point-ref"] = vdu_icp["id"]
+ if "port-security-enabled" in icp:
+ vdu_iface["port-security-enabled"] = icp["port-security-enabled"]
+
+ if "port-security-disable-strategy" in icp:
+ vdu_iface["port-security-disable-strategy"] = icp["port-security-disable-strategy"]
+
+ for ext_cp in vnfd.get("ext-cpd", ()):
+ if not ext_cp.get("int-cpd"):
+ continue
+ if ext_cp["int-cpd"].get("vdu-id") != vdu["id"]:
+ continue
+ if icp["id"] == ext_cp["int-cpd"].get("cpd"):
+ vdu_iface["external-connection-point-ref"] = ext_cp.get("id")
+
+ if "port-security-enabled" in ext_cp:
+ vdu_iface["port-security-enabled"] = (
+ ext_cp["port-security-enabled"]
+ )
+
+ if "port-security-disable-strategy" in ext_cp:
+ vdu_iface["port-security-disable-strategy"] = (
+ ext_cp["port-security-disable-strategy"]
+ )
+
+ break
+
+ if vnfd_mgmt_cp and vdu_iface.get("external-connection-point-ref") == vnfd_mgmt_cp:
+ vdu_iface["mgmt-vnf"] = True
+ vdu_iface["mgmt-interface"] = True
+
+ for ecp in vdu_mgmt_cp:
+ if vdu_iface.get("external-connection-point-ref") == ecp:
+ vdu_iface["mgmt-interface"] = True
+
+ if iface.get("virtual-interface"):
+ vdu_iface.update(deepcopy(iface["virtual-interface"]))
+
+ # look for network where this interface is connected
+ iface_ext_cp = vdu_iface.get("external-connection-point-ref")
+ if iface_ext_cp:
+ # TODO: Change for multiple df support
+ for df in get_iterable(nsd.get("df")):
+ for vnf_profile in get_iterable(df.get("vnf-profile")):
+ for vlc_index, vlc in \
+ enumerate(get_iterable(vnf_profile.get("virtual-link-connectivity"))):
+ for cpd in get_iterable(vlc.get("constituent-cpd-id")):
+ if cpd.get("constituent-cpd-id") == iface_ext_cp:
+ vdu_iface["ns-vld-id"] = vlc.get("virtual-link-profile-id")
+ # if iface type is SRIOV or PASSTHROUGH, set pci-interfaces flag to True
+ if vdu_iface.get("type") in ("SR-IOV", "PCI-PASSTHROUGH"):
+ nsr_descriptor["vld"][vlc_index]["pci-interfaces"] = True
+ break
+ elif vdu_iface.get("internal-connection-point-ref"):
+ vdu_iface["vnf-vld-id"] = icp.get("int-virtual-link-desc")
+ # TODO: store fixed IP address in the record (if it exists in the ICP)
+ # if iface type is SRIOV or PASSTHROUGH, set pci-interfaces flag to True
+ if vdu_iface.get("type") in ("SR-IOV", "PCI-PASSTHROUGH"):
+ ivld_index = utils.find_index_in_list(vnfd.get("int-virtual-link-desc", ()),
+ lambda ivld:
+ ivld["id"] == icp.get("int-virtual-link-desc")
+ )
+ vnfr_descriptor["vld"][ivld_index]["pci-interfaces"] = True
+
+ vdur["interfaces"].append(vdu_iface)
+
+ if vdu.get("sw-image-desc"):
+ sw_image = utils.find_in_list(
+ vnfd.get("sw-image-desc", ()),
+ lambda image: image["id"] == vdu.get("sw-image-desc"))
+ nsr_sw_image_data = utils.find_in_list(
+ nsr_descriptor["image"],
+ lambda nsr_image: (nsr_image.get("image") == sw_image.get("image"))
+ )
+ vdur["ns-image-id"] = nsr_sw_image_data["id"]
+
+ if vdu.get("alternative-sw-image-desc"):
+ alt_image_ids = []
+ for alt_image_id in vdu.get("alternative-sw-image-desc", ()):
+ sw_image = utils.find_in_list(
+ vnfd.get("sw-image-desc", ()),
+ lambda image: image["id"] == alt_image_id)
+ nsr_sw_image_data = utils.find_in_list(
+ nsr_descriptor["image"],
+ lambda nsr_image: (nsr_image.get("image") == sw_image.get("image"))
+ )
+ alt_image_ids.append(nsr_sw_image_data["id"])
+ vdur["alt-image-ids"] = alt_image_ids
+
+ flavor_data_name = vdu["id"][:56] + "-flv"
+ nsr_flavor_desc = utils.find_in_list(
+ nsr_descriptor["flavor"],
+ lambda flavor: flavor["name"] == flavor_data_name)
+
+ if nsr_flavor_desc:
+ vdur["ns-flavor-id"] = nsr_flavor_desc["id"]
+
+ if vdu_instantiation_level:
+ count = vdu_instantiation_level.get("number-of-instances")
+ else:
+ count = 1
+
+ for index in range(0, count):
+ vdur = deepcopy(vdur)
+ for iface in vdur["interfaces"]:
+ if iface.get("ip-address"):
+ iface["ip-address"] = increment_ip_mac(iface["ip-address"])
+ if iface.get("mac-address"):
+ iface["mac-address"] = increment_ip_mac(iface["mac-address"])
+
+ vdur["_id"] = str(uuid4())
+ vdur["id"] = vdur["_id"]
+ vdur["count-index"] = index
+ vnfr_descriptor["vdur"].append(vdur)
+
+ return vnfr_descriptor