X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FNBI.git;a=blobdiff_plain;f=osm_nbi%2Finstance_topics.py;h=986d4d3e062f83b75f7bcaabd5c77df0a4335977;hp=16e9ade7171127c4b627076235ad0748dbf38e7f;hb=b091dc1758a3ac2838d5c6d324e8cacaa11be7d7;hpb=9cb7d67d7b0440ae9cbf0a08362bb3c0a19fdc3b;ds=sidebyside diff --git a/osm_nbi/instance_topics.py b/osm_nbi/instance_topics.py index 16e9ade..986d4d3 100644 --- a/osm_nbi/instance_topics.py +++ b/osm_nbi/instance_topics.py @@ -19,7 +19,7 @@ from http import HTTPStatus from time import time from copy import copy, deepcopy from osm_nbi.validation import validate_input, ValidationError, ns_instantiate, ns_action, ns_scale, nsi_instantiate -from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable +from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable, deep_get # from descriptor_topics import DescriptorTopic from yaml import safe_dump from osm_common.dbbase import DbException @@ -119,29 +119,41 @@ class NsrTopic(BaseTopic): return formated_request @staticmethod - def _format_addional_params(ns_request, member_vnf_index=None, descriptor=None): + def _format_addional_params(ns_request, member_vnf_index=None, vdu_id=None, kdu_name=None, descriptor=None): """ Get and format user additional params for NS or VNF :param ns_request: User instantiation additional parameters :param member_vnf_index: None for extract NS params, or member_vnf_index to extract VNF params :param descriptor: If not None it check that needed parameters of descriptor are supplied - :return: a formated copy of additional params or None if not supplied + :return: a formatted copy of additional params or None if not supplied """ additional_params = None if not member_vnf_index: additional_params = copy(ns_request.get("additionalParamsForNs")) where_ = "additionalParamsForNs" elif ns_request.get("additionalParamsForVnf"): - for additionalParamsForVnf in get_iterable(ns_request.get("additionalParamsForVnf")): - if additionalParamsForVnf["member-vnf-index"] == member_vnf_index: - additional_params = copy(additionalParamsForVnf.get("additionalParams")) - where_ = "additionalParamsForVnf[member-vnf-index={}]".format( - additionalParamsForVnf["member-vnf-index"]) - break + where_ = "additionalParamsForVnf[member-vnf-index={}]".format(member_vnf_index) + item = next((x for x in ns_request["additionalParamsForVnf"] if x["member-vnf-index"] == member_vnf_index), + None) + if item: + additional_params = copy(item.get("additionalParams")) or {} + if vdu_id and item.get("additionalParamsForVdu"): + item_vdu = next((x for x in item["additionalParamsForVdu"] if x["vdu_id"] == vdu_id), None) + if item_vdu and item_vdu.get("additionalParams"): + where_ += ".additionalParamsForVdu[vdu_id={}]".format(vdu_id) + additional_params = item_vdu["additionalParams"] + if kdu_name: + additional_params = {} + if item.get("additionalParamsForKdu"): + item_kdu = next((x for x in item["additionalParamsForKdu"] if x["kdu_name"] == kdu_name), None) + if item_kdu and item_kdu.get("additionalParams"): + where_ += ".additionalParamsForKdu[kdu_name={}]".format(kdu_name) + additional_params = item_kdu["additionalParams"] + if additional_params: for k, v in additional_params.items(): - # BEGIN Check that additional parameter names are valid Jinja2 identifiers - if not match('^[a-zA-Z_][a-zA-Z0-9_]*$', k): + # BEGIN Check that additional parameter names are valid Jinja2 identifiers if target is not Kdu + if not kdu_name and not match('^[a-zA-Z_][a-zA-Z0-9_]*$', k): raise EngineException("Invalid param name at {}:{}. Must contain only alphanumeric characters " "and underscores, and cannot start with a digit" .format(where_, k)) @@ -157,20 +169,28 @@ class NsrTopic(BaseTopic): # check that enough parameters are supplied for the initial-config-primitive # TODO: check for cloud-init if member_vnf_index: - if descriptor.get("vnf-configuration"): - for initial_primitive in get_iterable( - descriptor["vnf-configuration"].get("initial-config-primitive")): - for param in get_iterable(initial_primitive.get("parameter")): - if param["value"].startswith("<") and param["value"].endswith(">"): - if param["value"] in ("", ""): - continue - if not additional_params or param["value"][1:-1] not in additional_params: - raise EngineException("Parameter '{}' needed for vnfd[id={}]:vnf-configuration:" - "initial-config-primitive[name={}] not supplied". - format(param["value"], descriptor["id"], - initial_primitive["name"])) + if kdu_name: + initial_primitives = None + elif vdu_id: + vdud = next(x for x in descriptor["vdu"] if x["id"] == vdu_id) + initial_primitives = deep_get(vdud, ("vdu-configuration", "initial-config-primitive")) + else: + initial_primitives = deep_get(descriptor, ("vnf-configuration", "initial-config-primitive")) + else: + initial_primitives = deep_get(descriptor, ("ns-configuration", "initial-config-primitive")) - return additional_params + for initial_primitive in get_iterable(initial_primitives): + for param in get_iterable(initial_primitive.get("parameter")): + if param["value"].startswith("<") and param["value"].endswith(">"): + if param["value"] in ("", "", ""): + continue + if not additional_params or param["value"][1:-1] not in additional_params: + raise EngineException("Parameter '{}' needed for vnfd[id={}]:vnf-configuration:" + "initial-config-primitive[name={}] not supplied". + format(param["value"], descriptor["id"], + initial_primitive["name"])) + + return additional_params or None def new(self, rollback, session, indata=None, kwargs=None, headers=None): """ @@ -231,7 +251,7 @@ class NsrTopic(BaseTopic): "nsd-id": nsd["_id"], "vnfd-id": [], "instantiate_params": self._format_ns_request(ns_request), - "additionalParamsForNs": self._format_addional_params(ns_request), + "additionalParamsForNs": self._format_addional_params(ns_request, descriptor=nsd), "ns-instance-config-ref": nsr_id, "id": nsr_id, "_id": nsr_id, @@ -271,7 +291,7 @@ class NsrTopic(BaseTopic): "nsr-id-ref": nsr_id, "member-vnf-index-ref": member_vnf["member-vnf-index"], "additionalParamsForVnf": self._format_addional_params(ns_request, member_vnf["member-vnf-index"], - vnfd), + descriptor=vnfd), "created-time": now, # "vnfd": vnfd, # at OSM model.but removed to avoid data duplication TODO: revise "vnfd-ref": vnfd_id, @@ -301,14 +321,39 @@ class NsrTopic(BaseTopic): } vnfr_descriptor["connection-point"].append(vnf_cp) + # Create k8s-cluster information + if vnfd.get("k8s-cluster"): + vnfr_descriptor["k8s-cluster"] = vnfd["k8s-cluster"] + for net in get_iterable(vnfr_descriptor["k8s-cluster"].get("nets")): + if net.get("external-connection-point-ref"): + for nsd_vld in get_iterable(nsd.get("vld")): + for nsd_vld_cp in get_iterable(nsd_vld.get("vnfd-connection-point-ref")): + if nsd_vld_cp.get("vnfd-connection-point-ref") == \ + net["external-connection-point-ref"] and \ + nsd_vld_cp.get("member-vnf-index-ref") == member_vnf["member-vnf-index"]: + net["ns-vld-id"] = nsd_vld["id"] + break + else: + continue + break + elif net.get("internal-connection-point-ref"): + for vnfd_ivld in get_iterable(vnfd.get("internal-vld")): + for vnfd_ivld_icp in get_iterable(vnfd_ivld.get("internal-connection-point")): + if vnfd_ivld_icp.get("id-ref") == net["internal-connection-point-ref"]: + net["vnf-vld-id"] = vnfd_ivld["id"] + break + else: + continue + break # update kdus for kdu in get_iterable(vnfd.get("kdu")): - kdur = { - "kdu-name": kdu["name"], - # TODO "name": "" Name of the VDU in the VIM - "ip-address": None, # mgmt-interface filled by LCM - "k8s-cluster": kdu.get("k8s-cluster") or {} - } + kdur = {x: kdu[x] for x in kdu if x in ("helm-chart", "juju-bundle")} + kdur["kdu-name"] = kdu["name"] + # TODO "name": "" Name of the VDU in the VIM + kdur["ip-address"] = None, # mgmt-interface filled by LCM + kdur["k8s-cluster"] = {}, + kdur["additionalParams"] = self._format_addional_params(ns_request, member_vnf["member-vnf-index"], + kdu_name=kdu["name"], descriptor=vnfd), if not vnfr_descriptor.get("kdur"): vnfr_descriptor["kdur"] = [] vnfr_descriptor["kdur"].append(kdur) @@ -321,6 +366,8 @@ class NsrTopic(BaseTopic): # "vim-id", "flavor-id", "image-id", "management-ip" # filled by LCM "internal-connection-point": [], "interfaces": [], + "additionalParams": self._format_addional_params(ns_request, member_vnf["member-vnf-index"], + vdu_id=vdu["id"], descriptor=vnfd), } if vdu.get("pdu-type"): vdur["pdu-type"] = vdu["pdu-type"] @@ -560,7 +607,7 @@ class NsLcmOpTopic(BaseTopic): vdud = check_valid_vdu(vnfd, indata["vdu_id"]) descriptor_configuration = vdud.get("vdu-configuration", {}).get("config-primitive") elif indata.get("kdu_name"): - kdud = check_valid_kdu(vnfd, indata["vdu_name"]) + kdud = check_valid_kdu(vnfd, indata["kdu_name"]) descriptor_configuration = kdud.get("kdu-configuration", {}).get("config-primitive") else: descriptor_configuration = vnfd.get("vnf-configuration", {}).get("config-primitive") @@ -568,8 +615,11 @@ class NsLcmOpTopic(BaseTopic): descriptor_configuration = nsd.get("ns-configuration", {}).get("config-primitive") # For k8s allows default primitives without validating the parameters - if indata.get("kdu_name") and indata["primitive"] in ("upgrade", "rollback", "status"): + if indata.get("kdu_name") and indata["primitive"] in ("upgrade", "rollback", "status", "inspect", "readme"): # TODO should be checked that rollback only can contains revsision_numbe???? + if not indata.get("member_vnf_index"): + raise EngineException("Missing action parameter 'member_vnf_index' for default KDU primitive '{}'" + .format(indata["primitive"])) return # if not, check primitive for config_primitive in get_iterable(descriptor_configuration): @@ -713,11 +763,9 @@ class NsLcmOpTopic(BaseTopic): "vnf-vld-id": vdur_interface.get("vnf-vld-id"), "ns-vld-id": vdur_interface.get("ns-vld-id")}) if pdu_interface.get("vim-network-id"): - ifaces_forcing_vim_network.append({ - "vim-network-id": pdu_interface.get("vim-network-id")}) + ifaces_forcing_vim_network[-1]["vim-network-id"] = pdu_interface["vim-network-id"] if pdu_interface.get("vim-network-name"): - ifaces_forcing_vim_network.append({ - "vim-network-name": pdu_interface.get("vim-network-name")}) + ifaces_forcing_vim_network[-1]["vim-network-name"] = pdu_interface["vim-network-name"] break return ifaces_forcing_vim_network @@ -744,36 +792,65 @@ class NsLcmOpTopic(BaseTopic): """ ifaces_forcing_vim_network = [] - for kdur_index, kdur in enumerate(get_iterable(vnfr.get("kdur"))): - kdu_filter = self._get_project_filter(session) - kdu_filter["vim_account"] = vim_account - # TODO kdu_filter["_admin.operationalState"] = "ENABLED" - - available_k8sclusters = self.db.get_list("k8sclusters", kdu_filter) - k8s_requirements = {} # just for logging - for k8scluster in available_k8sclusters: - # restrict by cni - if kdur["k8s-cluster"].get("cni"): - k8s_requirements["cni"] = kdur["k8s-cluster"]["cni"] - if not set(kdur["k8s-cluster"]["cni"]).intersection(k8scluster.get("cni", ())): - continue - # restrict by version - if kdur["k8s-cluster"].get("version"): - k8s_requirements["version"] = kdur["k8s-cluster"]["version"] - if k8scluster.get("k8s_version") not in kdur["k8s-cluster"]["version"]: - continue + if not vnfr.get("kdur"): + return ifaces_forcing_vim_network + + kdu_filter = self._get_project_filter(session) + kdu_filter["vim_account"] = vim_account + # TODO kdu_filter["_admin.operationalState"] = "ENABLED" + available_k8sclusters = self.db.get_list("k8sclusters", kdu_filter) + + k8s_requirements = {} # just for logging + for k8scluster in available_k8sclusters: + if not vnfr.get("k8s-cluster"): break - else: - raise EngineException( - "No k8scluster with requirements='{}' at vim_account={} found for member_vnf_index={}, kdu={}" - .format(k8s_requirements, vim_account, vnfr["member-vnf-index-ref"], kdur["kdu-name"])) + # restrict by cni + if vnfr["k8s-cluster"].get("cni"): + k8s_requirements["cni"] = vnfr["k8s-cluster"]["cni"] + if not set(vnfr["k8s-cluster"]["cni"]).intersection(k8scluster.get("cni", ())): + continue + # restrict by version + if vnfr["k8s-cluster"].get("version"): + k8s_requirements["version"] = vnfr["k8s-cluster"]["version"] + if k8scluster.get("k8s_version") not in vnfr["k8s-cluster"]["version"]: + continue + # restrict by number of networks + if vnfr["k8s-cluster"].get("nets"): + k8s_requirements["networks"] = len(vnfr["k8s-cluster"]["nets"]) + if not k8scluster.get("nets") or len(k8scluster["nets"]) < len(vnfr["k8s-cluster"]["nets"]): + continue + break + else: + raise EngineException("No k8scluster with requirements='{}' at vim_account={} found for member_vnf_index={}" + .format(k8s_requirements, vim_account, vnfr["member-vnf-index-ref"])) + for kdur_index, kdur in enumerate(get_iterable(vnfr.get("kdur"))): # step 3. Fill vnfr info by filling kdur kdu_text = "kdur.{}.".format(kdur_index) vnfr_update_rollback[kdu_text + "k8s-cluster.id"] = None vnfr_update[kdu_text + "k8s-cluster.id"] = k8scluster["_id"] - # TODO proccess interfaces ifaces_forcing_vim_network + # step 4. Check VIM networks that forces the selected k8s_cluster + if vnfr.get("k8s-cluster") and vnfr["k8s-cluster"].get("nets"): + k8scluster_net_list = list(k8scluster.get("nets").keys()) + for net_index, kdur_net in enumerate(vnfr["k8s-cluster"]["nets"]): + # get a network from k8s_cluster nets. If name matches use this, if not use other + if kdur_net["id"] in k8scluster_net_list: # name matches + vim_net = k8scluster["nets"][kdur_net["id"]] + k8scluster_net_list.remove(kdur_net["id"]) + else: + vim_net = k8scluster["nets"][k8scluster_net_list[0]] + k8scluster_net_list.pop(0) + vnfr_update_rollback["k8s-cluster.nets.{}.vim_net".format(net_index)] = None + vnfr_update["k8s-cluster.nets.{}.vim_net".format(net_index)] = vim_net + if vim_net and (kdur_net.get("vnf-vld-id") or kdur_net.get("ns-vld-id")): + ifaces_forcing_vim_network.append({ + "name": kdur_net.get("vnf-vld-id") or kdur_net.get("ns-vld-id"), + "vnf-vld-id": kdur_net.get("vnf-vld-id"), + "ns-vld-id": kdur_net.get("ns-vld-id"), + "vim-network-name": vim_net, # TODO can it be vim-network-id ??? + }) + # TODO check that this forcing is not incompatible with other forcing return ifaces_forcing_vim_network def _update_vnfrs(self, session, rollback, nsr, indata):