from http import HTTPStatus
from validation import ValidationError, pdu_new_schema, pdu_edit_schema
from 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
+from pyangbind.lib.serialise import pybindJSONDecoder
+import pyangbind.lib.pybindJSON as pybindJSON
__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
BaseTopic.__init__(self, db, fs, msg)
def check_conflict_on_edit(self, session, final_content, edit_content, _id, force=False):
- # check that this id is not present
- _filter = {"id": final_content["id"]}
- if _id:
+ # 1. validate again with pyangbind
+ # 1.1. remove internal keys
+ internal_keys = {}
+ for k in ("_id", "_admin"):
+ if k in final_content:
+ internal_keys[k] = final_content.pop(k)
+ serialized = self._validate_input_new(final_content, force)
+ # 1.2. modify final_content with a serialized version
+ final_content.clear()
+ final_content.update(serialized)
+ # 1.3. restore internal keys
+ for k, v in internal_keys.items():
+ final_content[k] = v
+
+ # 2. check that this id is not present
+ if "id" in edit_content:
+ _filter = self._get_project_filter(session, write=False, show_all=False)
+ _filter["id"] = final_content["id"]
_filter["_id.neq"] = _id
-
- _filter.update(self._get_project_filter(session, write=False, show_all=False))
- if self.db.get_one(self.topic, _filter, fail_on_empty=False):
- raise EngineException("{} with id '{}' already exists for this project".format(self.topic[:-1],
- final_content["id"]),
- HTTPStatus.CONFLICT)
- # TODO validate with pyangbind. Load and dumps to convert data types
+ if self.db.get_one(self.topic, _filter, fail_on_empty=False):
+ raise EngineException("{} with id '{}' already exists for this project".format(self.topic[:-1],
+ final_content["id"]),
+ HTTPStatus.CONFLICT)
@staticmethod
def format_on_new(content, project_id=None, make_public=False):
"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")
+ 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
+
+ except Exception as e:
+ raise EngineException("Error in pyangbind validation: {}".format(str(e)),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
class VnfdTopic(DescriptorTopic):
topic = "vnfds"
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 only one element")
+ 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]
return clean_indata
def check_conflict_on_del(self, session, _id, force=False):
raise EngineException("There is soame NSD that depends on this VNFD", http_code=HTTPStatus.CONFLICT)
def _validate_input_new(self, indata, force=False):
- # TODO validate with pyangbind, serialize
-
+ indata = self.pyangbind_validation("vnfds", indata, force)
# Cross references validation in the descriptor
- if not indata.get("mgmt-interface"):
- raise EngineException("'mgmt-interface' 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"]),
+ if indata.get("vdu"):
+ if not indata.get("mgmt-interface"):
+ raise EngineException("'mgmt-interface' 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"]),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
for vdu in get_iterable(indata.get("vdu")):
for interface in get_iterable(vdu.get("interface")):
"vnf-configuration:config-primitive:name"
.format(sgd["name"], sca["vnf-config-primitive-name-ref"]),
http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+ # TODO validata that if contains cloud-init-file or charms, have artifacts _admin.storage."pkg-dir" is not none
return indata
def _validate_input_edit(self, indata, force=False):
- # TODO validate with pyangbind, serialize
+ # not needed to validate with pyangbind becuase it will be validated at check_conflict_on_edit
return indata
clean_indata = clean_indata['nsd-catalog']
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 only one element")
+ 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, force=False):
- # transform constituent-vnfd:member-vnf-index to string
- if indata.get("constituent-vnfd"):
- for constituent_vnfd in indata["constituent-vnfd"]:
- if "member-vnf-index" in constituent_vnfd:
- constituent_vnfd["member-vnf-index"] = str(constituent_vnfd["member-vnf-index"])
-
- # TODO validate with pyangbind, serialize
+ indata = self.pyangbind_validation("nsds", indata, force)
+ # TODO validata that if contains cloud-init-file or charms, have artifacts _admin.storage."pkg-dir" is not none
return indata
def _validate_input_edit(self, indata, force=False):
- # TODO validate with pyangbind, serialize
+ # not needed to validate with pyangbind becuase it will be validated at check_conflict_on_edit
return indata
def _check_descriptor_dependencies(self, session, descriptor):
def check_conflict_on_edit(self, session, final_content, edit_content, _id, force=False):
super().check_conflict_on_edit(session, final_content, edit_content, _id, force=force)
- self._check_descriptor_dependencies(session, final_content)
+ if not force:
+ self._check_descriptor_dependencies(session, final_content)
def check_conflict_on_del(self, session, _id, force=False):
"""