# && cd ..
# OSM_IM
-RUN git -C /app clone https://osm.etsi.org/gerrit/osm/IM \
+RUN git -C /app clone --branch sol006 https://osm.etsi.org/gerrit/osm/IM \
&& python3 -m pip install /app/IM
EXPOSE 9999
import tarfile
import yaml
import json
+import importlib
# import logging
from hashlib import md5
from osm_common.dbbase import DbException, deep_update_rfc7396
from osm_nbi.validation import ValidationError, pdu_new_schema, pdu_edit_schema, \
validate_input, vnfpkgop_new_schema
from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable
-from osm_im.vnfd import vnfd as vnfd_im
-from osm_im.nsd import nsd as nsd_im
+etsi_nfv_vnfd = importlib.import_module("osm_im.etsi-nfv-vnfd")
+etsi_nfv_nsd = importlib.import_module("osm_im.etsi-nfv-nsd")
from osm_im.nst import nst as nst_im
from pyangbind.lib.serialise import pybindJSONDecoder
import pyangbind.lib.pybindJSON as pybindJSON
# 1.3. restore internal keys
for k, v in internal_keys.items():
final_content[k] = v
-
if session["force"]:
return
# 2. check that this id is not present
# Override descriptor with query string kwargs
if kwargs:
self._update_input_with_kwargs(indata, kwargs)
- # it will call overrides method at VnfdTopic or NsdTopic
- # indata = self._validate_input_edit(indata, force=session["force"])
deep_update_rfc7396(current_desc, indata)
self.check_conflict_on_edit(session, current_desc, indata, _id=_id)
"future versions", http_code=HTTPStatus.NOT_ACCEPTABLE)
return self.fs.file_open((storage['folder'], storage['zipfile']), "rb"), accept_zip
- def pyangbind_validation(self, item, data, force=False):
- try:
- if item == "vnfds":
- myvnfd = vnfd_im()
- pybindJSONDecoder.load_ietf_json({'vnfd:vnfd-catalog': {'vnfd': [data]}}, None, None, obj=myvnfd,
- path_helper=True, skip_unknown=force)
- out = pybindJSON.dumps(myvnfd, mode="ietf")
- elif item == "nsds":
- mynsd = nsd_im()
- pybindJSONDecoder.load_ietf_json({'nsd:nsd-catalog': {'nsd': [data]}}, None, None, obj=mynsd,
- path_helper=True, skip_unknown=force)
- out = pybindJSON.dumps(mynsd, mode="ietf")
- elif item == "nsts":
- mynst = nst_im()
- pybindJSONDecoder.load_ietf_json({'nst': [data]}, None, None, obj=mynst,
- path_helper=True, skip_unknown=force)
- out = pybindJSON.dumps(mynst, mode="ietf")
- else:
- raise EngineException("Not possible to validate '{}' item".format(item),
- http_code=HTTPStatus.INTERNAL_SERVER_ERROR)
-
- desc_out = self._remove_envelop(yaml.safe_load(out))
- return desc_out
+ def _remove_yang_prefixes_from_descriptor(self, descriptor):
+ new_descriptor = {}
+ for k, v in descriptor.items():
+ new_v = v
+ if isinstance(v, dict):
+ new_v = self._remove_yang_prefixes_from_descriptor(v)
+ elif isinstance(v, list):
+ new_v = list()
+ for x in v:
+ if isinstance(x, dict):
+ new_v.append(self._remove_yang_prefixes_from_descriptor(x))
+ else:
+ new_v.append(x)
+ new_descriptor[k.split(':')[-1]] = new_v
+ return new_descriptor
- except Exception as e:
- raise EngineException("Error in pyangbind validation: {}".format(str(e)),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ def pyangbind_validation(self, item, data, force=False):
+ raise EngineException("Not possible to validate '{}' item".format(item),
+ http_code=HTTPStatus.INTERNAL_SERVER_ERROR)
def _validate_input_edit(self, indata, content, force=False):
# not needed to validate with pyangbind becuase it will be validated at check_conflict_on_edit
def __init__(self, db, fs, msg, auth):
DescriptorTopic.__init__(self, db, fs, msg, auth)
+ def pyangbind_validation(self, item, data, force=False):
+ try:
+ myvnfd = etsi_nfv_vnfd.etsi_nfv_vnfd()
+ pybindJSONDecoder.load_ietf_json({'etsi-nfv-vnfd:vnfd': data}, None, None, obj=myvnfd,
+ path_helper=True, skip_unknown=force)
+ out = pybindJSON.dumps(myvnfd, mode="ietf")
+ desc_out = self._remove_envelop(yaml.safe_load(out))
+ desc_out = self._remove_yang_prefixes_from_descriptor(desc_out)
+ return desc_out
+ except Exception as e:
+ raise EngineException("Error in pyangbind validation: {}".format(str(e)),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
@staticmethod
def _remove_envelop(indata=None):
if not indata:
return {}
clean_indata = indata
- if clean_indata.get('vnfd:vnfd-catalog'):
- clean_indata = clean_indata['vnfd:vnfd-catalog']
- elif clean_indata.get('vnfd-catalog'):
- clean_indata = clean_indata['vnfd-catalog']
- if clean_indata.get('vnfd'):
- if not isinstance(clean_indata['vnfd'], list) or len(clean_indata['vnfd']) != 1:
- raise EngineException("'vnfd' must be a list of only one element")
- clean_indata = clean_indata['vnfd'][0]
- elif clean_indata.get('vnfd:vnfd'):
- if not isinstance(clean_indata['vnfd:vnfd'], list) or len(clean_indata['vnfd:vnfd']) != 1:
- raise EngineException("'vnfd:vnfd' must be a list of only one element")
- clean_indata = clean_indata['vnfd:vnfd'][0]
+
+ if clean_indata.get('etsi-nfv-vnfd:vnfd'):
+ if not isinstance(clean_indata['etsi-nfv-vnfd:vnfd'], dict):
+ raise EngineException("'etsi-nfv-vnfd:vnfd' must be a dict")
+ clean_indata = clean_indata['etsi-nfv-vnfd:vnfd']
+ elif clean_indata.get('vnfd'):
+ if not isinstance(clean_indata['vnfd'], dict):
+ raise EngineException("'vnfd' must be dict")
+ clean_indata = clean_indata['vnfd']
+
return clean_indata
def check_conflict_on_edit(self, session, final_content, edit_content, _id):
indata.pop("onboardingState", None)
indata.pop("operationalState", None)
indata.pop("usageState", None)
-
indata.pop("links", None)
indata = self.pyangbind_validation("vnfds", indata, force)
# Cross references validation in the descriptor
- self.validate_mgmt_interfaces_connection_points(indata)
+
+ self.validate_mgmt_interface_connection_point(indata)
for vdu in get_iterable(indata.get("vdu")):
- self.validate_vdu_connection_point_refs(vdu, indata)
+ self.validate_vdu_internal_connection_points(vdu)
self._validate_vdu_charms_in_package(storage_params, vdu, indata)
self._validate_vdu_cloud_init_in_package(storage_params, vdu, indata)
self._validate_vnf_charms_in_package(storage_params, indata)
- self.validate_internal_vlds(indata)
+ self.validate_external_connection_points(indata)
+ self.validate_internal_virtual_links(indata)
self.validate_monitoring_params(indata)
self.validate_scaling_group_descriptor(indata)
return indata
@staticmethod
- def validate_mgmt_interfaces_connection_points(indata):
+ def validate_mgmt_interface_connection_point(indata):
if not indata.get("vdu"):
return
- if not indata.get("mgmt-interface"):
- raise EngineException("'mgmt-interface' is a mandatory field and it is not defined",
+ if not indata.get("mgmt-cp"):
+ raise EngineException("'mgmt-cp' is a mandatory field and it is not defined",
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- if indata["mgmt-interface"].get("cp"):
- for cp in get_iterable(indata.get("connection-point")):
- if cp["name"] == indata["mgmt-interface"]["cp"]:
- break
- else:
- raise EngineException("mgmt-interface:cp='{}' must match an existing connection-point"
- .format(indata["mgmt-interface"]["cp"]),
+
+ for cp in get_iterable(indata.get("ext-cpd")):
+ if cp["id"] == indata["mgmt-cp"]:
+ break
+ else:
+ raise EngineException("mgmt-cp='{}' must match an existing ext-cpd".format(indata["mgmt-cp"]),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
+ @staticmethod
+ def validate_vdu_internal_connection_points(vdu):
+ int_cpds = set()
+ for cpd in get_iterable(vdu.get("int-cpd")):
+ cpd_id = cpd.get("id")
+ if cpd_id and cpd_id in int_cpds:
+ raise EngineException("vdu[id='{}']:int-cpd[id='{}'] is already used by other int-cpd"
+ .format(vdu["id"], cpd_id),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ int_cpds.add(cpd_id)
@staticmethod
- def validate_vdu_connection_point_refs(vdu, indata):
- icp_refs = []
- ecp_refs = []
- for interface in get_iterable(vdu.get("interface")):
- if interface.get("external-connection-point-ref"):
- if interface.get("external-connection-point-ref") in ecp_refs:
- raise EngineException("vdu[id='{}']:interface[name='{}']:external-connection-point-ref='{}' "
- "is referenced by other interface"
- .format(vdu["id"], interface["name"],
- interface["external-connection-point-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- ecp_refs.append(interface.get("external-connection-point-ref"))
- for cp in get_iterable(indata.get("connection-point")):
- if cp["name"] == interface["external-connection-point-ref"]:
- break
- else:
- raise EngineException("vdu[id='{}']:interface[name='{}']:external-connection-point-ref='{}' "
- "must match an existing connection-point"
- .format(vdu["id"], interface["name"],
- interface["external-connection-point-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- elif interface.get("internal-connection-point-ref"):
- if interface.get("internal-connection-point-ref") in icp_refs:
- raise EngineException("vdu[id='{}']:interface[name='{}']:internal-connection-point-ref='{}' "
- "is referenced by other interface"
- .format(vdu["id"], interface["name"],
- interface["internal-connection-point-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- icp_refs.append(interface.get("internal-connection-point-ref"))
- for internal_cp in get_iterable(vdu.get("internal-connection-point")):
- if interface["internal-connection-point-ref"] == internal_cp.get("id"):
- break
- else:
- raise EngineException("vdu[id='{}']:interface[name='{}']:internal-connection-point-ref='{}' "
- "must match an existing vdu:internal-connection-point"
- .format(vdu["id"], interface["name"],
- interface["internal-connection-point-ref"]),
+ def validate_external_connection_points(indata):
+ all_vdus_int_cpds = set()
+ for vdu in get_iterable(indata.get("vdu")):
+ for int_cpd in get_iterable(vdu.get("int-cpd")):
+ all_vdus_int_cpds.add((vdu.get("id"), int_cpd.get("id")))
+
+ ext_cpds = set()
+ for cpd in get_iterable(indata.get("ext-cpd")):
+ cpd_id = cpd.get("id")
+ if cpd_id and cpd_id in ext_cpds:
+ raise EngineException("ext-cpd[id='{}'] is already used by other ext-cpd".format(cpd_id),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ ext_cpds.add(cpd_id)
+
+ int_cpd = cpd.get("int-cpd")
+ if int_cpd:
+ if (int_cpd.get("vdu-id"), int_cpd.get("cpd")) not in all_vdus_int_cpds:
+ raise EngineException("ext-cpd[id='{}']:int-cpd must match an existing vdu int-cpd".format(cpd_id),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ # TODO: Validate k8s-cluster-net points to a valid k8s-cluster:nets ?
def _validate_vdu_charms_in_package(self, storage_params, vdu, indata):
if not vdu.get("vdu-configuration"):
return
- if vdu["vdu-configuration"].get("juju"):
- if not self._validate_package_folders(storage_params, 'charms'):
- raise EngineException("Charm defined in vnf[id={}]:vdu[id={}] but not present in "
- "package".format(indata["id"], vdu["id"]))
+ for vdu_configuration in get_iterable(indata.get("vdu-configuration")):
+ if vdu_configuration.get("juju"):
+ if not self._validate_package_folders(storage_params, 'charms'):
+ raise EngineException("Charm defined in vnf[id={}] but not present in "
+ "package".format(indata["id"]))
def _validate_vdu_cloud_init_in_package(self, storage_params, vdu, indata):
if not vdu.get("cloud-init-file"):
def _validate_vnf_charms_in_package(self, storage_params, indata):
if not indata.get("vnf-configuration"):
return
- if indata["vnf-configuration"].get("juju"):
- if not self._validate_package_folders(storage_params, 'charms'):
- raise EngineException("Charm defined in vnf[id={}] but not present in "
- "package".format(indata["id"]))
+ for vnf_configuration in get_iterable(indata.get("vnf-configuration")):
+ if vnf_configuration.get("juju"):
+ if not self._validate_package_folders(storage_params, 'charms'):
+ raise EngineException("Charm defined in vnf[id={}] but not present in "
+ "package".format(indata["id"]))
def _validate_package_folders(self, storage_params, folder, file=None):
if not storage_params or not storage_params.get("pkg-dir"):
return False
@staticmethod
- def validate_internal_vlds(indata):
- vld_names = [] # For detection of duplicated VLD names
- for ivld in get_iterable(indata.get("internal-vld")):
- ivld_name = ivld.get("name")
- if ivld_name and ivld_name in vld_names:
- raise EngineException("Duplicated VLD name '{}' in vnfd[id={}]:internal-vld[id={}]"
- .format(ivld["name"], indata["id"], ivld["id"]),
+ def validate_internal_virtual_links(indata):
+ all_ivld_ids = set()
+ for ivld in get_iterable(indata.get("int-virtual-link-desc")):
+ ivld_id = ivld.get("id")
+ if ivld_id and ivld_id in all_ivld_ids:
+ raise EngineException("Duplicated VLD id in int-virtual-link-desc[id={}]".format(ivld_id),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
else:
- vld_names.append(ivld_name)
-
- for icp in get_iterable(ivld.get("internal-connection-point")):
- icp_mark = False
- for vdu in get_iterable(indata.get("vdu")):
- for internal_cp in get_iterable(vdu.get("internal-connection-point")):
- if icp["id-ref"] == internal_cp["id"]:
- icp_mark = True
- break
- if icp_mark:
- break
- else:
- raise EngineException("internal-vld[id='{}']:internal-connection-point='{}' must match an existing "
- "vdu:internal-connection-point".format(ivld["id"], icp["id-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- if ivld.get("ip-profile-ref"):
- for ip_prof in get_iterable(indata.get("ip-profiles")):
- if ip_prof["name"] == get_iterable(ivld.get("ip-profile-ref")):
- break
- else:
- raise EngineException("internal-vld[id='{}']:ip-profile-ref='{}' does not exist".format(
- ivld["id"], ivld["ip-profile-ref"]),
+ all_ivld_ids.add(ivld_id)
+
+ for vdu in get_iterable(indata.get("vdu")):
+ for int_cpd in get_iterable(vdu.get("int-cpd")):
+ int_cpd_ivld_id = int_cpd.get("int-virtual-link-desc")
+ if int_cpd_ivld_id and int_cpd_ivld_id not in all_ivld_ids:
+ raise EngineException(
+ "vdu[id='{}']:int-cpd[id='{}']:int-virtual-link-desc='{}' must match an existing "
+ "int-virtual-link-desc".format(vdu["id"], int_cpd["id"], int_cpd_ivld_id),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ for df in get_iterable(indata.get("df")):
+ for vlp in get_iterable(df.get("virtual-link-profile")):
+ vlp_ivld_id = vlp.get("id")
+ if vlp_ivld_id and vlp_ivld_id not in all_ivld_ids:
+ raise EngineException("df[id='{}']:virtual-link-profile='{}' must match an existing "
+ "int-virtual-link-desc".format(df["id"], vlp_ivld_id),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
@staticmethod
def validate_monitoring_params(indata):
- for mp in get_iterable(indata.get("monitoring-param")):
- if mp.get("vdu-monitoring-param"):
- mp_vmp_mark = False
- for vdu in get_iterable(indata.get("vdu")):
- for vmp in get_iterable(vdu.get("monitoring-param")):
- if vmp["id"] == mp["vdu-monitoring-param"].get("vdu-monitoring-param-ref") and vdu["id"] == \
- mp["vdu-monitoring-param"]["vdu-ref"]:
- mp_vmp_mark = True
- break
- if mp_vmp_mark:
- break
+ all_monitoring_params = set()
+ for ivld in get_iterable(indata.get("int-virtual-link-desc")):
+ for mp in get_iterable(ivld.get("monitoring-parameters")):
+ mp_id = mp.get("id")
+ if mp_id and mp_id in all_monitoring_params:
+ raise EngineException("Duplicated monitoring-parameter id in "
+ "int-virtual-link-desc[id='{}']:monitoring-parameters[id='{}']"
+ .format(ivld["id"], mp_id),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
else:
- raise EngineException("monitoring-param:vdu-monitoring-param:vdu-monitoring-param-ref='{}' not "
- "defined at vdu[id='{}'] or vdu does not exist"
- .format(mp["vdu-monitoring-param"]["vdu-monitoring-param-ref"],
- mp["vdu-monitoring-param"]["vdu-ref"]),
+ all_monitoring_params.add(mp_id)
+
+ for vdu in get_iterable(indata.get("vdu")):
+ for mp in get_iterable(vdu.get("monitoring-parameter")):
+ mp_id = mp.get("id")
+ if mp_id and mp_id in all_monitoring_params:
+ raise EngineException("Duplicated monitoring-parameter id in "
+ "vdu[id='{}']:monitoring-parameter[id='{}']"
+ .format(vdu["id"], mp_id),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- elif mp.get("vdu-metric"):
- mp_vm_mark = False
- for vdu in get_iterable(indata.get("vdu")):
- if vdu.get("vdu-configuration"):
- for metric in get_iterable(vdu["vdu-configuration"].get("metrics")):
- if metric["name"] == mp["vdu-metric"]["vdu-metric-name-ref"] and vdu["id"] == \
- mp["vdu-metric"]["vdu-ref"]:
- mp_vm_mark = True
- break
- if mp_vm_mark:
- break
else:
- raise EngineException("monitoring-param:vdu-metric:vdu-metric-name-ref='{}' not defined at "
- "vdu[id='{}'] or vdu does not exist"
- .format(mp["vdu-metric"]["vdu-metric-name-ref"],
- mp["vdu-metric"]["vdu-ref"]),
+ all_monitoring_params.add(mp_id)
+
+ for df in get_iterable(indata.get("df")):
+ for mp in get_iterable(df.get("monitoring-parameter")):
+ mp_id = mp.get("id")
+ if mp_id and mp_id in all_monitoring_params:
+ raise EngineException("Duplicated monitoring-parameter id in "
+ "df[id='{}']:monitoring-parameter[id='{}']"
+ .format(df["id"], mp_id),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ else:
+ all_monitoring_params.add(mp_id)
@staticmethod
def validate_scaling_group_descriptor(indata):
- for sgd in get_iterable(indata.get("scaling-group-descriptor")):
- for sp in get_iterable(sgd.get("scaling-policy")):
- for sc in get_iterable(sp.get("scaling-criteria")):
- for mp in get_iterable(indata.get("monitoring-param")):
- if mp["id"] == get_iterable(sc.get("vnf-monitoring-param-ref")):
- break
- else:
- raise EngineException("scaling-group-descriptor[name='{}']:scaling-criteria[name='{}']:"
- "vnf-monitoring-param-ref='{}' not defined in any monitoring-param"
- .format(sgd["name"], sc["name"], sc["vnf-monitoring-param-ref"]),
+ all_monitoring_params = set()
+ for ivld in get_iterable(indata.get("int-virtual-link-desc")):
+ for mp in get_iterable(ivld.get("monitoring-parameters")):
+ all_monitoring_params.add(mp.get("id"))
+
+ for vdu in get_iterable(indata.get("vdu")):
+ for mp in get_iterable(vdu.get("monitoring-parameter")):
+ all_monitoring_params.add(mp.get("id"))
+
+ for df in get_iterable(indata.get("df")):
+ for mp in get_iterable(df.get("monitoring-parameter")):
+ all_monitoring_params.add(mp.get("id"))
+
+ for df in get_iterable(indata.get("df")):
+ for sa in get_iterable(df.get("scaling-aspect")):
+ for sp in get_iterable(sa.get("scaling-policy")):
+ for sc in get_iterable(sp.get("scaling-criteria")):
+ sc_monitoring_param = sc.get("vnf-monitoring-param-ref")
+ if sc_monitoring_param and sc_monitoring_param not in all_monitoring_params:
+ raise EngineException("df[id='{}']:scaling-aspect[id='{}']:scaling-policy"
+ "[name='{}']:scaling-criteria[name='{}']: "
+ "vnf-monitoring-param-ref='{}' not defined in any monitoring-param"
+ .format(df["id"], sa["id"], sp["name"], sc["name"],
+ sc_monitoring_param),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
+ for sca in get_iterable(sa.get("scaling-config-action")):
+ if not indata.get("vnf-configuration"):
+ raise EngineException("'vnf-configuration' not defined in the descriptor but it is referenced "
+ "by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
+ .format(df["id"], sa["id"]),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- for sgd_vdu in get_iterable(sgd.get("vdu")):
- sgd_vdu_mark = False
- for vdu in get_iterable(indata.get("vdu")):
- if vdu["id"] == sgd_vdu["vdu-id-ref"]:
- sgd_vdu_mark = True
- break
- if sgd_vdu_mark:
- break
- else:
- raise EngineException("scaling-group-descriptor[name='{}']:vdu-id-ref={} does not match any vdu"
- .format(sgd["name"], sgd_vdu["vdu-id-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- for sca in get_iterable(sgd.get("scaling-config-action")):
- if not indata.get("vnf-configuration"):
- raise EngineException("'vnf-configuration' not defined in the descriptor but it is referenced by "
- "scaling-group-descriptor[name='{}']:scaling-config-action"
- .format(sgd["name"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- for primitive in get_iterable(indata["vnf-configuration"].get("config-primitive")):
- if primitive["name"] == sca["vnf-config-primitive-name-ref"]:
- break
- else:
- raise EngineException("scaling-group-descriptor[name='{}']:scaling-config-action:vnf-config-"
- "primitive-name-ref='{}' does not match any "
- "vnf-configuration:config-primitive:name"
- .format(sgd["name"], sca["vnf-config-primitive-name-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ for configuration in get_iterable(indata["vnf-configuration"]):
+ for primitive in get_iterable(configuration.get("config-primitive")):
+ if primitive["name"] == sca["vnf-config-primitive-name-ref"]:
+ break
+ else:
+ raise EngineException("df[id='{}']:scaling-aspect[id='{}']:scaling-config-action:vnf-"
+ "config-primitive-name-ref='{}' does not match any "
+ "vnf-configuration:config-primitive:name"
+ .format(df["id"], sa["id"], sca["vnf-config-primitive-name-ref"]),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
def delete_extra(self, session, _id, db_content, not_send_msg=None):
"""
def __init__(self, db, fs, msg, auth):
DescriptorTopic.__init__(self, db, fs, msg, auth)
+ def pyangbind_validation(self, item, data, force=False):
+ try:
+ mynsd = etsi_nfv_nsd.etsi_nfv_nsd()
+ pybindJSONDecoder.load_ietf_json({'nsd': {'nsd': [data]}}, None, None, obj=mynsd,
+ path_helper=True, skip_unknown=force)
+ out = pybindJSON.dumps(mynsd, mode="ietf")
+ desc_out = self._remove_envelop(yaml.safe_load(out))
+ desc_out = self._remove_yang_prefixes_from_descriptor(desc_out)
+ return desc_out
+ except Exception as e:
+ raise EngineException("Error in pyangbind validation: {}".format(str(e)),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
@staticmethod
def _remove_envelop(indata=None):
if not indata:
return {}
clean_indata = indata
- if clean_indata.get('nsd:nsd-catalog'):
- clean_indata = clean_indata['nsd:nsd-catalog']
- elif clean_indata.get('nsd-catalog'):
- clean_indata = clean_indata['nsd-catalog']
+ if clean_indata.get('nsd'):
+ clean_indata = clean_indata['nsd']
+ elif clean_indata.get('etsi-nfv-nsd:nsd'):
+ clean_indata = clean_indata['etsi-nfv-nsd:nsd']
if clean_indata.get('nsd'):
if not isinstance(clean_indata['nsd'], list) or len(clean_indata['nsd']) != 1:
raise EngineException("'nsd' must be a list of only one element")
clean_indata = clean_indata['nsd'][0]
- elif clean_indata.get('nsd:nsd'):
- if not isinstance(clean_indata['nsd:nsd'], list) or len(clean_indata['nsd:nsd']) != 1:
- raise EngineException("'nsd:nsd' must be a list of only one element")
- clean_indata = clean_indata['nsd:nsd'][0]
return clean_indata
def _validate_input_new(self, indata, storage_params, force=False):
indata = self.pyangbind_validation("nsds", indata, force)
# Cross references validation in the descriptor
# TODO validata that if contains cloud-init-file or charms, have artifacts _admin.storage."pkg-dir" is not none
- for vld in get_iterable(indata.get("vld")):
- self.validate_vld_mgmt_network_with_ip_profile_ref(vld)
- self.validate_vld_connection_point_refs(vld, indata)
+ for vld in get_iterable(indata.get("virtual-link-desc")):
+ self.validate_vld_mgmt_network_with_virtual_link_protocol_data(vld, indata)
- for fgd in get_iterable(indata.get("vnffgd")):
- self.validate_fgd_classifiers(fgd)
+ self.validate_vnf_profiles_vnfd_id(indata)
return indata
@staticmethod
- def validate_vld_mgmt_network_with_ip_profile_ref(vld):
- if vld.get("mgmt-network") and vld.get("ip-profile-ref"):
- raise EngineException("Error at vld[id='{}']:ip-profile-ref"
- " You cannot set an ip-profile when mgmt-network is True"
- .format(vld["id"]), http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
-
- @staticmethod
- def validate_vld_connection_point_refs(vld, indata):
- for vnfd_cp in get_iterable(vld.get("vnfd-connection-point-ref")):
- for constituent_vnfd in get_iterable(indata.get("constituent-vnfd")):
- if vnfd_cp["member-vnf-index-ref"] == constituent_vnfd["member-vnf-index"]:
- if vnfd_cp.get("vnfd-id-ref") and vnfd_cp["vnfd-id-ref"] != constituent_vnfd["vnfd-id-ref"]:
- raise EngineException("Error at vld[id='{}']:vnfd-connection-point-ref[vnfd-id-ref='{}'] "
- "does not match constituent-vnfd[member-vnf-index='{}']:vnfd-id-ref"
- " '{}'".format(vld["id"], vnfd_cp["vnfd-id-ref"],
- constituent_vnfd["member-vnf-index"],
- constituent_vnfd["vnfd-id-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
- break
- else:
- raise EngineException("Error at vld[id='{}']:vnfd-connection-point-ref[member-vnf-index-ref='{}'] "
- "does not match any constituent-vnfd:member-vnf-index"
- .format(vld["id"], vnfd_cp["member-vnf-index-ref"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ def validate_vld_mgmt_network_with_virtual_link_protocol_data(vld, indata):
+ if not vld.get("mgmt-network"):
+ return
+ vld_id = vld.get("id")
+ for df in get_iterable(indata.get("df")):
+ for vlp in get_iterable(df.get("virtual-link-profile")):
+ if vld_id and vld_id == vlp.get("virtual-link-desc-id"):
+ if vlp.get("virtual-link-protocol-data"):
+ raise EngineException("Error at df[id='{}']:virtual-link-profile[id='{}']:virtual-link-"
+ "protocol-data You cannot set a virtual-link-protocol-data "
+ "when mgmt-network is True"
+ .format(df["id"], vlp["id"]), http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
@staticmethod
- def validate_fgd_classifiers(fgd):
- for cls in get_iterable(fgd.get("classifier")):
- rspref = cls.get("rsp-id-ref")
- for rsp in get_iterable(fgd.get("rsp")):
- rspid = rsp.get("id")
- if rspid and rspref and rspid == rspref:
- break
- else:
- raise EngineException(
- "Error at vnffgd[id='{}']:classifier[id='{}']:rsp-id-ref '{}' does not match any rsp:id"
- .format(fgd["id"], cls["id"], rspref),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ def validate_vnf_profiles_vnfd_id(indata):
+ all_vnfd_ids = set(get_iterable(indata.get("vnfd-id")))
+ for df in get_iterable(indata.get("df")):
+ for vnf_profile in get_iterable(df.get("vnf-profile")):
+ vnfd_id = vnf_profile.get("vnfd-id")
+ if vnfd_id and vnfd_id not in all_vnfd_ids:
+ raise EngineException("Error at df[id='{}']:vnf_profile[id='{}']:vnfd-id='{}' "
+ "does not match any vnfd-id".format(df["id"], vnf_profile["id"], vnfd_id),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
def _validate_input_edit(self, indata, content, force=False):
# not needed to validate with pyangbind becuase it will be validated at check_conflict_on_edit
"""
if session["force"]:
return
- member_vnfd_index = self._get_descriptor_constituent_vnfds_by_member_vnfd_index(session, descriptor)
+ vnfds_index = self._get_descriptor_constituent_vnfds_index(session, descriptor)
# Cross references validation in the descriptor and vnfd connection point validation
- for vld in get_iterable(descriptor.get("vld")):
- self.validate_vld_connection_point_refs_vnfd_connection_points(vld, member_vnfd_index)
-
- def _get_descriptor_constituent_vnfds_by_member_vnfd_index(self, session, descriptor):
- member_vnfd_index = {}
- if descriptor.get("constituent-vnfd") and not session["force"]:
- for vnf in descriptor["constituent-vnfd"]:
- vnfd_id = vnf["vnfd-id-ref"]
+ for df in get_iterable(descriptor.get("df")):
+ self.validate_df_vnf_profiles_constituent_connection_points(df, vnfds_index)
+
+ def _get_descriptor_constituent_vnfds_index(self, session, descriptor):
+ vnfds_index = {}
+ if descriptor.get("vnfd-id") and not session["force"]:
+ for vnfd_id in get_iterable(descriptor.get("vnfd-id")):
query_filter = self._get_project_filter(session)
query_filter["id"] = vnfd_id
vnf_list = self.db.get_list("vnfds", query_filter)
if not vnf_list:
- raise EngineException("Descriptor error at 'constituent-vnfd':'vnfd-id-ref'='{}' references a non "
+ raise EngineException("Descriptor error at 'vnfd-id'='{}' references a non "
"existing vnfd".format(vnfd_id), http_code=HTTPStatus.CONFLICT)
-
- member_vnfd_index[vnf["member-vnf-index"]] = vnf_list[0]
- return member_vnfd_index
+ vnfds_index[vnfd_id] = vnf_list[0]
+ return vnfds_index
@staticmethod
- def validate_vld_connection_point_refs_vnfd_connection_points(vld, member_vnfd_index):
- for referenced_vnfd_cp in get_iterable(vld.get("vnfd-connection-point-ref")):
- # look if this vnfd contains this connection point
- vnfd = member_vnfd_index.get(referenced_vnfd_cp["member-vnf-index-ref"])
- for vnfd_cp in get_iterable(vnfd.get("connection-point")):
- if referenced_vnfd_cp.get("vnfd-connection-point-ref") == vnfd_cp["name"]:
- break
- else:
- raise EngineException(
- "Error at vld[id='{}']:vnfd-connection-point-ref[member-vnf-index-ref='{}']:vnfd-"
- "connection-point-ref='{}' references a non existing conection-point:name inside vnfd '{}'"
- .format(vld["id"], referenced_vnfd_cp["member-vnf-index-ref"],
- referenced_vnfd_cp["vnfd-connection-point-ref"], vnfd["id"]),
- http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ def validate_df_vnf_profiles_constituent_connection_points(df, vnfds_index):
+ for vnf_profile in get_iterable(df.get("vnf-profile")):
+ vnfd = vnfds_index.get(vnf_profile["vnfd-id"])
+ all_vnfd_ext_cpds = set()
+ for ext_cpd in get_iterable(vnfd.get("ext-cpd")):
+ if ext_cpd.get('id'):
+ all_vnfd_ext_cpds.add(ext_cpd.get('id'))
+
+ for virtual_link in get_iterable(vnf_profile.get("virtual-link-connectivity")):
+ for vl_cpd in get_iterable(virtual_link.get("constituent-cpd-id")):
+ vl_cpd_id = vl_cpd.get('constituent-cpd-id')
+ if vl_cpd_id and vl_cpd_id not in all_vnfd_ext_cpds:
+ raise EngineException("Error at df[id='{}']:vnf-profile[id='{}']:virtual-link-connectivity"
+ "[virtual-link-profile-id='{}']:constituent-cpd-id='{}' references a "
+ "non existing ext-cpd:id inside vnfd '{}'"
+ .format(df["id"], vnf_profile["id"],
+ virtual_link["virtual-link-profile-id"], vl_cpd_id, vnfd["id"]),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
def check_conflict_on_edit(self, session, final_content, edit_content, _id):
super().check_conflict_on_edit(session, final_content, edit_content, _id)
def __init__(self, db, fs, msg, auth):
DescriptorTopic.__init__(self, db, fs, msg, auth)
+ def pyangbind_validation(self, item, data, force=False):
+ try:
+ mynst = nst_im()
+ pybindJSONDecoder.load_ietf_json({'nst': [data]}, None, None, obj=mynst,
+ path_helper=True, skip_unknown=force)
+ out = pybindJSON.dumps(mynst, mode="ietf")
+ desc_out = self._remove_envelop(yaml.safe_load(out))
+ return desc_out
+ except Exception as e:
+ raise EngineException("Error in pyangbind validation: {}".format(str(e)),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
@staticmethod
def _remove_envelop(indata=None):
if not indata:
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
-----BEGIN CERTIFICATE-----
MIID6zCCAtOgAwIBAgIJAP5stGSyLGztMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
VQQGEwJlczEPMA0GA1UECAwGTWFkcmlkMQ8wDQYDVQQHDAZNYWRyaWQxFzAVBgNV
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA15Qu6L8mhTGYM+RnDLevBhPgj0m7amHTQu6fv8529X6viPzG
RiYH4eHyAER4HbqC3mu8ADLyrohwQjG2LZrbv3ZnDwTzOPs6dfqkUkBSOdlQlW6P
from osm_nbi.validation import validate_input, ValidationError, ns_instantiate, ns_terminate, ns_action, ns_scale,\
nsi_instantiate
from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable, deep_get, increment_ip_mac
-# from descriptor_topics import DescriptorTopic
from yaml import safe_dump
from osm_common.dbbase import DbException
from osm_common.msgbase import MsgException
from osm_common.fsbase import FsException
+from osm_nbi import utils
from re import match # For checking that additional parameter names are valid Jinja2 identifiers
__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
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"))
+ vnf_configurations = get_iterable(descriptor.get("vnf-configuration"))
+ initial_primitives = []
+ for vnfc in vnf_configurations:
+ for primitive in get_iterable(vnfc.get("initial-config-primitive")):
+ initial_primitives.append(primitive)
else:
initial_primitives = deep_get(descriptor, ("ns-configuration", "initial-config-primitive"))
EngineException, ValidationError, DbException, FsException, MsgException.
Note: Exceptions are not captured on purpose. They should be captured at called
"""
-
try:
step = "checking quotas"
self.check_quota(session)
step = "validating input parameters"
ns_request = self._remove_envelop(indata)
- # Override descriptor with query string kwargs
self._update_input_with_kwargs(ns_request, kwargs)
self._validate_input_new(ns_request, session["force"])
- # look for nsd
step = "getting nsd id='{}' from database".format(ns_request.get("nsdId"))
- _filter = self._get_project_filter(session)
- _filter["_id"] = ns_request["nsdId"]
- nsd = self.db.get_one("nsds", _filter)
- del _filter["_id"]
+ nsd = self._get_nsd_from_db(ns_request["nsdId"], session)
+ ns_k8s_namespace = self._get_ns_k8s_namespace(nsd, ns_request, session)
- # check NSD is not disabled
step = "checking nsdOperationalState"
- 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)
-
- nsr_id = str(uuid4())
+ self._check_nsd_operational_state(nsd, ns_request)
- now = time()
step = "filling nsr from input data"
- 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"]
-
- 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() if k in ("vld", "_id", "id", "constituent-vnfd", "name",
- "ns-configuration")},
- "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": {},
- # {"networks": {"active": 0, "total": 0}, "vms": {"active": 0, "total": 0}},
-
- "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,
- # "input-parameter": xpath, value,
- "ssh-authorized-key": ns_request.get("ssh_keys"), # TODO remove
- "vld": nsd.get("vld") or [],
- "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("vld"):
- nsr_descriptor["vld"] = nsd["vld"]
+ nsr_id = str(uuid4())
+ nsr_descriptor = self._create_nsr_descriptor_from_nsd(nsd, ns_request, nsr_id)
- # Create VNFR
+ # Create VNFRs
needed_vnfds = {}
- for member_vnf in nsd.get("constituent-vnfd", ()):
- vnfd_id = member_vnf["vnfd-id-ref"]
- step = "getting vnfd id='{}' constituent-vnfd='{}' from database".format(
- member_vnf["vnfd-id-ref"], member_vnf["member-vnf-index"])
+ # TODO: Change for multiple df support
+ vnf_profiles = nsd.get("df", [[]])[0].get("vnf-profile", ())
+ for vnfp in vnf_profiles:
+ vnfd_id = vnfp.get("vnfd-id")
+ vnf_index = vnfp.get("id")
+ step = "getting vnfd id='{}' constituent-vnfd='{}' from database".format(vnfd_id, vnf_index)
if vnfd_id not in needed_vnfds:
- # Obtain vnfd
- _filter["id"] = vnfd_id
- vnfd = self.db.get_one("vnfds", _filter, fail_on_empty=True, fail_on_more=True)
- del _filter["id"]
- vnfd.pop("_admin")
+ vnfd = self._get_vnfd_from_db(vnfd_id, session)
needed_vnfds[vnfd_id] = vnfd
nsr_descriptor["vnfd-id"].append(vnfd["_id"])
else:
vnfd = needed_vnfds[vnfd_id]
- step = "filling vnfr vnfd-id='{}' constituent-vnfd='{}'".format(
- member_vnf["vnfd-id-ref"], member_vnf["member-vnf-index"])
- vnfr_id = str(uuid4())
- additional_params, vnf_params = self._format_additional_params(ns_request,
- member_vnf["member-vnf-index"],
- descriptor=vnfd)
- vnfr_descriptor = {
- "id": vnfr_id,
- "_id": vnfr_id,
- "nsr-id-ref": nsr_id,
- "member-vnf-index-ref": member_vnf["member-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,
- "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("internal-vld"):
- vnfr_descriptor["vld"] = []
- for vnfd_vld in vnfd.get("internal-vld"):
- vnfr_descriptor["vld"].append(
- {key: vnfd_vld[key] for key in ("id", "vim-network-name", "vim-network-id") if key in
- vnfd_vld})
-
- vnfd_mgmt_cp = vnfd["mgmt-interface"].get("cp")
- for cp in vnfd.get("connection-point", ()):
- vnf_cp = {
- "name": cp["name"],
- "connection-point-id": cp.get("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
- 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")):
- additional_params, kdu_params = self._format_additional_params(ns_request,
- member_vnf["member-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)
+
+ step = "filling vnfr vnfd-id='{}' constituent-vnfd='{}'".format(vnfd_id, vnf_index)
+ vnfr_descriptor = self._create_vnfr_descriptor_from_vnfd(nsd, vnfd, vnfd_id, vnf_index, nsr_descriptor,
+ ns_request, ns_k8s_namespace)
+
+ step = "creating vnfr vnfd-id='{}' constituent-vnfd='{}' at database".format(vnfd_id, vnf_index)
+ self._add_vnfr_to_db(vnfr_descriptor, rollback, session)
+ nsr_descriptor["constituent-vnfr-ref"].append(vnfr_descriptor["id"])
+
+ step = "creating nsr at database"
+ self._add_nsr_to_db(nsr_descriptor, rollback, session)
+
+ step = "creating nsr temporal folder"
+ self.fs.mkdir(nsr_id)
+
+ return nsr_id, None
+ except (ValidationError, EngineException, DbException, MsgException, FsException) as e:
+ 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):
+ 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.db.get_one("vnfds",
+ {"id": vnf_profile.get("vnfd-id")},
+ fail_on_empty=True,
+ fail_on_more=True)
for vdu in vnfd.get("vdu", ()):
- additional_params, vdu_params = self._format_additional_params(
- ns_request, member_vnf["member-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"]
-
- # flavor
- flavor_data = copy(vdu.get("vm-flavor", {}))
- flavor_data["guest-epa"] = vdu.get("guest-epa")
+ 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
f = next((f for f in nsr_descriptor["flavor"] if
all(f.get(k) == flavor_data[k] for k in flavor_data)), None)
+
if not f:
+ flavor_data["vim_info"] = []
flavor_data["name"] = vdu["id"][:56] + "-flv"
flavor_data["id"] = str(len(nsr_descriptor["flavor"]))
nsr_descriptor["flavor"].append(flavor_data)
- f = flavor_data
- vdur["ns-flavor-id"] = f["id"]
- # image
- if vdu.get("image"):
- image_data = {"image": vdu["image"], "image_checksum": vdu.get("image_checksum")}
+ sw_image_id = vdu.get("sw-image-desc")
+ if 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"]
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["vim_info"] = []
image_data["id"] = str(len(nsr_descriptor["image"]))
nsr_descriptor["image"].append(image_data)
- img = image_data
- vdur["ns-image-id"] = img["id"]
-
- # TODO volumes: name, volume-id
- for icp in vdu.get("internal-connection-point", ()):
- vdu_icp = {
- "id": icp["id"],
- "connection-point-id": icp["id"],
- "name": icp.get("name"),
- }
- vdur["internal-connection-point"].append(vdu_icp)
- for iface in vdu.get("interface", ()):
- vdu_iface = {
- x: iface[x] for x in ("name", "ip-address", "mac-address", "internal-connection-point-ref",
- "external-connection-point-ref") if iface.get(x) is not None}
- if iface.get("ip-address"):
- vdu_iface["fixed-ip"] = True
- if iface.get("mac-address"):
- vdu_iface["fixed-mac"] = True
- if vnfd_mgmt_cp and iface.get("external-connection-point-ref") == vnfd_mgmt_cp:
- vdu_iface["mgmt-vnf"] = True
- if iface.get("mgmt-interface"):
- vdu_iface["mgmt-interface"] = True # TODO change to mgmt-vdu
- if iface.get("virtual-interface"):
- vdu_iface.update({x: iface["virtual-interface"][x] for x in ("type", "vcpi", "bandwidth")
- if iface["virtual-interface"].get(x) is not None})
-
- # look for network where this interface is connected
- if iface.get("external-connection-point-ref"):
- for vld_index, nsd_vld in enumerate(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") == \
- iface["external-connection-point-ref"] and \
- nsd_vld_cp.get("member-vnf-index-ref") == member_vnf["member-vnf-index"]:
- vdu_iface["ns-vld-id"] = nsd_vld["id"]
- # if interface is of type PCI, mark connected vld as of type PCI
- if vdu_iface.get("type") in ("SR-IOV", "PCI-PASSTHROUGH"):
- nsr_descriptor["vld"][vld_index]["pci-interfaces"] = True
- break
- else:
- continue
- break
- elif iface.get("internal-connection-point-ref"):
- for vld_index, vnfd_ivld in enumerate(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") == iface["internal-connection-point-ref"]:
- vdu_iface["vnf-vld-id"] = vnfd_ivld["id"]
- if vnfd_ivld_icp.get("ip-address"):
- vdu_iface["ip-address"] = vnfd_ivld_icp["ip-address"]
- # if interface is of type PCI, mark connected vld as of type PCI
- if vdu_iface.get("type") in ("SR-IOV", "PCI-PASSTHROUGH"):
- vnfr_descriptor["vld"][vld_index]["pci-interfaces"] = True
- break
- else:
- continue
- break
- if iface.get("position") is not None:
- vdur["interfaces"].insert(iface["position"], vdu_iface)
- else:
- vdur["interfaces"].append(vdu_iface)
- count = vdu.get("count", 1)
- if count is None:
- count = 1
- count = int(count) # TODO remove when descriptor serialized with payngbind
- for index in range(0, count):
- if index:
- 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["count-index"] = index
- vdur["id"] = "{}-{}".format(vdur["vdu-id-ref"], index)
- vnfr_descriptor["vdur"].append(vdur)
-
- step = "creating vnfr vnfd-id='{}' constituent-vnfd='{}' at database".format(
- member_vnf["vnfd-id-ref"], member_vnf["member-vnf-index"])
-
- # add at database
- 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_id})
- nsr_descriptor["constituent-vnfr-ref"].append(vnfr_id)
- step = "creating nsr at database"
- 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_id})
+ 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
- step = "creating nsr temporal folder"
- self.fs.mkdir(nsr_id)
+ return nsr_descriptor
- return nsr_id, None
- except (ValidationError, EngineException, DbException, MsgException, FsException) as e:
- raise type(e)("{} while '{}'".format(e, step), http_code=e.http_code)
+ 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,
+ "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
+ # TODO: Change for multiple df support
+ all_kdu_profiles = vnfd.get("df", [[]])[0].get("kdu-profile", ())
+ all_kdu_profiles_models = {profile.get("name"): profile.get("kdu-model-id") for profile in all_kdu_profiles}
+ all_kdu_models = vnfd.get("kdu-model", ())
+ all_kdu_models = {model.get("id"): model for model in all_kdu_models}
+ 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.get("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"]
+
+ kdu_model_data = all_kdu_models[all_kdu_profiles_models[kdur["name"]]]
+ kdur[kdu_model_data.get("kdu-model-type")] = kdu_model or kdu_model_data
+ 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", ()):
+ 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"]
+ 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")
+ 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 # TODO change to mgmt-vdu
+
+ # 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 in 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")
+ break
+ elif vdu_iface.get("internal-connection-point-ref"):
+ vdu_iface["vnf-vld-id"] = icp.get("int-virtual-link-desc")
+
+ 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"]
+
+ 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"]
+
+ count = int(vdu.get("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
def edit(self, session, _id, indata=None, kwargs=None, content=None):
raise EngineException("Method edit called directly", HTTPStatus.INTERNAL_SERVER_ERROR)
:param indata: descriptor with the parameters of the operation
:return: None
"""
+ if operation == "action":
+ self._check_action_ns_operation(indata, nsr)
+ elif operation == "scale":
+ self._check_scale_ns_operation(indata, nsr)
+ elif operation == "instantiate":
+ self._check_instantiate_ns_operation(indata, nsr, session)
+
+ def _check_action_ns_operation(self, indata, nsr):
+ nsd = nsr["nsd"]
+ # check vnf_member_index
+ if indata.get("vnf_member_index"):
+ indata["member_vnf_index"] = indata.pop("vnf_member_index") # for backward compatibility
+ if indata.get("member_vnf_index"):
+ vnfd = self._get_vnfd_from_vnf_member_index(indata["member_vnf_index"], nsr["_id"])
+ if indata.get("vdu_id"):
+ vdud = self._check_valid_vdu(vnfd, indata["vdu_id"])
+ descriptor_configuration = vdud.get("vdu-configuration", {}).get("config-primitive")
+ elif indata.get("kdu_name"):
+ kdud = self._check_valid_kdu(vnfd, indata["kdu_name"])
+ descriptor_configuration = kdud.get("kdu-configuration", {}).get("config-primitive")
+ else:
+ # TODO: Validate the [0] as vnf-configuration is now a list
+ descriptor_configuration = vnfd.get("vnf-configuration", {})[0].get("config-primitive")
+ else: # use a NSD
+ 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", "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):
+ if indata["primitive"] == config_primitive["name"]:
+ # check needed primitive_params are provided
+ if indata.get("primitive_params"):
+ in_primitive_params_copy = copy(indata["primitive_params"])
+ else:
+ in_primitive_params_copy = {}
+ for paramd in get_iterable(config_primitive.get("parameter")):
+ if paramd["name"] in in_primitive_params_copy:
+ del in_primitive_params_copy[paramd["name"]]
+ elif not paramd.get("default-value"):
+ raise EngineException("Needed parameter {} not provided for primitive '{}'".format(
+ paramd["name"], indata["primitive"]))
+ # check no extra primitive params are provided
+ if in_primitive_params_copy:
+ raise EngineException("parameter/s '{}' not present at vnfd /nsd for primitive '{}'".format(
+ list(in_primitive_params_copy.keys()), indata["primitive"]))
+ break
+ else:
+ raise EngineException("Invalid primitive '{}' is not present at vnfd/nsd".format(indata["primitive"]))
+
+ def _check_scale_ns_operation(self, indata, nsr):
+ vnfd = self._get_vnfd_from_vnf_member_index(indata["scaleVnfData"]["scaleByStepData"]["member-vnf-index"],
+ nsr["_id"])
+ for scaling_group in get_iterable(vnfd.get("scaling-group-descriptor")):
+ if indata["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"] == scaling_group["name"]:
+ break
+ else:
+ raise EngineException("Invalid scaleVnfData:scaleByStepData:scaling-group-descriptor '{}' is not "
+ "present at vnfd:scaling-group-descriptor"
+ .format(indata["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"]))
+
+ def _check_instantiate_ns_operation(self, indata, nsr, session):
vnf_member_index_to_vnfd = {} # map between vnf_member_index to vnf descriptor.
vim_accounts = []
wim_accounts = []
nsd = nsr["nsd"]
-
- def check_valid_vnf_member_index(member_vnf_index):
- # Obtain vnf descriptor. The vnfr is used to get the vnfd._id used for this member_vnf_index
+ self._check_valid_vim_account(indata["vimAccountId"], vim_accounts, session)
+ self._check_valid_wim_account(indata.get("wimAccountId"), wim_accounts, session)
+ for in_vnf in get_iterable(indata.get("vnf")):
+ member_vnf_index = in_vnf["member-vnf-index"]
if vnf_member_index_to_vnfd.get(member_vnf_index):
- return vnf_member_index_to_vnfd[member_vnf_index]
- vnfr = self.db.get_one("vnfrs",
- {"nsr-id-ref": nsr["_id"], "member-vnf-index-ref": member_vnf_index},
- fail_on_empty=False)
- if not vnfr:
- raise EngineException("Invalid parameter member_vnf_index='{}' is not one of the "
- "nsd:constituent-vnfd".format(member_vnf_index))
- vnfd = self.db.get_one("vnfds", {"_id": vnfr["vnfd-id"]}, fail_on_empty=False)
- if not vnfd:
- raise EngineException("vnfd id={} has been deleted!. Operation cannot be performed".
- format(vnfr["vnfd-id"]))
- vnf_member_index_to_vnfd[member_vnf_index] = vnfd # add to cache, avoiding a later look for
- return vnfd
-
- def check_valid_vdu(vnfd, vdu_id):
- for vdud in get_iterable(vnfd.get("vdu")):
- if vdud["id"] == vdu_id:
- return vdud
+ vnfd = vnf_member_index_to_vnfd[member_vnf_index]
else:
- raise EngineException("Invalid parameter vdu_id='{}' not present at vnfd:vdu:id".format(vdu_id))
-
- def check_valid_kdu(vnfd, kdu_name):
- for kdud in get_iterable(vnfd.get("kdu")):
- if kdud["name"] == kdu_name:
- return kdud
+ vnfd = self._get_vnfd_from_vnf_member_index(member_vnf_index, nsr["_id"])
+ vnf_member_index_to_vnfd[member_vnf_index] = vnfd # add to cache, avoiding a later look for
+ self._check_vnf_instantiation_params(in_vnf, vnfd)
+ if in_vnf.get("vimAccountId"):
+ self._check_valid_vim_account(in_vnf["vimAccountId"], vim_accounts, session)
+
+ for in_vld in get_iterable(indata.get("vld")):
+ self._check_valid_wim_account(in_vld.get("wimAccountId"), wim_accounts, session)
+ for vldd in get_iterable(nsd.get("virtual-link-desc")):
+ if in_vld["name"] == vldd["id"]:
+ break
else:
- raise EngineException("Invalid parameter kdu_name='{}' not present at vnfd:kdu:name".format(kdu_name))
+ raise EngineException("Invalid parameter vld:name='{}' is not present at nsd:vld".format(
+ in_vld["name"]))
+
+ def _get_vnfd_from_vnf_member_index(self, member_vnf_index, nsr_id):
+ # Obtain vnf descriptor. The vnfr is used to get the vnfd._id used for this member_vnf_index
+ vnfr = self.db.get_one("vnfrs",
+ {"nsr-id-ref": nsr_id, "member-vnf-index-ref": member_vnf_index},
+ fail_on_empty=False)
+ if not vnfr:
+ raise EngineException("Invalid parameter member_vnf_index='{}' is not one of the "
+ "nsd:constituent-vnfd".format(member_vnf_index))
+ vnfd = self.db.get_one("vnfds", {"_id": vnfr["vnfd-id"]}, fail_on_empty=False)
+ if not vnfd:
+ raise EngineException("vnfd id={} has been deleted!. Operation cannot be performed".
+ format(vnfr["vnfd-id"]))
+ return vnfd
+
+ def _check_valid_vdu(self, vnfd, vdu_id):
+ for vdud in get_iterable(vnfd.get("vdu")):
+ if vdud["id"] == vdu_id:
+ return vdud
+ else:
+ raise EngineException("Invalid parameter vdu_id='{}' not present at vnfd:vdu:id".format(vdu_id))
- def _check_vnf_instantiation_params(in_vnfd, vnfd):
+ def _check_valid_kdu(self, vnfd, kdu_name):
+ for kdud in get_iterable(vnfd.get("kdu")):
+ if kdud["name"] == kdu_name:
+ return kdud
+ else:
+ raise EngineException("Invalid parameter kdu_name='{}' not present at vnfd:kdu:name".format(kdu_name))
+
+ def _check_vnf_instantiation_params(self, in_vnf, vnfd):
+ for in_vdu in get_iterable(in_vnf.get("vdu")):
+ for vdu in get_iterable(vnfd.get("vdu")):
+ if in_vdu["id"] == vdu["id"]:
+ for volume in get_iterable(in_vdu.get("volume")):
+ for volumed in get_iterable(vdu.get("virtual-storage-desc")):
+ if volumed["id"] == volume["name"]:
+ break
+ else:
+ raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:vdu[id='{}']:"
+ "volume:name='{}' is not present at "
+ "vnfd:vdu:virtual-storage-desc list".
+ format(in_vnf["member-vnf-index"], in_vdu["id"],
+ volume["id"]))
+
+ vdu_if_names = set()
+ for cpd in get_iterable(vdu.get("int-cpd")):
+ for iface in get_iterable(cpd.get("virtual-network-interface-requirement")):
+ vdu_if_names.add(iface.get("name"))
+
+ for in_iface in get_iterable(in_vdu["interface"]):
+ if in_iface["name"] in vdu_if_names:
+ break
+ else:
+ raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:vdu[id='{}']:"
+ "int-cpd[id='{}'] is not present at vnfd:vdu:int-cpd"
+ .format(in_vnf["member-vnf-index"], in_vdu["id"],
+ in_iface["name"]))
+ break
- for in_vdu in get_iterable(in_vnfd.get("vdu")):
- for vdu in get_iterable(vnfd.get("vdu")):
- if in_vdu["id"] == vdu["id"]:
- for volume in get_iterable(in_vdu.get("volume")):
- for volumed in get_iterable(vdu.get("volumes")):
- if volumed["name"] == volume["name"]:
- break
- else:
- raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:vdu[id='{}']:"
- "volume:name='{}' is not present at vnfd:vdu:volumes list".
- format(in_vnf["member-vnf-index"], in_vdu["id"],
- volume["name"]))
- for in_iface in get_iterable(in_vdu["interface"]):
- for iface in get_iterable(vdu.get("interface")):
- if in_iface["name"] == iface["name"]:
- break
- else:
- raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:vdu[id='{}']:"
- "interface[name='{}'] is not present at vnfd:vdu:interface"
- .format(in_vnf["member-vnf-index"], in_vdu["id"],
- in_iface["name"]))
- break
- else:
- raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:vdu[id='{}'] is is not present "
- "at vnfd:vdu".format(in_vnf["member-vnf-index"], in_vdu["id"]))
-
- for in_ivld in get_iterable(in_vnfd.get("internal-vld")):
- for ivld in get_iterable(vnfd.get("internal-vld")):
- if in_ivld["name"] in (ivld["id"], ivld.get("name")):
- for in_icp in get_iterable(in_ivld.get("internal-connection-point")):
- for icp in ivld["internal-connection-point"]:
- if in_icp["id-ref"] == icp["id-ref"]:
- break
- else:
- raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:internal-vld[name"
- "='{}']:internal-connection-point[id-ref:'{}'] is not present at "
- "vnfd:internal-vld:name/id:internal-connection-point"
- .format(in_vnf["member-vnf-index"], in_ivld["name"],
- in_icp["id-ref"]))
+ else:
+ raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:vdu[id='{}'] is not present "
+ "at vnfd:vdu".format(in_vnf["member-vnf-index"], in_vdu["id"]))
+
+ vnfd_ivlds_cpds = {ivld.get("id"): set() for ivld in get_iterable(vnfd.get("int-virtual-link-desc"))}
+ for vdu in get_iterable(vnfd.get("vdu")):
+ for cpd in get_iterable(vnfd.get("int-cpd")):
+ if cpd.get("int-virtual-link-desc"):
+ vnfd_ivlds_cpds[cpd.get("int-virtual-link-desc")] = cpd.get("id")
+
+ for in_ivld in get_iterable(in_vnf.get("internal-vld")):
+ if in_ivld.get("name") in vnfd_ivlds_cpds:
+ for in_icp in get_iterable(in_ivld.get("internal-connection-point")):
+ if in_icp["id-ref"] in vnfd_ivlds_cpds[in_ivld.get("name")]:
break
- else:
- raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:internal-vld:name='{}'"
- " is not present at vnfd '{}'".format(in_vnf["member-vnf-index"],
- in_ivld["name"], vnfd["id"]))
-
- def check_valid_vim_account(vim_account):
- if vim_account in vim_accounts:
- return
- try:
- db_filter = self._get_project_filter(session)
- db_filter["_id"] = vim_account
- self.db.get_one("vim_accounts", db_filter)
- except Exception:
- raise EngineException("Invalid vimAccountId='{}' not present for the project".format(vim_account))
- vim_accounts.append(vim_account)
-
- def check_valid_wim_account(wim_account):
- if not isinstance(wim_account, str):
- return
- elif wim_account in wim_accounts:
- return
- try:
- db_filter = self._get_project_filter(session, write=False, show_all=True)
- db_filter["_id"] = wim_account
- self.db.get_one("wim_accounts", db_filter)
- except Exception:
- raise EngineException("Invalid wimAccountId='{}' not present for the project".format(wim_account))
- wim_accounts.append(wim_account)
-
- if operation == "action":
- # check vnf_member_index
- if indata.get("vnf_member_index"):
- indata["member_vnf_index"] = indata.pop("vnf_member_index") # for backward compatibility
- if indata.get("member_vnf_index"):
- vnfd = check_valid_vnf_member_index(indata["member_vnf_index"])
- if indata.get("vdu_id"):
- 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["kdu_name"])
- descriptor_configuration = kdud.get("kdu-configuration", {}).get("config-primitive")
- else:
- descriptor_configuration = vnfd.get("vnf-configuration", {}).get("config-primitive")
- else: # use a NSD
- 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", "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):
- if indata["primitive"] == config_primitive["name"]:
- # check needed primitive_params are provided
- if indata.get("primitive_params"):
- in_primitive_params_copy = copy(indata["primitive_params"])
else:
- in_primitive_params_copy = {}
- for paramd in get_iterable(config_primitive.get("parameter")):
- if paramd["name"] in in_primitive_params_copy:
- del in_primitive_params_copy[paramd["name"]]
- elif not paramd.get("default-value"):
- raise EngineException("Needed parameter {} not provided for primitive '{}'".format(
- paramd["name"], indata["primitive"]))
- # check no extra primitive params are provided
- if in_primitive_params_copy:
- raise EngineException("parameter/s '{}' not present at vnfd /nsd for primitive '{}'".format(
- list(in_primitive_params_copy.keys()), indata["primitive"]))
- break
+ raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:internal-vld[name"
+ "='{}']:internal-connection-point[id-ref:'{}'] is not present at "
+ "vnfd:internal-vld:name/id:internal-connection-point"
+ .format(in_vnf["member-vnf-index"], in_ivld["name"],
+ in_icp["id-ref"]))
else:
- raise EngineException("Invalid primitive '{}' is not present at vnfd/nsd".format(indata["primitive"]))
- if operation == "scale":
- vnfd = check_valid_vnf_member_index(indata["scaleVnfData"]["scaleByStepData"]["member-vnf-index"])
- for scaling_group in get_iterable(vnfd.get("scaling-group-descriptor")):
- if indata["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"] == scaling_group["name"]:
- break
- else:
- raise EngineException("Invalid scaleVnfData:scaleByStepData:scaling-group-descriptor '{}' is not "
- "present at vnfd:scaling-group-descriptor".format(
- indata["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"]))
- if operation == "instantiate":
- # check vim_account
- check_valid_vim_account(indata["vimAccountId"])
- check_valid_wim_account(indata.get("wimAccountId"))
- for in_vnf in get_iterable(indata.get("vnf")):
- vnfd = check_valid_vnf_member_index(in_vnf["member-vnf-index"])
- _check_vnf_instantiation_params(in_vnf, vnfd)
- if in_vnf.get("vimAccountId"):
- check_valid_vim_account(in_vnf["vimAccountId"])
-
- for in_vld in get_iterable(indata.get("vld")):
- check_valid_wim_account(in_vld.get("wimAccountId"))
- for vldd in get_iterable(nsd.get("vld")):
- if in_vld["name"] == vldd["name"] or in_vld["name"] == vldd["id"]:
- break
- else:
- raise EngineException("Invalid parameter vld:name='{}' is not present at nsd:vld".format(
- in_vld["name"]))
+ raise EngineException("Invalid parameter vnf[member-vnf-index='{}']:internal-vld:name='{}'"
+ " is not present at vnfd '{}'".format(in_vnf["member-vnf-index"],
+ in_ivld["name"], vnfd["id"]))
+
+ def _check_valid_vim_account(self, vim_account, vim_accounts, session):
+ if vim_account in vim_accounts:
+ return
+ try:
+ db_filter = self._get_project_filter(session)
+ db_filter["_id"] = vim_account
+ self.db.get_one("vim_accounts", db_filter)
+ except Exception:
+ raise EngineException("Invalid vimAccountId='{}' not present for the project".format(vim_account))
+ vim_accounts.append(vim_account)
+
+ def _check_valid_wim_account(self, wim_account, wim_accounts, session):
+ if not isinstance(wim_account, str):
+ return
+ if wim_account in wim_accounts:
+ return
+ try:
+ db_filter = self._get_project_filter(session, write=False, show_all=True)
+ db_filter["_id"] = wim_account
+ self.db.get_one("wim_accounts", db_filter)
+ except Exception:
+ raise EngineException("Invalid wimAccountId='{}' not present for the project".format(wim_account))
+ wim_accounts.append(wim_account)
def _look_for_pdu(self, session, rollback, vnfr, vim_account, vnfr_update, vnfr_update_rollback):
"""
if not nsis_list:
self.db.set_one("nsts", {"_id": nsir_admin["nst-id"]}, {"_admin.usageState": "NOT_IN_USE"})
- # def delete(self, session, _id, dry_run=False):
- # """
- # Delete item by its internal _id
- # :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
- # :param _id: server internal id
- # :param dry_run: make checking but do not delete
- # :return: dictionary with deleted item _id. It raises EngineException on error: not found, conflict, ...
- # """
- # # TODO add admin to filter, validate rights
- # BaseTopic.delete(self, session, _id, dry_run=True)
- # if dry_run:
- # return
- #
- # # Deleting the nsrs belonging to nsir
- # nsir = self.db.get_one("nsis", {"_id": _id})
- # for nsrs_detailed_item in nsir["_admin"]["nsrs-detailed-list"]:
- # nsr_id = nsrs_detailed_item["nsrId"]
- # if nsrs_detailed_item.get("shared"):
- # _filter = {"_admin.nsrs-detailed-list.ANYINDEX.shared": True,
- # "_admin.nsrs-detailed-list.ANYINDEX.nsrId": nsr_id,
- # "_id.ne": nsir["_id"]}
- # nsi = self.db.get_one("nsis", _filter, fail_on_empty=False, fail_on_more=False)
- # if nsi: # last one using nsr
- # continue
- # try:
- # self.nsrTopic.delete(session, nsr_id, dry_run=False)
- # except (DbException, EngineException) as e:
- # if e.http_code == HTTPStatus.NOT_FOUND:
- # pass
- # else:
- # raise
- # # deletes NetSlice instance object
- # v = self.db.del_one("nsis", {"_id": _id})
- #
- # # makes a temporal list of nsilcmops objects related to the _id given and deletes them from db
- # _filter = {"netsliceInstanceId": _id}
- # self.db.del_list("nsilcmops", _filter)
- #
- # # Search if nst is being used by other nsi
- # nsir_admin = nsir.get("_admin")
- # if nsir_admin:
- # if nsir_admin.get("nst-id"):
- # nsis_list = self.db.get_one("nsis", {"nst-id": nsir_admin["nst-id"]},
- # fail_on_empty=False, fail_on_more=False)
- # if not nsis_list:
- # self.db.set_one("nsts", {"_id": nsir_admin["nst-id"]}, {"_admin.usageState": "NOT_IN_USE"})
- # return v
-
def new(self, rollback, session, indata=None, kwargs=None, headers=None):
"""
Creates a new netslice instance record into database. It also creates needed nsrs and vnfrs
usageState: NOT_IN_USE
userDefinedData: {}
_id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
- connection-point:
- - id: vnf-mgmt
- name: vnf-mgmt
- short-name: vnf-mgmt
- type: VPORT
- - id: vnf-data
- name: vnf-data
- short-name: vnf-data
- type: VPORT
- description: A VNF consisting of 2 VDUs connected to an internal VL, and one VDU
- with cloud-init
id: hackfest3charmed-vnf
- internal-vld:
- - id: internal
- internal-connection-point:
- - id-ref: mgmtVM-internal
- - id-ref: dataVM-internal
- name: internal
- short-name: internal
- type: ELAN
- logo: osm.png
- mgmt-interface:
- cp: vnf-mgmt
- monitoring-param:
- - aggregation-type: AVERAGE
- id: monitor1
- name: monitor1
- vdu-monitoring-param:
- vdu-monitoring-param-ref: dataVM_cpu_util
- vdu-ref: dataVM
- - id: dataVM_users
- aggregation-type: AVERAGE
- name: dataVM_users
- vdu-metric:
- vdu-metric-name-ref: users
- vdu-ref: dataVM
- - id: dataVM_load
- aggregation-type: AVERAGE
- name: dataVM_load
- vdu-metric:
- vdu-metric-name-ref: load
- vdu-ref: dataVM
- name: hackfest3charmed-vnf
- scaling-group-descriptor:
- - max-instance-count: 10
- name: scale_dataVM
- scaling-config-action:
- - trigger: post-scale-out
- vnf-config-primitive-name-ref: touch
- - trigger: pre-scale-in
- vnf-config-primitive-name-ref: touch
- scaling-policy:
- - cooldown-time: 60
- name: auto_cpu_util_above_threshold
- scaling-criteria:
- - name: cpu_util_above_threshold
- scale-in-relational-operation: LE
- scale-in-threshold: '15.0000000000'
- scale-out-relational-operation: GE
- scale-out-threshold: '60.0000000000'
- vnf-monitoring-param-ref: monitor1
- scaling-type: automatic
- threshold-time: 0
- vdu:
- - count: 1
- vdu-id-ref: dataVM
- short-name: hackfest3charmed-vnf
+ description: >-
+ A VNF consisting of 2 VDUs connected to an internal VL, and one VDU with
+ cloud-init
+ product-name: hackfest3charmed-vnf
+ version: '1.0'
+ mgmt-cp: vnf-mgmt-ext
+
+ virtual-compute-desc:
+ - id: mgmt-compute
+ virtual-cpu:
+ num-virtual-cpu: 1
+ virtual-memory:
+ size: 1
+ - id: data-compute
+ virtual-cpu:
+ num-virtual-cpu: 1
+ virtual-memory:
+ size: 1
+
+ virtual-storage-desc:
+ - id: mgmt-storage
+ size-of-storage: 10
+ - id: data-storage
+ size-of-storage: 10
+
+ sw-image-desc:
+ - id: hackfest3-mgmt
+ name: hackfest3-mgmt
+
vdu:
- - count: '1'
- cloud-init-file: cloud-config.txt
- id: mgmtVM
- image: hackfest3-mgmt
- interface:
- - external-connection-point-ref: vnf-mgmt
- name: mgmtVM-eth0
- position: 1
- type: EXTERNAL
- virtual-interface:
- type: VIRTIO
- - internal-connection-point-ref: mgmtVM-internal
- name: mgmtVM-eth1
- position: 2
- type: INTERNAL
- virtual-interface:
- type: VIRTIO
- internal-connection-point:
- - id: mgmtVM-internal
- name: mgmtVM-internal
- short-name: mgmtVM-internal
- type: VPORT
+ - id: mgmtVM
name: mgmtVM
- vm-flavor:
- memory-mb: '1024'
- storage-gb: '10'
- vcpu-count: 1
- - count: '1'
- id: dataVM
- image: hackfest3-mgmt
- interface:
- - internal-connection-point-ref: dataVM-internal
- name: dataVM-eth0
- position: 1
- type: INTERNAL
- virtual-interface:
- type: VIRTIO
- - external-connection-point-ref: vnf-data
- name: dataVM-xe0
- position: 2
- type: EXTERNAL
- virtual-interface:
- type: VIRTIO
- internal-connection-point:
- - id: dataVM-internal
- name: dataVM-internal
- short-name: dataVM-internal
- type: VPORT
- monitoring-param:
- - id: dataVM_cpu_util
- nfvi-metric: cpu_utilization
+ cloud-init-file: cloud-config.txt
+ sw-image-desc: hackfest3-mgmt
+ virtual-compute-desc: mgmt-compute
+ virtual-storage-desc:
+ - mgmt-storage
+ int-cpd:
+ - id: vnf-mgmt
+ virtual-network-interface-requirement:
+ - name: mgmtVM-eth0
+ position: 1
+ virtual-interface:
+ type: VIRTIO
+ - id: mgmtVM-internal
+ int-virtual-link-desc: internal
+ virtual-network-interface-requirement:
+ - name: mgmtVM-eth1
+ position: 2
+ virtual-interface:
+ type: VIRTIO
+ - id: dataVM
name: dataVM
- vdu-configuration:
- initial-config-primitive:
- - parameter:
- - value: "<rw_mgmt_ip>"
- name: ssh-hostname
- - value: ubuntu
- name: ssh-username
- - value: osm2018
- name: ssh-password
- name: config
- seq: '1'
- metrics:
- - name: users
- - name: load
- juju:
- proxy: true
- charm: testmetrics
- vm-flavor:
- memory-mb: '1024'
- storage-gb: '10'
- vcpu-count: 1
- version: '1.0'
+ sw-image-desc: hackfest3-mgmt
+ virtual-compute-desc: data-compute
+ virtual-storage-desc:
+ - data-storage
+ int-cpd:
+ - id: dataVM-internal
+ int-virtual-link-desc: internal
+ virtual-network-interface-requirement:
+ - name: dataVM-eth1
+ position: 1
+ virtual-interface:
+ type: VIRTIO
+ - id: vnf-data
+ virtual-network-interface-requirement:
+ - name: dataVM-eth0
+ position: 2
+ virtual-interface:
+ type: VIRTIO
+ monitoring-parameter:
+ - id: dataVM_cpu_util
+ name: dataVM_cpu_util
+ performance-metric: cpu_utilization
+
+ int-virtual-link-desc:
+ - id: internal
+
+ ext-cpd:
+ - id: vnf-mgmt-ext
+ int-cpd: # Connection to int-cpd
+ vdu-id: mgmtVM
+ cpd: vnf-mgmt
+ - id: vnf-data-ext
+ int-cpd: # Connection to int-cpd
+ vdu-id: dataVM
+ cpd: vnf-data
+
+ df:
+ - id: hackfest_default
+ vnf-configuration-id: vnf-configuration-example
+ vdu-profile:
+ - id: mgmtVM
+ min-number-of-instances: 1
+ - id: dataVM
+ min-number-of-instances: 1
+ max-number-of-instances: 10
+ vdu-configuration-id: vdu-configuration-example
+ instantiation-level:
+ - id: default
+ vdu-level:
+ - vdu-id: mgmtVM
+ number-of-instances: 1
+ - vdu-id: dataVM
+ number-of-instances: 1
+ scaling-aspect:
+ - id: scale_dataVM
+ name: scale_dataVM
+ max-scale-level: 10
+ aspect-delta-details:
+ deltas:
+ - id: delta1
+ vdu-delta:
+ - id: vdudelta1
+ number-of-instances: 1
+ scaling-policy:
+ - name: auto_cpu_util_above_threshold
+ scaling-type: automatic
+ enabled: true
+ threshold-time: 0
+ cooldown-time: 60
+ scaling-criteria:
+ - name: cpu_util_above_threshold
+ scale-in-relational-operation: LE
+ scale-in-threshold: '15.0000000000'
+ scale-out-relational-operation: GE
+ scale-out-threshold: '60.0000000000'
+ vnf-monitoring-param-ref: dataVM_cpu_util
+ scaling-config-action:
+ - trigger: post-scale-out
+ vnf-config-primitive-name-ref: touch
+ - trigger: pre-scale-in
+ vnf-config-primitive-name-ref: touch
+
vnf-configuration:
- config-primitive:
- - name: touch
- parameter:
- - data-type: STRING
- default-value: <touch_filename2>
- name: filename
+ - id: vnf-configuration-example
initial-config-primitive:
- - name: config
+ - seq: "1"
+ name: config
parameter:
- - name: ssh-hostname
+ - name: ssh-hostname
value: <rw_mgmt_ip>
- - name: ssh-username
+ - name: ssh-username
value: ubuntu
- - name: ssh-password
+ - name: ssh-password
value: osm4u
- seq: '1'
- - name: touch
+ - seq: "2"
+ name: touch
parameter:
- - name: filename
+ - name: filename
value: <touch_filename>
- seq: '2'
+ config-primitive:
+ - name: touch
+ parameter:
+ - data-type: STRING
+ default-value: <touch_filename2>
+ name: filename
juju:
- charm: simple
+ charm: simple
"""
db_nsds_text = """
usageState: NOT_IN_USE
userDefinedData: {}
_id: 8c2f8b95-bb1b-47ee-8001-36dc090678da
- constituent-vnfd:
- - member-vnf-index: '1'
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index: '2'
- vnfd-id-ref: hackfest3charmed-vnf
- description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and mgmtnet
- VLs
id: hackfest3charmed-ns
- logo: osm.png
name: hackfest3charmed-ns
- short-name: hackfest3charmed-ns
+ description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and mgmtnet VLs
+ designer: OSM
version: '1.0'
- vld:
- - id: mgmt
- mgmt-network: true
- name: mgmt
- short-name: mgmt
- type: ELAN
- vim-network-name: mgmt
- vnfd-connection-point-ref:
- - member-vnf-index-ref: '1'
- vnfd-connection-point-ref: vnf-mgmt
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index-ref: '2'
- vnfd-connection-point-ref: vnf-mgmt
- vnfd-id-ref: hackfest3charmed-vnf
- - id: datanet
- name: datanet
- short-name: datanet
- type: ELAN
- vnfd-connection-point-ref:
- - member-vnf-index-ref: '1'
- vnfd-connection-point-ref: vnf-data
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index-ref: '2'
- vnfd-connection-point-ref: vnf-data
- vnfd-id-ref: hackfest3charmed-vnf
+
+ vnfd-id:
+ - hackfest3charmed-vnf
+
+ virtual-link-desc:
+ - id: mgmt
+ mgmt-network: "true"
+ - id: datanet
+ mgmt-network: "false"
+
+ df:
+ - id: hackfest_charmed_DF
+ vnf-profile:
+ - id: hackfest_vnf1 # member-vnf-index-ref: 1
+ vnfd-id: hackfest3charmed-vnf
+ virtual-link-connectivity:
+ - virtual-link-profile-id: mgmt
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf1
+ constituent-cpd-id: vnf-mgmt-ext
+ - virtual-link-profile-id: datanet
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf1
+ constituent-cpd-id: vnf-data-ext
+ - id: hackfest_vnf2 # member-vnf-index-ref: 2
+ vnfd-id: hackfest3charmed-vnf
+ virtual-link-connectivity:
+ - virtual-link-profile-id: mgmt
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf2
+ constituent-cpd-id: vnf-mgmt-ext
+ - virtual-link-profile-id: datanet
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf2
+ constituent-cpd-id: vnf-data-ext
"""
db_nsrs_text = """
usageState: NOT_IN_USE
userDefinedData: {}
_id: 8c2f8b95-bb1b-47ee-8001-36dc090678da
- constituent-vnfd:
- - member-vnf-index: '1'
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index: '2'
- vnfd-id-ref: hackfest3charmed-vnf
- description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and
- mgmtnet VLs
id: hackfest3charmed-ns
- logo: osm.png
name: hackfest3charmed-ns
- short-name: hackfest3charmed-ns
+ description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and mgmtnet VLs
+ designer: OSM
version: '1.0'
- vld:
- - id: mgmt
- mgmt-network: true
- name: mgmt
- short-name: mgmt
- type: ELAN
- vim-network-name: mgmt
- vnfd-connection-point-ref:
- - member-vnf-index-ref: '1'
- vnfd-connection-point-ref: vnf-mgmt
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index-ref: '2'
- vnfd-connection-point-ref: vnf-mgmt
- vnfd-id-ref: hackfest3charmed-vnf
- - id: datanet
- name: datanet
- short-name: datanet
- type: ELAN
- vnfd-connection-point-ref:
- - member-vnf-index-ref: '1'
- vnfd-connection-point-ref: vnf-data
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index-ref: '2'
- vnfd-connection-point-ref: vnf-data
- vnfd-id-ref: hackfest3charmed-vnf
+
+ vnfd-id:
+ - hackfest3charmed-vnf
+
+ virtual-link-desc:
+ - id: mgmt
+ mgmt-network: "true"
+ - id: datanet
+ mgmt-network: "false"
+
+ df:
+ - id: hackfest_charmed_DF
+ vnf-profile:
+ - id: hackfest_vnf1 # member-vnf-index-ref: 1
+ vnfd-id: hackfest3charmed-vnf
+ virtual-link-connectivity:
+ - virtual-link-profile-id: mgmt
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf1
+ constituent-cpd-id: vnf-mgmt-ext
+ - virtual-link-profile-id: datanet
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf1
+ constituent-cpd-id: vnf-data-ext
+ - id: hackfest_vnf2 # member-vnf-index-ref: 2
+ vnfd-id: hackfest3charmed-vnf
+ virtual-link-connectivity:
+ - virtual-link-profile-id: mgmt
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf2
+ constituent-cpd-id: vnf-mgmt-ext
+ - virtual-link-profile-id: datanet
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf2
+ constituent-cpd-id: vnf-data-ext
nsd-id: 8c2f8b95-bb1b-47ee-8001-36dc090678da
nsd-name-ref: hackfest3charmed-ns
nsd-ref: hackfest3charmed-ns
self.assertEqual(db_args[1]["_admin"]["projects_read"], [test_pid], "Wrong read-only project list")
self.assertEqual(db_args[1]["_admin"]["projects_write"], [test_pid], "Wrong read-write project list")
tmp1 = test_vnfd["vdu"][0]["cloud-init-file"]
- tmp2 = test_vnfd["vnf-configuration"]["juju"]
+ tmp2 = test_vnfd["vnf-configuration"][0]["juju"]
del test_vnfd["vdu"][0]["cloud-init-file"]
- del test_vnfd["vnf-configuration"]["juju"]
+ del test_vnfd["vnf-configuration"][0]["juju"]
try:
self.db.get_one.side_effect = [{"_id": did, "_admin": db_vnfd_content["_admin"]}, None]
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
compare_desc(self, test_vnfd, db_args[2], "VNFD")
finally:
test_vnfd["vdu"][0]["cloud-init-file"] = tmp1
- test_vnfd["vnf-configuration"]["juju"] = tmp2
+ test_vnfd["vnf-configuration"][0]["juju"] = tmp2
self.db.get_one.side_effect = lambda table, filter, fail_on_empty=None, fail_on_more=None: \
{"_id": did, "_admin": db_vnfd_content["_admin"]}
- with self.subTest(i=2, t='Check Pyangbind Validation: required properties'):
- tmp = test_vnfd["id"]
- del test_vnfd["id"]
- try:
- with self.assertRaises(EngineException, msg="Accepted VNFD with a missing required property") as e:
- self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error in pyangbind validation: '{}'".format("id")),
- norm(str(e.exception)), "Wrong exception text")
- finally:
- test_vnfd["id"] = tmp
- with self.subTest(i=3, t='Check Pyangbind Validation: additional properties'):
+ with self.subTest(i=2, t='Check Pyangbind Validation: additional properties'):
test_vnfd["extra-property"] = 0
try:
with self.assertRaises(EngineException, msg="Accepted VNFD with an additional property") as e:
norm(str(e.exception)), "Wrong exception text")
finally:
del test_vnfd["extra-property"]
- with self.subTest(i=4, t='Check Pyangbind Validation: property types'):
- tmp = test_vnfd["short-name"]
- test_vnfd["short-name"] = {"key": 0}
+ with self.subTest(i=3, t='Check Pyangbind Validation: property types'):
+ tmp = test_vnfd["product-name"]
+ test_vnfd["product-name"] = {"key": 0}
try:
with self.assertRaises(EngineException, msg="Accepted VNFD with a wrongly typed property") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
.format("json object contained a key that did not exist", "key")),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd["short-name"] = tmp
- with self.subTest(i=5, t='Check Input Validation: cloud-init'):
+ test_vnfd["product-name"] = tmp
+ with self.subTest(i=4, t='Check Input Validation: cloud-init'):
with self.assertRaises(EngineException, msg="Accepted non-existent cloud_init file") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.BAD_REQUEST, "Wrong HTTP status code")
self.assertIn(norm("{} defined in vnf[id={}]:vdu[id={}] but not present in package"
.format("cloud-init", test_vnfd["id"], test_vnfd["vdu"][0]["id"])),
norm(str(e.exception)), "Wrong exception text")
- with self.subTest(i=6, t='Check Input Validation: vnf-configuration[juju]'):
+ with self.subTest(i=5, t='Check Input Validation: vnf-configuration[juju]'):
del test_vnfd["vdu"][0]["cloud-init-file"]
with self.assertRaises(EngineException, msg="Accepted non-existent charm in VNF configuration") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.BAD_REQUEST, "Wrong HTTP status code")
self.assertIn(norm("{} defined in vnf[id={}] but not present in package".format("charm", test_vnfd["id"])),
norm(str(e.exception)), "Wrong exception text")
- with self.subTest(i=7, t='Check Input Validation: mgmt-interface'):
- del test_vnfd["vnf-configuration"]["juju"]
- tmp = test_vnfd["mgmt-interface"]
- del test_vnfd["mgmt-interface"]
+ del test_vnfd["vnf-configuration"][0]["juju"]
+ with self.subTest(i=6, t='Check Input Validation: mgmt-cp'):
+ tmp = test_vnfd["mgmt-cp"]
+ del test_vnfd["mgmt-cp"]
try:
with self.assertRaises(EngineException, msg="Accepted VNFD without management interface") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("'{}' is a mandatory field and it is not defined".format("mgmt-interface")),
+ self.assertIn(norm("'{}' is a mandatory field and it is not defined".format("mgmt-cp")),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd["mgmt-interface"] = tmp
- with self.subTest(i=8, t='Check Input Validation: mgmt-interface[cp]'):
- tmp = test_vnfd["mgmt-interface"]["cp"]
- test_vnfd["mgmt-interface"]["cp"] = "wrong-cp"
+ test_vnfd["mgmt-cp"] = tmp
+ with self.subTest(i=7, t='Check Input Validation: mgmt-cp connection point'):
+ tmp = test_vnfd["mgmt-cp"]
+ test_vnfd["mgmt-cp"] = "wrong-cp"
try:
- with self.assertRaises(EngineException,
- msg="Accepted wrong management interface connection point") as e:
+ with self.assertRaises(EngineException, msg="Accepted wrong mgmt-cp connection point") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("mgmt-interface:cp='{}' must match an existing connection-point"
- .format(test_vnfd["mgmt-interface"]["cp"])),
+ self.assertIn(norm("mgmt-cp='{}' must match an existing ext-cpd".format(test_vnfd["mgmt-cp"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd["mgmt-interface"]["cp"] = tmp
- with self.subTest(i=9, t='Check Input Validation: vdu[interface][external-connection-point-ref]'):
- tmp = test_vnfd["vdu"][0]["interface"][0]["external-connection-point-ref"]
- test_vnfd["vdu"][0]["interface"][0]["external-connection-point-ref"] = "wrong-cp"
+ test_vnfd["mgmt-cp"] = tmp
+ with self.subTest(i=8, t='Check Input Validation: vdu int-cpd'):
+ ext_cpd = test_vnfd["ext-cpd"][1]
+ tmp = ext_cpd["int-cpd"]["cpd"]
+ ext_cpd["int-cpd"]["cpd"] = "wrong-cpd"
try:
- with self.assertRaises(EngineException,
- msg="Accepted wrong VDU interface external connection point reference") as e:
+ with self.assertRaises(EngineException, msg="Accepted wrong ext-cpd internal connection point") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("vdu[id='{}']:interface[name='{}']:external-connection-point-ref='{}'"
- " must match an existing connection-point"
- .format(test_vnfd["vdu"][0]["id"], test_vnfd["vdu"][0]["interface"][0]["name"],
- test_vnfd["vdu"][0]["interface"][0]["external-connection-point-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- finally:
- test_vnfd["vdu"][0]["interface"][0]["external-connection-point-ref"] = tmp
- with self.subTest(i=10, t='Check Input Validation: vdu[interface][internal-connection-point-ref]'):
- tmp = test_vnfd["vdu"][1]["interface"][0]["internal-connection-point-ref"]
- test_vnfd["vdu"][1]["interface"][0]["internal-connection-point-ref"] = "wrong-cp"
- try:
- with self.assertRaises(EngineException,
- msg="Accepted wrong VDU interface internal connection point reference") as e:
- self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("vdu[id='{}']:interface[name='{}']:internal-connection-point-ref='{}'"
- " must match an existing vdu:internal-connection-point"
- .format(test_vnfd["vdu"][1]["id"], test_vnfd["vdu"][1]["interface"][0]["name"],
- test_vnfd["vdu"][1]["interface"][0]["internal-connection-point-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- finally:
- test_vnfd["vdu"][1]["interface"][0]["internal-connection-point-ref"] = tmp
- with self.subTest(i=11, t='Check Input Validation: vdu[vdu-configuration][juju]'):
- test_vnfd["vdu"][0]["vdu-configuration"] = {"juju": {"charm": "wrong-charm"}}
- try:
- with self.assertRaises(EngineException, msg="Accepted non-existent charm in VDU configuration") as e:
- self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.BAD_REQUEST, "Wrong HTTP status code")
- self.assertIn(norm("{} defined in vnf[id={}]:vdu[id={}] but not present in package"
- .format("charm", test_vnfd["id"], test_vnfd["vdu"][0]["id"])),
+ self.assertIn(norm("ext-cpd[id='{}']:int-cpd must match an existing vdu int-cpd".format(ext_cpd["id"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- del test_vnfd["vdu"][0]["vdu-configuration"]
- with self.subTest(i=12, t='Check Input Validation: Duplicated VLD name'):
- test_vnfd["internal-vld"].append(deepcopy(test_vnfd["internal-vld"][0]))
- test_vnfd["internal-vld"][1]["id"] = "wrong-internal-vld"
+ ext_cpd["int-cpd"]["cpd"] = tmp
+ with self.subTest(i=9, t='Check Input Validation: Duplicated VLD'):
+ test_vnfd['int-virtual-link-desc'].insert(0, {'id': 'internal'})
try:
with self.assertRaises(EngineException, msg="Accepted duplicated VLD name") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Duplicated VLD name '{}' in vnfd[id={}]:internal-vld[id={}]"
- .format(test_vnfd["internal-vld"][1]["name"], test_vnfd["id"],
- test_vnfd["internal-vld"][1]["id"])),
- norm(str(e.exception)), "Wrong exception text")
+ self.assertIn(
+ norm("identifier id '{}' is not unique".format(test_vnfd['int-virtual-link-desc'][0]["id"])),
+ norm(str(e.exception)), "Wrong exception text")
finally:
- del test_vnfd["internal-vld"][1]
- with self.subTest(i=13, t='Check Input Validation: internal-vld[internal-connection-point][id-ref])'):
- tmp = test_vnfd["internal-vld"][0]["internal-connection-point"][0]["id-ref"]
- test_vnfd["internal-vld"][0]["internal-connection-point"][0]["id-ref"] = "wrong-icp-id-ref"
+ del test_vnfd['int-virtual-link-desc'][0]
+ with self.subTest(i=10, t='Check Input Validation: vdu int-virtual-link-desc'):
+ vdu = test_vnfd['vdu'][0]
+ int_cpd = vdu['int-cpd'][1]
+ tmp = int_cpd['int-virtual-link-desc']
+ int_cpd['int-virtual-link-desc'] = 'non-existing-int-virtual-link-desc'
try:
- with self.assertRaises(EngineException, msg="Accepted non-existent internal VLD ICP id-ref") as e:
+ with self.assertRaises(EngineException, msg="Accepted int-virtual-link-desc") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("internal-vld[id='{}']:internal-connection-point='{}' must match an existing "
- "vdu:internal-connection-point"
- .format(test_vnfd["internal-vld"][0]["id"],
- test_vnfd["internal-vld"][0]["internal-connection-point"][0]["id-ref"])),
+ self.assertIn(norm("vdu[id='{}']:int-cpd[id='{}']:int-virtual-link-desc='{}' must match an existing "
+ "int-virtual-link-desc".format(vdu["id"], int_cpd["id"],
+ int_cpd['int-virtual-link-desc'])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd["internal-vld"][0]["internal-connection-point"][0]["id-ref"] = tmp
- with self.subTest(i=14, t='Check Input Validation: internal-vld[ip-profile-ref])'):
- test_vnfd["ip-profiles"] = [{"name": "fake-ip-profile-ref"}]
- test_vnfd["internal-vld"][0]["ip-profile-ref"] = "wrong-ip-profile-ref"
+ int_cpd['int-virtual-link-desc'] = tmp
+ with self.subTest(i=11, t='Check Input Validation: virtual-link-profile)'):
+ fake_ivld_profile = {'id': 'fake-profile-ref', 'flavour': 'fake-flavour'}
+ df = test_vnfd['df'][0]
+ df['virtual-link-profile'] = [fake_ivld_profile]
try:
- with self.assertRaises(EngineException, msg="Accepted non-existent IP Profile Ref") as e:
+ with self.assertRaises(EngineException, msg="Accepted non-existent Profile Ref") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("internal-vld[id='{}']:ip-profile-ref='{}' does not exist"
- .format(test_vnfd["internal-vld"][0]["id"],
- test_vnfd["internal-vld"][0]["ip-profile-ref"])),
+ self.assertIn(norm("df[id='{}']:virtual-link-profile='{}' must match an existing "
+ "int-virtual-link-desc".format(df["id"], fake_ivld_profile["id"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- del test_vnfd["ip-profiles"]
- del test_vnfd["internal-vld"][0]["ip-profile-ref"]
- with self.subTest(i=15, t='Check Input Validation: vdu[monitoring-param])'):
- test_vnfd["monitoring-param"] = [{"id": "fake-mp-id", "vdu-monitoring-param": {
- "vdu-monitoring-param-ref": "fake-vdu-mp-ref", "vdu-ref": "fake-vdu-ref"}}]
- test_vnfd["vdu"][0]["monitoring-param"] = [{"id": "wrong-vdu-mp-id"}]
+ del df['virtual-link-profile']
+ with self.subTest(i=12, t='Check Input Validation: scaling-criteria monitoring-param-ref'):
+ vdu = test_vnfd['vdu'][1]
+ affected_df = test_vnfd['df'][0]
+ sa = affected_df['scaling-aspect'][0]
+ sp = sa['scaling-policy'][0]
+ sc = sp['scaling-criteria'][0]
+ tmp = vdu.pop('monitoring-parameter')
try:
- with self.assertRaises(EngineException, msg="Accepted non-existent VDU Monitorimg Param") as e:
+ with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group Policy Criteria") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- mp = test_vnfd["monitoring-param"][0]["vdu-monitoring-param"]
- self.assertIn(norm("monitoring-param:vdu-monitoring-param:vdu-monitoring-param-ref='{}' not defined"
- " at vdu[id='{}'] or vdu does not exist"
- .format(mp["vdu-monitoring-param-ref"], mp["vdu-ref"])),
+ self.assertIn(norm("df[id='{}']:scaling-aspect[id='{}']:scaling-policy"
+ "[name='{}']:scaling-criteria[name='{}']: "
+ "vnf-monitoring-param-ref='{}' not defined in any monitoring-param"
+ .format(affected_df["id"], sa["id"], sp["name"],
+ sc["name"], sc["vnf-monitoring-param-ref"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- del test_vnfd["monitoring-param"]
- del test_vnfd["vdu"][0]["monitoring-param"]
- with self.subTest(i=16, t='Check Input Validation: vdu[vdu-configuration][metrics]'):
- test_vnfd["monitoring-param"] = [{"id": "fake-mp-id", "vdu-metric": {
- "vdu-metric-name-ref": "fake-vdu-mp-ref", "vdu-ref": "fake-vdu-ref"}}]
- test_vnfd["vdu"][0]["vdu-configuration"] = {"metrics": [{"name": "wrong-vdu-mp-id"}]}
+ vdu['monitoring-parameter'] = tmp
+ with self.subTest(i=13, t='Check Input Validation: scaling-aspect vnf-configuration'):
+ df = test_vnfd['df'][0]
+ tmp = test_vnfd.pop('vnf-configuration')
try:
- with self.assertRaises(EngineException, msg="Accepted non-existent VDU Configuration Metric") as e:
+ with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group VDU ID Reference") \
+ as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- mp = test_vnfd["monitoring-param"][0]["vdu-metric"]
- self.assertIn(norm("monitoring-param:vdu-metric:vdu-metric-name-ref='{}' not defined"
- " at vdu[id='{}'] or vdu does not exist"
- .format(mp["vdu-metric-name-ref"], mp["vdu-ref"])),
+ self.assertIn(norm("'vnf-configuration' not defined in the descriptor but it is referenced "
+ "by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
+ .format(df["id"], df['scaling-aspect'][0]["id"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- del test_vnfd["monitoring-param"]
- del test_vnfd["vdu"][0]["vdu-configuration"]
- with self.subTest(i=17, t='Check Input Validation: scaling-group-descriptor[scaling-policy][scaling-criteria]'):
- test_vnfd["monitoring-param"] = [{"id": "fake-mp-id"}]
- test_vnfd["scaling-group-descriptor"] = [{
- "name": "fake-vnf-sg-name",
- "vdu": [{"vdu-id-ref": "wrong-vdu-id-ref"}],
- "scaling-policy": [{"name": "fake-vnf-sp-name", "scaling-criteria": [{
- "name": "fake-vnf-sc-name", "vnf-monitoring-param-ref": "wrong-vnf-mp-id"}]}]}]
- with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group Policy Criteria") as e:
- self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- sg = test_vnfd["scaling-group-descriptor"][0]
- sc = sg["scaling-policy"][0]["scaling-criteria"][0]
- self.assertIn(norm("scaling-group-descriptor[name='{}']:scaling-criteria[name='{}']:"
- "vnf-monitoring-param-ref='{}' not defined in any monitoring-param"
- .format(sg["name"], sc["name"], sc["vnf-monitoring-param-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- with self.subTest(i=18, t='Check Input Validation: scaling-group-descriptor[vdu][vdu-id-ref]'):
- sc["vnf-monitoring-param-ref"] = "fake-mp-id"
- with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group VDU ID Reference") as e:
- self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("scaling-group-descriptor[name='{}']:vdu-id-ref={} does not match any vdu"
- .format(sg["name"], sg["vdu"][0]["vdu-id-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- with self.subTest(i=19, t='Check Input Validation: scaling-group-descriptor[scaling-config-action]'):
- tmp = test_vnfd["vnf-configuration"]
- del test_vnfd["vnf-configuration"]
- sg["vdu"][0]["vdu-id-ref"] = test_vnfd["vdu"][0]["id"]
- sg["scaling-config-action"] = [{"trigger": "pre-scale-in"}]
+ test_vnfd["vnf-configuration"] = tmp
+ with self.subTest(i=14, t='Check Input Validation: scaling-config-action'):
+ df = test_vnfd['df'][0]
+ tmp = test_vnfd['vnf-configuration'][0]['config-primitive']
+ test_vnfd['vnf-configuration'][0]['config-primitive'] = [{'name': 'wrong-primitive'}]
try:
- with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group VDU ID Reference") \
- as e:
+ with self.assertRaises(EngineException,
+ msg="Accepted non-existent Scaling Group VDU ID Reference") as e:
self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("'vnf-configuration' not defined in the descriptor but it is referenced"
- " by scaling-group-descriptor[name='{}']:scaling-config-action"
- .format(sg["name"])),
+ self.assertIn(norm("df[id='{}']:scaling-aspect[id='{}']:scaling-config-action:vnf-"
+ "config-primitive-name-ref='{}' does not match any "
+ "vnf-configuration:config-primitive:name"
+ .format(df["id"], df['scaling-aspect'][0]["id"],
+ sa['scaling-config-action'][0]['vnf-config-primitive-name-ref'])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_vnfd["vnf-configuration"] = tmp
- with self.subTest(i=20, t='Check Input Validation: scaling-group-descriptor[scaling-config-action]'
- '[vnf-config-primitive-name-ref]'):
- sg["scaling-config-action"][0]["vnf-config-primitive-name-ref"] = "wrong-sca-prim-name"
- with self.assertRaises(EngineException, msg="Accepted non-existent Scaling Group VDU ID Reference") as e:
- self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("scaling-group-descriptor[name='{}']:scaling-config-action:"
- "vnf-config-primitive-name-ref='{}' does not match"
- " any vnf-configuration:config-primitive:name"
- .format(sg["name"], sg["scaling-config-action"][0]["vnf-config-primitive-name-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- # del test_vnfd["monitoring-param"]
- # del test_vnfd["scaling-group-descriptor"]
- with self.subTest(i=21, t='Check Input Validation: everything right'):
- sg["scaling-config-action"][0]["vnf-config-primitive-name-ref"] = "touch"
+ test_vnfd['vnf-configuration'][0]['config-primitive'] = tmp
+ with self.subTest(i=15, t='Check Input Validation: everything right'):
test_vnfd["id"] = "fake-vnfd-id"
self.db.get_one.side_effect = [{"_id": did, "_admin": db_vnfd_content["_admin"]}, None]
rc = self.topic.upload_content(fake_session, did, test_vnfd, {}, {"Content-Type": []})
return
def test_edit_vnfd(self):
- did = db_vnfd_content["_id"]
+ vnfd_content = deepcopy(db_vnfd_content)
+ did = vnfd_content["_id"]
self.fs.file_exists.return_value = True
self.fs.dir_ls.return_value = True
with self.subTest(i=1, t='Normal Edition'):
now = time()
- self.db.get_one.side_effect = [db_vnfd_content, None]
- data = {"id": "new-vnfd-id", "name": "new-vnfd-name"}
+ self.db.get_one.side_effect = [vnfd_content, None]
+ data = {"id": "new-vnfd-id", "product-name": "new-vnfd-name"}
self.topic.edit(fake_session, did, data)
db_args = self.db.replace.call_args[0]
msg_args = self.msg.write.call_args[0]
self.assertEqual(msg_args[2], data, "Wrong message content")
self.assertEqual(db_args[0], self.topic.topic, "Wrong DB topic")
self.assertEqual(db_args[1], did, "Wrong DB ID")
- self.assertEqual(db_args[2]["_admin"]["created"], db_vnfd_content["_admin"]["created"],
+ self.assertEqual(db_args[2]["_admin"]["created"], vnfd_content["_admin"]["created"],
"Wrong creation time")
self.assertGreater(db_args[2]["_admin"]["modified"], now,
"Wrong modification time")
- self.assertEqual(db_args[2]["_admin"]["projects_read"], db_vnfd_content["_admin"]["projects_read"],
+ self.assertEqual(db_args[2]["_admin"]["projects_read"], vnfd_content["_admin"]["projects_read"],
"Wrong read-only project list")
- self.assertEqual(db_args[2]["_admin"]["projects_write"], db_vnfd_content["_admin"]["projects_write"],
+ self.assertEqual(db_args[2]["_admin"]["projects_write"], vnfd_content["_admin"]["projects_write"],
"Wrong read-write project list")
self.assertEqual(db_args[2]["id"], data["id"], "Wrong VNFD ID")
- self.assertEqual(db_args[2]["name"], data["name"], "Wrong VNFD Name")
+ self.assertEqual(db_args[2]["product-name"], data["product-name"], "Wrong VNFD Name")
with self.subTest(i=2, t='Conflict on Edit'):
- data = {"id": "fake-vnfd-id", "name": "new-vnfd-name"}
- self.db.get_one.side_effect = [db_vnfd_content, {"_id": str(uuid4()), "id": data["id"]}]
+ data = {"id": "fake-vnfd-id", "product-name": "new-vnfd-name"}
+ self.db.get_one.side_effect = [vnfd_content, {"_id": str(uuid4()), "id": data["id"]}]
with self.assertRaises(EngineException, msg="Accepted existing VNFD ID") as e:
self.topic.edit(fake_session, did, data)
self.assertEqual(e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code")
self.assertIn(norm("{} with id '{}' already exists for this project".format("vnfd", data["id"])),
norm(str(e.exception)), "Wrong exception text")
with self.subTest(i=3, t='Check Envelope'):
- data = {"vnfd": {"id": "new-vnfd-id-1", "name": "new-vnfd-name"}}
+ data = {"vnfd": [{"id": "new-vnfd-id-1", "product-name": "new-vnfd-name"}]}
with self.assertRaises(EngineException, msg="Accepted VNFD with wrong envelope") as e:
- self.topic.edit(fake_session, did, data)
+ self.topic.edit(fake_session, did, data, content=vnfd_content)
self.assertEqual(e.exception.http_code, HTTPStatus.BAD_REQUEST, "Wrong HTTP status code")
- self.assertIn("'vnfd' must be a list of only one element", norm(str(e.exception)), "Wrong exception text")
+ self.assertIn("'vnfd' must be dict", norm(str(e.exception)), "Wrong exception text")
return
def test_delete_vnfd(self):
self.fs.file_delete.assert_not_called()
return
- def test_validate_mgmt_interfaces_connection_points_on_valid_descriptor(self):
+ def test_validate_mgmt_interface_connection_point_on_valid_descriptor(self):
indata = deepcopy(db_vnfd_content)
- self.topic.validate_mgmt_interfaces_connection_points(indata)
+ self.topic.validate_mgmt_interface_connection_point(indata)
- def test_validate_mgmt_interfaces_connection_points_when_missing_connection_point(self):
+ def test_validate_mgmt_interface_connection_point_when_missing_connection_point(self):
indata = deepcopy(db_vnfd_content)
- indata['connection-point'] = []
+ indata['ext-cpd'] = []
with self.assertRaises(EngineException) as e:
- self.topic.validate_mgmt_interfaces_connection_points(indata)
+ self.topic.validate_mgmt_interface_connection_point(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("mgmt-interface:cp='{}' must match an existing connection-point"
- .format(indata["mgmt-interface"]["cp"])),
+ self.assertIn(norm("mgmt-cp='{}' must match an existing ext-cpd"
+ .format(indata["mgmt-cp"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_mgmt_interfaces_connection_points_when_missing_mgmt_interface(self):
+ def test_validate_mgmt_interface_connection_point_when_missing_mgmt_cp(self):
indata = deepcopy(db_vnfd_content)
- indata.pop('mgmt-interface')
+ indata.pop('mgmt-cp')
with self.assertRaises(EngineException) as e:
- self.topic.validate_mgmt_interfaces_connection_points(indata)
+ self.topic.validate_mgmt_interface_connection_point(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("'mgmt-interface' is a mandatory field and it is not defined"),
+ self.assertIn(norm("'mgmt-cp' is a mandatory field and it is not defined"),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_vdu_connection_point_refs_on_valid_descriptor(self):
+ def test_validate_vdu_internal_connection_points_on_valid_descriptor(self):
indata = db_vnfd_content
vdu = indata['vdu'][0]
- self.topic.validate_vdu_connection_point_refs(vdu, indata)
+ self.topic.validate_vdu_internal_connection_points(vdu)
- def test_validate_vdu_connection_point_refs_when_missing_internal_connection_point(self):
- indata = deepcopy(db_vnfd_content)
- vdu = indata['vdu'][0]
- vdu.pop('internal-connection-point')
- with self.assertRaises(EngineException) as e:
- self.topic.validate_vdu_connection_point_refs(vdu, indata)
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("vdu[id='{}']:interface[name='{}']:internal-connection-point-ref='{}' "
- "must match an existing vdu:internal-connection-point"
- .format(vdu["id"], vdu['interface'][1]["name"],
- vdu['interface'][1]["internal-connection-point-ref"])),
- norm(str(e.exception)), "Wrong exception text")
+ def test_validate_external_connection_points_on_valid_descriptor(self):
+ indata = db_vnfd_content
+ self.topic.validate_external_connection_points(indata)
- def test_validate_vdu_connection_point_refs_when_missing_external_connection_point(self):
+ def test_validate_external_connection_points_when_missing_internal_connection_point(self):
indata = deepcopy(db_vnfd_content)
vdu = indata['vdu'][0]
- indata.pop('connection-point')
+ vdu.pop('int-cpd')
+ affected_ext_cpd = indata["ext-cpd"][0]
with self.assertRaises(EngineException) as e:
- self.topic.validate_vdu_connection_point_refs(vdu, indata)
+ self.topic.validate_external_connection_points(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("vdu[id='{}']:interface[name='{}']:external-connection-point-ref='{}' "
- "must match an existing connection-point"
- .format(vdu["id"], vdu['interface'][0]["name"],
- vdu['interface'][0]["external-connection-point-ref"])),
+ self.assertIn(norm("ext-cpd[id='{}']:int-cpd must match an existing vdu int-cpd"
+ .format(affected_ext_cpd["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_vdu_connection_point_refs_on_duplicated_internal_connection_point_ref(self):
+ def test_validate_vdu_internal_connection_points_on_duplicated_internal_connection_point(self):
indata = deepcopy(db_vnfd_content)
vdu = indata['vdu'][0]
- duplicated_interface = {'name': 'dup-mgmt-eth1', 'position': 3,
- 'internal-connection-point-ref': 'mgmtVM-internal'}
- vdu['interface'].insert(0, duplicated_interface)
+ duplicated_cpd = {'id': 'vnf-mgmt', 'order': 3,
+ 'virtual-network-interface-requirement': [{'name': 'duplicated'}]}
+ vdu['int-cpd'].insert(0, duplicated_cpd)
with self.assertRaises(EngineException) as e:
- self.topic.validate_vdu_connection_point_refs(vdu, indata)
+ self.topic.validate_vdu_internal_connection_points(vdu)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("vdu[id='{}']:interface[name='{}']:internal-connection-point-ref='{}' "
- "is referenced by other interface"
- .format(vdu["id"], vdu['interface'][2]["name"],
- vdu['interface'][2]["internal-connection-point-ref"])),
+ self.assertIn(norm("vdu[id='{}']:int-cpd[id='{}'] is already used by other int-cpd"
+ .format(vdu["id"], duplicated_cpd["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_vdu_connection_point_refs_on_duplicated_external_connection_point_ref(self):
+ def test_validate_external_connection_points_on_duplicated_external_connection_point(self):
indata = deepcopy(db_vnfd_content)
- vdu = indata['vdu'][0]
- duplicated_interface = {'name': 'dup-mgmt-eth0', 'position': 3, 'external-connection-point-ref': 'vnf-mgmt'}
- vdu['interface'].insert(0, duplicated_interface)
+ duplicated_cpd = {'id': 'vnf-mgmt-ext', 'int-cpd': {'vdu-id': 'dataVM', 'cpd': 'vnf-data'}}
+ indata['ext-cpd'].insert(0, duplicated_cpd)
with self.assertRaises(EngineException) as e:
- self.topic.validate_vdu_connection_point_refs(vdu, indata)
+ self.topic.validate_external_connection_points(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("vdu[id='{}']:interface[name='{}']:external-connection-point-ref='{}' "
- "is referenced by other interface"
- .format(vdu["id"], vdu['interface'][1]["name"],
- vdu['interface'][1]["external-connection-point-ref"])),
+ self.assertIn(norm("ext-cpd[id='{}'] is already used by other ext-cpd"
+ .format(duplicated_cpd["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_internal_vlds_on_valid_descriptor(self):
+ def test_validate_internal_virtual_links_on_valid_descriptor(self):
indata = db_vnfd_content
- self.topic.validate_internal_vlds(indata)
+ self.topic.validate_internal_virtual_links(indata)
- def test_validate_internal_vlds_on_duplicated_vld(self):
+ def test_validate_internal_virtual_links_on_duplicated_ivld(self):
indata = deepcopy(db_vnfd_content)
- duplicated_vld = {'id': 'internal', 'name': 'internal',
- 'internal-connection-point': [{'id-ref': 'mgmtVM-internal'}, {'id-ref': 'dataVM-internal'}]}
- indata['internal-vld'].insert(0, duplicated_vld)
+ duplicated_vld = {'id': 'internal'}
+ indata['int-virtual-link-desc'].insert(0, duplicated_vld)
with self.assertRaises(EngineException) as e:
- self.topic.validate_internal_vlds(indata)
+ self.topic.validate_internal_virtual_links(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Duplicated VLD name '{}' in vnfd[id={}]:internal-vld[id={}]"
- .format(indata['internal-vld'][1]["name"], indata["id"], indata['internal-vld'][1]["id"])),
+ self.assertIn(norm("Duplicated VLD id in int-virtual-link-desc[id={}]"
+ .format(duplicated_vld["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_internal_vlds_when_missing_internal_connection_point(self):
+ def test_validate_internal_virtual_links_when_missing_ivld_on_connection_point(self):
indata = deepcopy(db_vnfd_content)
- ivld = indata['internal-vld'][0]
- icp = ivld['internal-connection-point'][0]
- indata['vdu'][0]['internal-connection-point'].pop()
+ vdu = indata['vdu'][0]
+ affected_int_cpd = vdu['int-cpd'][0]
+ affected_int_cpd['int-virtual-link-desc'] = 'non-existing-int-virtual-link-desc'
with self.assertRaises(EngineException) as e:
- self.topic.validate_internal_vlds(indata)
+ self.topic.validate_internal_virtual_links(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("internal-vld[id='{}']:internal-connection-point='{}' must match an existing "
- "vdu:internal-connection-point".format(ivld["id"], icp["id-ref"])),
+ self.assertIn(norm("vdu[id='{}']:int-cpd[id='{}']:int-virtual-link-desc='{}' must match an existing "
+ "int-virtual-link-desc".format(vdu["id"], affected_int_cpd["id"],
+ affected_int_cpd['int-virtual-link-desc'])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_internal_vlds_when_missing_ip_profile(self):
+ def test_validate_internal_virtual_links_when_missing_ivld_on_profile(self):
indata = deepcopy(db_vnfd_content)
- ivld = indata['internal-vld'][0]
- ivld['ip-profile-ref'] = 'non-existing-ip-profile'
+ affected_ivld_profile = {'id': 'non-existing-int-virtual-link-desc'}
+ df = indata['df'][0]
+ df['virtual-link-profile'] = [affected_ivld_profile]
with self.assertRaises(EngineException) as e:
- self.topic.validate_internal_vlds(indata)
+ self.topic.validate_internal_virtual_links(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("internal-vld[id='{}']:ip-profile-ref='{}' does not exist".format(
- ivld["id"], ivld["ip-profile-ref"])),
- norm(str(e.exception)), "Wrong exception text")
+ self.assertIn(norm("df[id='{}']:virtual-link-profile='{}' must match an existing "
+ "int-virtual-link-desc".format(df["id"], affected_ivld_profile["id"])),
+ norm(str(e.exception)), "Wrong exception text")
def test_validate_monitoring_params_on_valid_descriptor(self):
indata = db_vnfd_content
self.topic.validate_monitoring_params(indata)
- def test_validate_monitoring_params_when_missing_vdu(self):
+ def test_validate_monitoring_params_on_duplicated_ivld_monitoring_param(self):
indata = deepcopy(db_vnfd_content)
- monitoring_param = indata['monitoring-param'][0]
- indata['vdu'].pop()
+ duplicated_mp = {'id': 'cpu', 'name': 'cpu', 'performance_metric': 'cpu'}
+ affected_ivld = indata['int-virtual-link-desc'][0]
+ affected_ivld['monitoring-parameters'] = [duplicated_mp, duplicated_mp]
with self.assertRaises(EngineException) as e:
self.topic.validate_monitoring_params(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("monitoring-param:vdu-monitoring-param:vdu-monitoring-param-ref='{}' not "
- "defined at vdu[id='{}'] or vdu does not exist"
- .format(monitoring_param["vdu-monitoring-param"]["vdu-monitoring-param-ref"],
- monitoring_param["vdu-monitoring-param"]["vdu-ref"])),
+ self.assertIn(norm("Duplicated monitoring-parameter id in "
+ "int-virtual-link-desc[id='{}']:monitoring-parameters[id='{}']"
+ .format(affected_ivld["id"], duplicated_mp["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_monitoring_params_when_missing_vdu_monitoring_param_ref(self):
+ def test_validate_monitoring_params_on_duplicated_vdu_monitoring_param(self):
indata = deepcopy(db_vnfd_content)
- monitoring_param = indata['monitoring-param'][0]
- indata['vdu'][1]['monitoring-param'] = []
+ duplicated_mp = {'id': 'dataVM_cpu_util', 'name': 'dataVM_cpu_util', 'performance_metric': 'cpu'}
+ affected_vdu = indata['vdu'][1]
+ affected_vdu['monitoring-parameter'].insert(0, duplicated_mp)
with self.assertRaises(EngineException) as e:
self.topic.validate_monitoring_params(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("monitoring-param:vdu-monitoring-param:vdu-monitoring-param-ref='{}' not "
- "defined at vdu[id='{}'] or vdu does not exist"
- .format(monitoring_param["vdu-monitoring-param"]["vdu-monitoring-param-ref"],
- monitoring_param["vdu-monitoring-param"]["vdu-ref"])),
+ self.assertIn(norm("Duplicated monitoring-parameter id in "
+ "vdu[id='{}']:monitoring-parameter[id='{}']"
+ .format(affected_vdu["id"], duplicated_mp["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_scaling_group_descriptor_on_valid_descriptor(self):
- indata = db_vnfd_content
- self.topic.validate_scaling_group_descriptor(indata)
-
- def test_validate_scaling_group_descriptor_when_missing_vnf_monitoring_param_ref(self):
+ def test_validate_monitoring_params_on_duplicated_df_monitoring_param(self):
indata = deepcopy(db_vnfd_content)
- sgd = indata['scaling-group-descriptor'][0]
- sc = sgd['scaling-policy'][0]['scaling-criteria'][0]
- indata['monitoring-param'] = []
+ duplicated_mp = {'id': 'memory', 'name': 'memory', 'performance_metric': 'memory'}
+ affected_df = indata['df'][0]
+ affected_df['monitoring-parameter'] = [duplicated_mp, duplicated_mp]
with self.assertRaises(EngineException) as e:
- self.topic.validate_scaling_group_descriptor(indata)
+ self.topic.validate_monitoring_params(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("scaling-group-descriptor[name='{}']:scaling-criteria[name='{}']:"
- "vnf-monitoring-param-ref='{}' not defined in any monitoring-param"
- .format(sgd["name"], sc["name"], sc["vnf-monitoring-param-ref"])),
+ self.assertIn(norm("Duplicated monitoring-parameter id in "
+ "df[id='{}']:monitoring-parameter[id='{}']"
+ .format(affected_df["id"], duplicated_mp["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_scaling_group_descriptor_when_missing_vdu(self):
+ def test_validate_scaling_group_descriptor_on_valid_descriptor(self):
+ indata = db_vnfd_content
+ self.topic.validate_scaling_group_descriptor(indata)
+
+ def test_validate_scaling_group_descriptor_when_missing_monitoring_param(self):
indata = deepcopy(db_vnfd_content)
- sgd = indata['scaling-group-descriptor'][0]
- sgd_vdu = sgd['vdu'][0]
- indata['vdu'].pop()
+ vdu = indata['vdu'][1]
+ affected_df = indata['df'][0]
+ affected_sa = affected_df['scaling-aspect'][0]
+ affected_sp = affected_sa['scaling-policy'][0]
+ affected_sc = affected_sp['scaling-criteria'][0]
+ vdu.pop('monitoring-parameter')
with self.assertRaises(EngineException) as e:
self.topic.validate_scaling_group_descriptor(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("scaling-group-descriptor[name='{}']:vdu-id-ref={} does not match any vdu"
- .format(sgd["name"], sgd_vdu["vdu-id-ref"])),
+ self.assertIn(norm("df[id='{}']:scaling-aspect[id='{}']:scaling-policy"
+ "[name='{}']:scaling-criteria[name='{}']: "
+ "vnf-monitoring-param-ref='{}' not defined in any monitoring-param"
+ .format(affected_df["id"], affected_sa["id"], affected_sp["name"], affected_sc["name"],
+ affected_sc["vnf-monitoring-param-ref"])),
norm(str(e.exception)), "Wrong exception text")
def test_validate_scaling_group_descriptor_when_missing_vnf_configuration(self):
indata = deepcopy(db_vnfd_content)
- sgd = indata['scaling-group-descriptor'][0]
+ df = indata['df'][0]
+ affected_sa = df['scaling-aspect'][0]
indata.pop('vnf-configuration')
with self.assertRaises(EngineException) as e:
self.topic.validate_scaling_group_descriptor(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("'vnf-configuration' not defined in the descriptor but it is referenced by "
- "scaling-group-descriptor[name='{}']:scaling-config-action"
- .format(sgd["name"])),
+ self.assertIn(norm("'vnf-configuration' not defined in the descriptor but it is referenced "
+ "by df[id='{}']:scaling-aspect[id='{}']:scaling-config-action"
+ .format(df["id"], affected_sa["id"])),
norm(str(e.exception)), "Wrong exception text")
def test_validate_scaling_group_descriptor_when_missing_scaling_config_action_primitive(self):
indata = deepcopy(db_vnfd_content)
- sgd = indata['scaling-group-descriptor'][0]
- sca = sgd['scaling-config-action'][0]
- indata['vnf-configuration']['config-primitive'] = []
+ df = indata['df'][0]
+ affected_sa = df['scaling-aspect'][0]
+ affected_sca_primitive = affected_sa['scaling-config-action'][0]['vnf-config-primitive-name-ref']
+ indata['vnf-configuration'][0]['config-primitive'] = []
with self.assertRaises(EngineException) as e:
self.topic.validate_scaling_group_descriptor(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("scaling-group-descriptor[name='{}']:scaling-config-action:vnf-config-"
- "primitive-name-ref='{}' does not match any "
+ self.assertIn(norm("df[id='{}']:scaling-aspect[id='{}']:scaling-config-action:vnf-"
+ "config-primitive-name-ref='{}' does not match any "
"vnf-configuration:config-primitive:name"
- .format(sgd["name"], sca["vnf-config-primitive-name-ref"])),
+ .format(df["id"], affected_sa["id"], affected_sca_primitive)),
norm(str(e.exception)), "Wrong exception text")
finally:
del test_nsd["extra-property"]
with self.subTest(i=4, t='Check Pyangbind Validation: property types'):
- tmp = test_nsd["short-name"]
- test_nsd["short-name"] = {"key": 0}
+ tmp = test_nsd["designer"]
+ test_nsd["designer"] = {"key": 0}
try:
with self.assertRaises(EngineException, msg="Accepted NSD with a wrongly typed property") as e:
self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
.format("json object contained a key that did not exist", "key")),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_nsd["short-name"] = tmp
- with self.subTest(i=5, t='Check Input Validation: vld[mgmt-network+ip-profile]'):
- tmp = test_nsd["vld"][0]["vim-network-name"]
- del test_nsd["vld"][0]["vim-network-name"]
- test_nsd["vld"][0]["ip-profile-ref"] = "fake-ip-profile"
+ test_nsd["designer"] = tmp
+ with self.subTest(i=5, t='Check Input Validation: mgmt-network+virtual-link-protocol-data'):
+ df = test_nsd['df'][0]
+ mgmt_profile = {'id': 'id', 'virtual-link-desc-id': 'mgmt',
+ 'virtual-link-protocol-data': {'associated-layer-protocol': 'ipv4'}}
+ df['virtual-link-profile'] = [mgmt_profile]
try:
with self.assertRaises(EngineException, msg="Accepted VLD with mgmt-network+ip-profile") as e:
self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:ip-profile-ref"
- " You cannot set an ip-profile when mgmt-network is True"
- .format(test_nsd["vld"][0]["id"])),
+ self.assertIn(norm("Error at df[id='{}']:virtual-link-profile[id='{}']:virtual-link-protocol-data"
+ " You cannot set a virtual-link-protocol-data when mgmt-network is True"
+ .format(df["id"], mgmt_profile["id"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_nsd["vld"][0]["vim-network-name"] = tmp
- del test_nsd["vld"][0]["ip-profile-ref"]
- with self.subTest(i=6, t='Check Input Validation: vld[vnfd-connection-point-ref][vnfd-id-ref]'):
- tmp = test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-id-ref"]
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-id-ref"] = "wrong-vnfd-id-ref"
- try:
- with self.assertRaises(EngineException, msg="Accepted VLD with wrong vnfd-connection-point-ref") as e:
- self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:vnfd-connection-point-ref[vnfd-id-ref='{}']"
- " does not match constituent-vnfd[member-vnf-index='{}']:vnfd-id-ref '{}'"
- .format(test_nsd["vld"][0]["id"],
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-id-ref"],
- test_nsd["constituent-vnfd"][0]["member-vnf-index"],
- test_nsd["constituent-vnfd"][0]["vnfd-id-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- finally:
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-id-ref"] = tmp
- with self.subTest(i=7, t='Check Input Validation: vld[vnfd-connection-point-ref][member-vnf-index-ref]'):
- tmp = test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["member-vnf-index-ref"]
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["member-vnf-index-ref"] = "wrong-member-vnf-index-ref"
- try:
- with self.assertRaises(EngineException, msg="Accepted VLD with wrong vnfd-connection-point-ref") as e:
- self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:vnfd-connection-point-ref[member-vnf-index-ref='{}']"
- " does not match any constituent-vnfd:member-vnf-index"
- .format(test_nsd["vld"][0]["id"],
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["member-vnf-index-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- finally:
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["member-vnf-index-ref"] = tmp
- with self.subTest(i=8, t='Check Input Validation: vnffgd[classifier][rsp-id-ref]'):
- test_nsd["vnffgd"] = [{"id": "fake-vnffgd-id",
- "rsp": [{"id": "fake-rsp-id"}],
- "classifier": [{"id": "fake-vnffgd-classifier-id", "rsp-id-ref": "wrong-rsp-id"}]}]
- try:
- with self.assertRaises(EngineException, msg="Accepted VNF FGD with wrong classifier rsp-id-ref") as e:
- self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vnffgd[id='{}']:classifier[id='{}']:rsp-id-ref '{}'"
- " does not match any rsp:id"
- .format(test_nsd["vnffgd"][0]["id"],
- test_nsd["vnffgd"][0]["classifier"][0]["id"],
- test_nsd["vnffgd"][0]["classifier"][0]["rsp-id-ref"])),
- norm(str(e.exception)), "Wrong exception text")
- finally:
- test_nsd["vnffgd"][0]["classifier"][0]["rsp-id-ref"] = "fake-rsp-id"
- with self.subTest(i=9, t='Check Descriptor Dependencies: constituent-vnfd[vnfd-id-ref]'):
+ del df['virtual-link-profile']
+ with self.subTest(i=6, t='Check Descriptor Dependencies: constituent-vnfd[vnfd-id-ref]'):
self.db.get_one.side_effect = [{"_id": did, "_admin": db_nsd_content["_admin"]}, None]
self.db.get_list.return_value = []
try:
with self.assertRaises(EngineException, msg="Accepted wrong constituent VNFD ID reference") as e:
self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code")
- self.assertIn(norm("Descriptor error at 'constituent-vnfd':'vnfd-id-ref'='{}'"
- " references a non existing vnfd"
- .format(test_nsd["constituent-vnfd"][0]["vnfd-id-ref"])),
+ self.assertIn(norm("'vnfd-id'='{}' references a non existing vnfd".format(test_nsd['vnfd-id'][0])),
norm(str(e.exception)), "Wrong exception text")
finally:
pass
- with self.subTest(i=10, t='Check Descriptor Dependencies: '
- 'vld[vnfd-connection-point-ref][vnfd-connection-point-ref]'):
- tmp = test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-connection-point-ref"]
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-connection-point-ref"] = "wrong-vnfd-cp-ref"
+ with self.subTest(i=7, t='Check Descriptor Dependencies: '
+ 'vld[vnfd-connection-point-ref][vnfd-connection-point-ref]'):
+ vnfd_descriptor = deepcopy(db_vnfd_content)
+ df = test_nsd['df'][0]
+ affected_vnf_profile = df['vnf-profile'][0]
+ affected_virtual_link = affected_vnf_profile['virtual-link-connectivity'][1]
+ affected_cpd = vnfd_descriptor['ext-cpd'].pop()
self.db.get_one.side_effect = [{"_id": did, "_admin": db_nsd_content["_admin"]}, None]
- self.db.get_list.return_value = [db_vnfd_content]
+ self.db.get_list.return_value = [vnfd_descriptor]
try:
with self.assertRaises(EngineException, msg="Accepted wrong VLD CP reference") as e:
self.topic.upload_content(fake_session, did, test_nsd, {}, {"Content-Type": []})
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:vnfd-connection-point-ref[member-vnf-index-ref='{}']:"
- "vnfd-connection-point-ref='{}' references a non existing conection-point:name"
- " inside vnfd '{}'"
- .format(test_nsd["vld"][0]["id"],
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["member-vnf-index-ref"],
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]
- ["vnfd-connection-point-ref"],
- db_vnfd_content["id"])),
+ self.assertIn(norm("Error at df[id='{}']:vnf-profile[id='{}']:virtual-link-connectivity"
+ "[virtual-link-profile-id='{}']:constituent-cpd-id='{}' references a "
+ "non existing ext-cpd:id inside vnfd '{}'"
+ .format(df["id"], affected_vnf_profile["id"],
+ affected_virtual_link["virtual-link-profile-id"], affected_cpd["id"],
+ vnfd_descriptor["id"])),
norm(str(e.exception)), "Wrong exception text")
finally:
- test_nsd["vld"][0]["vnfd-connection-point-ref"][0]["vnfd-connection-point-ref"] = tmp
+ pass
return
def test_edit_nsd(self):
- did = db_nsd_content["_id"]
+ nsd_content = deepcopy(db_nsd_content)
+ did = nsd_content["_id"]
self.fs.file_exists.return_value = True
self.fs.dir_ls.return_value = True
with self.subTest(i=1, t='Normal Edition'):
now = time()
- self.db.get_one.side_effect = [db_nsd_content, None]
+ self.db.get_one.side_effect = [nsd_content, None]
self.db.get_list.return_value = [db_vnfd_content]
data = {"id": "new-nsd-id", "name": "new-nsd-name"}
self.topic.edit(fake_session, did, data)
self.assertEqual(msg_args[2], data, "Wrong message content")
self.assertEqual(db_args[0], self.topic.topic, "Wrong DB topic")
self.assertEqual(db_args[1], did, "Wrong DB ID")
- self.assertEqual(db_args[2]["_admin"]["created"], db_nsd_content["_admin"]["created"],
+ self.assertEqual(db_args[2]["_admin"]["created"], nsd_content["_admin"]["created"],
"Wrong creation time")
self.assertGreater(db_args[2]["_admin"]["modified"], now, "Wrong modification time")
- self.assertEqual(db_args[2]["_admin"]["projects_read"], db_nsd_content["_admin"]["projects_read"],
+ self.assertEqual(db_args[2]["_admin"]["projects_read"], nsd_content["_admin"]["projects_read"],
"Wrong read-only project list")
- self.assertEqual(db_args[2]["_admin"]["projects_write"], db_nsd_content["_admin"]["projects_write"],
+ self.assertEqual(db_args[2]["_admin"]["projects_write"], nsd_content["_admin"]["projects_write"],
"Wrong read-write project list")
self.assertEqual(db_args[2]["id"], data["id"], "Wrong NSD ID")
self.assertEqual(db_args[2]["name"], data["name"], "Wrong NSD Name")
with self.subTest(i=2, t='Conflict on Edit'):
data = {"id": "fake-nsd-id", "name": "new-nsd-name"}
- self.db.get_one.side_effect = [db_nsd_content, {"_id": str(uuid4()), "id": data["id"]}]
+ self.db.get_one.side_effect = [nsd_content, {"_id": str(uuid4()), "id": data["id"]}]
with self.assertRaises(EngineException, msg="Accepted existing NSD ID") as e:
self.topic.edit(fake_session, did, data)
self.assertEqual(e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code")
self.assertIn(norm("{} with id '{}' already exists for this project".format("nsd", data["id"])),
norm(str(e.exception)), "Wrong exception text")
with self.subTest(i=3, t='Check Envelope'):
- data = {"nsd": {"id": "new-nsd-id", "name": "new-nsd-name"}}
+ data = {"nsd": {"nsd": {"id": "new-nsd-id", "name": "new-nsd-name"}}}
+ self.db.get_one.side_effect = [nsd_content, None]
with self.assertRaises(EngineException, msg="Accepted NSD with wrong envelope") as e:
- self.topic.edit(fake_session, did, data)
+ self.topic.edit(fake_session, did, data, content=nsd_content)
self.assertEqual(e.exception.http_code, HTTPStatus.BAD_REQUEST, "Wrong HTTP status code")
self.assertIn("'nsd' must be a list of only one element", norm(str(e.exception)), "Wrong exception text")
return
self.fs.file_delete.assert_not_called()
return
- def test_validate_vld_mgmt_network_with_ip_profile_ref_on_valid_descriptor(self):
+ def test_validate_vld_mgmt_network_with_virtual_link_protocol_data_on_valid_descriptor(self):
indata = deepcopy(db_nsd_content)
- vld = indata['vld'][0]
- self.topic.validate_vld_mgmt_network_with_ip_profile_ref(vld)
+ vld = indata['virtual-link-desc'][0]
+ self.topic.validate_vld_mgmt_network_with_virtual_link_protocol_data(vld, indata)
- def test_validate_vld_mgmt_network_with_ip_profile_ref_when_both_defined(self):
+ def test_validate_vld_mgmt_network_with_virtual_link_protocol_data_when_both_defined(self):
indata = deepcopy(db_nsd_content)
- vld = indata['vld'][0]
- vld['ip-profile-ref'] = 'a-profile-ref'
+ vld = indata['virtual-link-desc'][0]
+ df = indata['df'][0]
+ affected_vlp = {'id': 'id', 'virtual-link-desc-id': 'mgmt',
+ 'virtual-link-protocol-data': {'associated-layer-protocol': 'ipv4'}}
+ df['virtual-link-profile'] = [affected_vlp]
with self.assertRaises(EngineException) as e:
- self.topic.validate_vld_mgmt_network_with_ip_profile_ref(vld)
+ self.topic.validate_vld_mgmt_network_with_virtual_link_protocol_data(vld, indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:ip-profile-ref"
- " You cannot set an ip-profile when mgmt-network is True"
- .format(vld["id"])),
+ self.assertIn(norm("Error at df[id='{}']:virtual-link-profile[id='{}']:virtual-link-protocol-data"
+ " You cannot set a virtual-link-protocol-data when mgmt-network is True"
+ .format(df["id"], affected_vlp["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_vld_connection_point_refs_on_valid_descriptor(self):
+ def test_validate_vnf_profiles_vnfd_id_on_valid_descriptor(self):
indata = deepcopy(db_nsd_content)
- vld = indata['vld'][0]
- self.topic.validate_vld_connection_point_refs(vld, indata)
-
- def test_validate_vld_connection_point_refs_when_missing_constituent_vnfd(self):
- indata = deepcopy(db_nsd_content)
- vld = indata['vld'][0]
- vnfd_cp = vld['vnfd-connection-point-ref'][0]
- indata['constituent-vnfd'] = []
- with self.assertRaises(EngineException) as e:
- self.topic.validate_vld_connection_point_refs(vld, indata)
- self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:vnfd-connection-point-ref[member-vnf-index-ref='{}'] "
- "does not match any constituent-vnfd:member-vnf-index"
- .format(vld["id"], vnfd_cp["member-vnf-index-ref"])),
- norm(str(e.exception)), "Wrong exception text")
+ self.topic.validate_vnf_profiles_vnfd_id(indata)
- def test_validate_vld_connection_point_refs_on_unmatched_constituent_vnfd(self):
+ def test_validate_vnf_profiles_vnfd_id_when_missing_vnfd(self):
indata = deepcopy(db_nsd_content)
- vld = indata['vld'][0]
- vnfd_cp = vld['vnfd-connection-point-ref'][0]
- constituent_vnfd = indata['constituent-vnfd'][0]
- constituent_vnfd['vnfd-id-ref'] = 'unmatched-vnfd-id-ref'
+ df = indata['df'][0]
+ affected_vnf_profile = df['vnf-profile'][0]
+ indata['vnfd-id'] = ['non-existing-vnfd']
with self.assertRaises(EngineException) as e:
- self.topic.validate_vld_connection_point_refs(vld, indata)
+ self.topic.validate_vnf_profiles_vnfd_id(indata)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:vnfd-connection-point-ref[vnfd-id-ref='{}'] "
- "does not match constituent-vnfd[member-vnf-index='{}']:vnfd-id-ref"
- " '{}'".format(vld["id"], vnfd_cp["vnfd-id-ref"],
- constituent_vnfd["member-vnf-index"],
- constituent_vnfd["vnfd-id-ref"])),
+ self.assertIn(norm("Error at df[id='{}']:vnf_profile[id='{}']:vnfd-id='{}' "
+ "does not match any vnfd-id"
+ .format(df["id"], affected_vnf_profile["id"], affected_vnf_profile['vnfd-id'])),
norm(str(e.exception)), "Wrong exception text")
- def test_validate_vld_connection_point_refs_vnfd_connection_points_on_valid_descriptor(self):
+ def test_validate_df_vnf_profiles_constituent_connection_points_on_valid_descriptor(self):
nsd_descriptor = deepcopy(db_nsd_content)
- vnfd_1_descriptor = deepcopy(db_vnfd_content)
- vnfd_2_descriptor = deepcopy(db_vnfd_content)
- vld = nsd_descriptor['vld'][0]
- member_vnfd_index = {'1': vnfd_1_descriptor, '2': vnfd_2_descriptor}
- self.topic.validate_vld_connection_point_refs_vnfd_connection_points(vld, member_vnfd_index)
+ vnfd_descriptor = deepcopy(db_vnfd_content)
+ df = nsd_descriptor['df'][0]
+ vnfds_index = {vnfd_descriptor['id']: vnfd_descriptor}
+ self.topic.validate_df_vnf_profiles_constituent_connection_points(df, vnfds_index)
- def test_validate_vld_connection_point_refs_vnfd_connection_points_when_missing_connection_point(self):
+ def test_validate_df_vnf_profiles_constituent_connection_points_when_missing_connection_point(self):
nsd_descriptor = deepcopy(db_nsd_content)
- vnfd_1_descriptor = deepcopy(db_vnfd_content)
- vnfd_2_descriptor = deepcopy(db_vnfd_content)
- vld = nsd_descriptor['vld'][0]
- referenced_vnfd_cp = vld['vnfd-connection-point-ref'][0]
- member_vnfd_index = {'1': vnfd_1_descriptor, '2': vnfd_2_descriptor}
- vnfd_1_descriptor['connection-point'] = []
+ vnfd_descriptor = deepcopy(db_vnfd_content)
+ df = nsd_descriptor['df'][0]
+ affected_vnf_profile = df['vnf-profile'][0]
+ affected_virtual_link = affected_vnf_profile['virtual-link-connectivity'][1]
+ vnfds_index = {vnfd_descriptor['id']: vnfd_descriptor}
+ affected_cpd = vnfd_descriptor['ext-cpd'].pop()
with self.assertRaises(EngineException) as e:
- self.topic.validate_vld_connection_point_refs_vnfd_connection_points(vld, member_vnfd_index)
+ self.topic.validate_df_vnf_profiles_constituent_connection_points(df, vnfds_index)
self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
- self.assertIn(norm("Error at vld[id='{}']:vnfd-connection-point-ref[member-vnf-index-ref='{}']:vnfd-"
- "connection-point-ref='{}' references a non existing conection-point:name inside vnfd '{}'"
- .format(vld["id"], referenced_vnfd_cp["member-vnf-index-ref"],
- referenced_vnfd_cp["vnfd-connection-point-ref"], vnfd_1_descriptor["id"])),
+ self.assertIn(norm("Error at df[id='{}']:vnf-profile[id='{}']:virtual-link-connectivity"
+ "[virtual-link-profile-id='{}']:constituent-cpd-id='{}' references a "
+ "non existing ext-cpd:id inside vnfd '{}'"
+ .format(df["id"], affected_vnf_profile["id"],
+ affected_virtual_link["virtual-link-profile-id"], affected_cpd["id"],
+ vnfd_descriptor["id"])),
norm(str(e.exception)), "Wrong exception text")
- def test_check_conflict_on_edit_when_missing_vnfd_index(self):
+ def test_check_conflict_on_edit_when_missing_constituent_vnfd_id(self):
nsd_descriptor = deepcopy(db_nsd_content)
- invalid_vnfd_id_ref = 'invalid-vnfd-id-ref'
+ invalid_vnfd_id = 'invalid-vnfd-id'
nsd_descriptor['id'] = 'invalid-vnfd-id-ns'
- nsd_descriptor['constituent-vnfd'][0]['vnfd-id-ref'] = invalid_vnfd_id_ref
- nsd_descriptor['vld'][0]['vnfd-connection-point-ref'][0]['vnfd-id-ref'] = invalid_vnfd_id_ref
- nsd_descriptor['vld'][1]['vnfd-connection-point-ref'][0]['vnfd-id-ref'] = invalid_vnfd_id_ref
+ nsd_descriptor['vnfd-id'][0] = invalid_vnfd_id
+ nsd_descriptor['df'][0]['vnf-profile'][0]['vnfd-id'] = invalid_vnfd_id
+ nsd_descriptor['df'][0]['vnf-profile'][1]['vnfd-id'] = invalid_vnfd_id
with self.assertRaises(EngineException) as e:
self.db.get_list.return_value = []
self.topic.check_conflict_on_edit(fake_session, nsd_descriptor, [], 'id')
self.assertEqual(e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code")
- self.assertIn(norm("Descriptor error at 'constituent-vnfd':'vnfd-id-ref'='{}' references a non "
- "existing vnfd".format(invalid_vnfd_id_ref)),
+ self.assertIn(norm("Descriptor error at 'vnfd-id'='{}' references a non "
+ "existing vnfd".format(invalid_vnfd_id)),
norm(str(e.exception)), "Wrong exception text")
"nsdId": self.nsd_id,
"nsName": "name",
"vimAccountId": self.vim_id,
- "additionalParamsForVnf": [{"member-vnf-index": "1", "additionalParams": {"touch_filename": "file"}},
- {"member-vnf-index": "2", "additionalParams": {"touch_filename": "file"}}]
+ "additionalParamsForVnf": [
+ {"member-vnf-index": "hackfest_vnf1", "additionalParams": {"touch_filename": "file"}},
+ {"member-vnf-index": "hackfest_vnf2", "additionalParams": {"touch_filename": "file"}}
+ ]
}
rollback = []
headers = {}
self.assertTrue(created_item["_admin"]["nsState"] == "NOT_INSTANTIATED",
"Database record must contain '_admin.nstate=NOT INSTANTIATE'")
- self.assertEqual(len(created_vnfrs), len(self.nsd["constituent-vnfd"]),
- "created a mismatch number of vnfr at database")
+ self.assertEqual(len(created_vnfrs), 2, "created a mismatch number of vnfr at database")
self.assertEqual(len(created_nsrs), 1, "Only one nsrs must be created at database")
self.assertEqual(len(rollback), len(created_vnfrs) + 1, "rollback mismatch with created items at database")
usageState: NOT_IN_USE
userDefinedData: {}
_id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77
- connection-point:
- - id: vnf-mgmt
- name: vnf-mgmt
- short-name: vnf-mgmt
- type: VPORT
- - id: vnf-data
- name: vnf-data
- short-name: vnf-data
- type: VPORT
- description: A VNF consisting of 2 VDUs connected to an internal VL, and one VDU
- with cloud-init
id: hackfest3charmed-vnf
- internal-vld:
- - id: internal
- internal-connection-point:
- - id-ref: mgmtVM-internal
- - id-ref: dataVM-internal
- name: internal
- short-name: internal
- type: ELAN
- logo: osm.png
- mgmt-interface:
- cp: vnf-mgmt
- monitoring-param:
- - aggregation-type: AVERAGE
- id: monitor1
- name: monitor1
- vdu-monitoring-param:
- vdu-monitoring-param-ref: dataVM_cpu_util
- vdu-ref: dataVM
- name: hackfest3charmed-vnf
- scaling-group-descriptor:
- - max-instance-count: 10
- name: scale_dataVM
- scaling-config-action:
- - trigger: post-scale-out
- vnf-config-primitive-name-ref: touch
- - trigger: pre-scale-in
- vnf-config-primitive-name-ref: touch
- scaling-policy:
- - cooldown-time: 60
- name: auto_cpu_util_above_threshold
- scaling-criteria:
- - name: cpu_util_above_threshold
- scale-in-relational-operation: LE
- scale-in-threshold: '15.0000000000'
- scale-out-relational-operation: GE
- scale-out-threshold: '60.0000000000'
- vnf-monitoring-param-ref: monitor1
- scaling-type: automatic
- threshold-time: 0
- vdu:
- - count: 1
- vdu-id-ref: dataVM
- short-name: hackfest3charmed-vnf
+ description: >-
+ A VNF consisting of 2 VDUs connected to an internal VL, and one VDU with
+ cloud-init
+ product-name: hackfest3charmed-vnf
+ version: '1.0'
+ mgmt-cp: vnf-mgmt-ext
+
+ virtual-compute-desc:
+ - id: mgmt-compute
+ virtual-cpu:
+ num-virtual-cpu: 2
+ virtual-memory:
+ size: '2'
+ - id: data-compute
+ virtual-cpu:
+ num-virtual-cpu: 2
+ virtual-memory:
+ size: '2'
+
+ virtual-storage-desc:
+ - id: mgmt-storage
+ size-of-storage: '20'
+ - id: data-storage
+ size-of-storage: '20'
+
+ sw-image-desc:
+ - id: hackfest3-mgmt
+ name: hackfest3-mgmt
+
vdu:
- - count: '1'
- cloud-init-file: cloud-config.txt
- id: mgmtVM
- image: hackfest3-mgmt
- interface:
- - external-connection-point-ref: vnf-mgmt
- name: mgmtVM-eth0
- position: 1
- type: EXTERNAL
- virtual-interface:
- type: VIRTIO
- - internal-connection-point-ref: mgmtVM-internal
- name: mgmtVM-eth1
- position: 2
- type: INTERNAL
- virtual-interface:
- type: VIRTIO
- internal-connection-point:
- - id: mgmtVM-internal
- name: mgmtVM-internal
- short-name: mgmtVM-internal
- type: VPORT
+ - id: mgmtVM
name: mgmtVM
- vm-flavor:
- memory-mb: '1024'
- storage-gb: '10'
- vcpu-count: 1
- - count: '1'
- id: dataVM
- image: hackfest3-mgmt
- interface:
- - internal-connection-point-ref: dataVM-internal
- name: dataVM-eth0
- position: 1
- type: INTERNAL
- virtual-interface:
- type: VIRTIO
- - external-connection-point-ref: vnf-data
- name: dataVM-xe0
- position: 2
- type: EXTERNAL
- virtual-interface:
- type: VIRTIO
- internal-connection-point:
- - id: dataVM-internal
- name: dataVM-internal
- short-name: dataVM-internal
- type: VPORT
- monitoring-param:
- - id: dataVM_cpu_util
- nfvi-metric: cpu_utilization
+ cloud-init-file: cloud-config.txt
+ sw-image-desc: hackfest3-mgmt
+ virtual-compute-desc: mgmt-compute
+ virtual-storage-desc:
+ - mgmt-storage
+ int-cpd:
+ - id: vnf-mgmt
+ virtual-network-interface-requirement:
+ - name: mgmtVM-eth0
+ position: 1
+ virtual-interface:
+ type: VIRTIO
+ - id: mgmtVM-internal
+ int-virtual-link-desc: internal
+ virtual-network-interface-requirement:
+ - name: mgmtVM-eth1
+ position: 2
+ virtual-interface:
+ type: VIRTIO
+ - id: dataVM
name: dataVM
- vm-flavor:
- memory-mb: '1024'
- storage-gb: '10'
- vcpu-count: 1
- version: '1.0'
+ sw-image-desc: hackfest3-mgmt
+ virtual-compute-desc: data-compute
+ virtual-storage-desc:
+ - data-storage
+ int-cpd:
+ - id: dataVM-internal
+ int-virtual-link-desc: internal
+ virtual-network-interface-requirement:
+ - name: dataVM-eth1
+ position: 1
+ virtual-interface:
+ type: VIRTIO
+ - id: vnf-data
+ virtual-network-interface-requirement:
+ - name: dataVM-eth0
+ position: 2
+ virtual-interface:
+ type: VIRTIO
+ monitoring-parameter:
+ - id: dataVM_cpu_util
+ name: dataVM_cpu_util
+ performance-metric: cpu_utilization
+
+ int-virtual-link-desc:
+ - id: internal
+
+ ext-cpd:
+ - id: vnf-mgmt-ext
+ int-cpd: # Connection to int-cpd
+ vdu-id: mgmtVM
+ cpd: vnf-mgmt
+ - id: vnf-data-ext
+ int-cpd: # Connection to int-cpd
+ vdu-id: dataVM
+ cpd: vnf-data
+
+ df:
+ - id: hackfest_default
+ vnf-configuration-id: vnf-configuration-example
+ vdu-profile:
+ - id: mgmtVM
+ min-number-of-instances: 1
+ - id: dataVM
+ min-number-of-instances: 1
+ max-number-of-instances: 10
+ vdu-configuration-id: vdu-configuration-example
+ instantiation-level:
+ - id: default
+ vdu-level:
+ - vdu-id: mgmtVM
+ number-of-instances: 1
+ - vdu-id: dataVM
+ number-of-instances: 1
+ scaling-aspect:
+ - id: scale_dataVM
+ name: scale_dataVM
+ max-scale-level: 10
+ aspect-delta-details:
+ deltas:
+ - id: delta1
+ vdu-delta:
+ - id: vdudelta1
+ number-of-instances: 1
+ scaling-policy:
+ - name: auto_cpu_util_above_threshold
+ scaling-type: automatic
+ enabled: true
+ threshold-time: 0
+ cooldown-time: 60
+ scaling-criteria:
+ - name: cpu_util_above_threshold
+ scale-in-relational-operation: LE
+ scale-in-threshold: '15.0000000000'
+ scale-out-relational-operation: GE
+ scale-out-threshold: '60.0000000000'
+ vnf-monitoring-param-ref: dataVM_cpu_util
+ scaling-config-action:
+ - trigger: post-scale-out
+ vnf-config-primitive-name-ref: touch
+ - trigger: pre-scale-in
+ vnf-config-primitive-name-ref: touch
+
vnf-configuration:
- config-primitive:
- - name: touch
- parameter:
- - data-type: STRING
- default-value: <touch_filename2>
- name: filename
+ - id: vnf-configuration-example
initial-config-primitive:
- - name: config
+ - seq: "1"
+ name: config
parameter:
- - name: ssh-hostname
+ - name: ssh-hostname
value: <rw_mgmt_ip>
- - name: ssh-username
+ - name: ssh-username
value: ubuntu
- - name: ssh-password
+ - name: ssh-password
value: osm4u
- seq: '1'
- - name: touch
+ - seq: "2"
+ name: touch
parameter:
- - name: filename
+ - name: filename
value: <touch_filename>
- seq: '2'
+ config-primitive:
+ - name: touch
+ parameter:
+ - data-type: STRING
+ default-value: <touch_filename2>
+ name: filename
juju:
- charm: simple
+ charm: simple
"""
db_nsds_text = """
usageState: NOT_IN_USE
userDefinedData: {}
_id: 8c2f8b95-bb1b-47ee-8001-36dc090678da
- constituent-vnfd:
- - member-vnf-index: '1'
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index: '2'
- vnfd-id-ref: hackfest3charmed-vnf
- description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and mgmtnet
- VLs
id: hackfest3charmed-ns
- logo: osm.png
name: hackfest3charmed-ns
- short-name: hackfest3charmed-ns
+ description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and mgmtnet VLs
+ designer: OSM
version: '1.0'
- vld:
- - id: mgmt
+
+ vnfd-id:
+ - hackfest3charmed-vnf
+
+ virtual-link-desc:
+ - id: mgmt
mgmt-network: true
- name: mgmt
- short-name: mgmt
- type: ELAN
- vim-network-name: mgmt
- vnfd-connection-point-ref:
- - member-vnf-index-ref: '1'
- vnfd-connection-point-ref: vnf-mgmt
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index-ref: '2'
- vnfd-connection-point-ref: vnf-mgmt
- vnfd-id-ref: hackfest3charmed-vnf
- - id: datanet
- name: datanet
- short-name: datanet
- type: ELAN
- vnfd-connection-point-ref:
- - member-vnf-index-ref: '1'
- vnfd-connection-point-ref: vnf-data
- vnfd-id-ref: hackfest3charmed-vnf
- - member-vnf-index-ref: '2'
- vnfd-connection-point-ref: vnf-data
- vnfd-id-ref: hackfest3charmed-vnf
+ - id: datanet
+ mgmt-network: false
+
+ df:
+ - id: hackfest_charmed_DF
+ vnf-profile:
+ - id: hackfest_vnf1 # member-vnf-index-ref: 1
+ vnfd-id: hackfest3charmed-vnf
+ virtual-link-connectivity:
+ - virtual-link-profile-id: mgmt
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf1
+ constituent-cpd-id: vnf-mgmt-ext
+ - virtual-link-profile-id: datanet
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf1
+ constituent-cpd-id: vnf-data-ext
+ - id: hackfest_vnf2 # member-vnf-index-ref: 2
+ vnfd-id: hackfest3charmed-vnf
+ virtual-link-connectivity:
+ - virtual-link-profile-id: mgmt
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf2
+ constituent-cpd-id: vnf-mgmt-ext
+ - virtual-link-profile-id: datanet
+ constituent-cpd-id:
+ - constituent-base-element-id: hackfest_vnf2
+ constituent-cpd-id: vnf-data-ext
"""
response = yaml.load(empty, Loader=yaml.Loader)
mock_res.get(endpoint, payload=response)
- def test_get_vnf_metric_list(self):
- with self.subTest("Test case1 failed in test_get_vnf_metric_list"):
- metric_list = self.pmjobs_topic._get_vnf_metric_list(self.nsr_id)
- self.assertCountEqual(metric_list, self.metric_check_list,
- "VNF metric list is not correctly fetched")
- with self.subTest("Test case2 failed in test_get_vnf_metric_list"):
- wrong_ns_id = "88d90b0c-faff-4bbc-cccc-aaaaaaaaaaaa"
- with self.assertRaises(EngineException, msg="ns not found") as e:
- self.pmjobs_topic._get_vnf_metric_list(wrong_ns_id)
- self.assertEqual(e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code")
- self.assertIn("NS not found with id {}".format(wrong_ns_id),
- str(e.exception), "Wrong exception text")
-
async def test_prom_metric_request(self):
with self.subTest("Test case1 failed in test_prom"):
prom_response = yaml.load(prom_res, Loader=yaml.Loader)
with aioresponses() as mock_res:
self.set_get_mock_res(mock_res, self.nsr_id, self.metric_check_list)
result = self.pmjobs_topic.show(self.session, self.nsr_id)
- self.assertEqual(len(result['entries']), 3, "Number of metrics returned")
+ self.assertEqual(len(result['entries']), 1, "Number of metrics returned")
self.assertCountEqual(result, show_response, "Response is valid")
with self.subTest("Test case2 failed in test_show"):
wrong_ns_id = "88d90b0c-faff-4bbc-cccc-aaaaaaaaaaaa"
--- /dev/null
+# -*- coding: utf-8 -*-
+
+# Copyright 2020 Whitestack, LLC
+# *************************************************************
+#
+# This file is part of OSM NBI module
+# All Rights Reserved to Whitestack, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact: fbravo@whitestack.com or agarcia@whitestack.com
+##
+
+
+def find_in_list(the_list, condition_lambda):
+ for item in the_list:
+ if condition_lambda(item):
+ return item
+ else:
+ return None
+
+
+def find_index_in_list(the_list, condition_lambda):
+ for index, item in enumerate(the_list):
+ if condition_lambda(item):
+ return index
+ else:
+ return -1
python-keystoneclient
requests
git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common
-git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im
+git+https://osm.etsi.org/gerrit/osm/IM.git@sol006#egg=osm-im
aiohttp>=2.3.10,<=3.6.2
'osm-common @ git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common',
'jsonschema>=3.2.0',
'PyYAML',
- 'osm-im @ git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im',
+ 'osm-im @ git+https://osm.etsi.org/gerrit/osm/IM.git@sol006#egg=osm-im',
'python-keystoneclient',
'requests',
'aiohttp>=2.3.10,<=3.6.2',
# limitations under the License.
[tox]
-envlist = cover, flake8, unittest
+envlist = cover, flake8
[testenv]
usedevelop = True