Minor updates to Validate cross references in descriptors
[osm/NBI.git] / osm_nbi / descriptor_topics.py
index b59b4f8..be34d5a 100644 (file)
@@ -8,7 +8,7 @@ from hashlib import md5
 from osm_common.dbbase import DbException, deep_update_rfc7396
 from http import HTTPStatus
 from validation import ValidationError, pdu_new_schema, pdu_edit_schema
-from base_topic import BaseTopic, EngineException
+from base_topic import BaseTopic, EngineException, get_iterable
 
 __author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
 
@@ -282,17 +282,20 @@ class DescriptorTopic(BaseTopic):
         """
         Return the file content of a vnfd or nsd
         :param session: contains the used login username and working project
-        :param _id: Identity of the vnfd, ndsd
+        :param _id: Identity of the vnfd, nsd
         :param path: artifact path or "$DESCRIPTOR" or None
         :param accept_header: Content of Accept header. Must contain applition/zip or/and text/plain
-        :return: opened file or raises an exception
+        :return: opened file plus Accept format or raises an exception
         """
         accept_text = accept_zip = False
         if accept_header:
             if 'text/plain' in accept_header or '*/*' in accept_header:
                 accept_text = True
             if 'application/zip' in accept_header or '*/*' in accept_header:
-                accept_zip = True
+                accept_zip = 'application/zip'
+            elif 'application/gzip' in accept_header:
+                accept_zip = 'application/gzip'
+
         if not accept_text and not accept_zip:
             raise EngineException("provide request header 'Accept' with 'application/zip' or 'text/plain'",
                                   http_code=HTTPStatus.NOT_ACCEPTABLE)
@@ -330,7 +333,7 @@ class DescriptorTopic(BaseTopic):
                 # TODO generate zipfile if not present
                 raise EngineException("Only allowed 'text/plain' Accept header for this descriptor. To be solved in "
                                       "future versions", http_code=HTTPStatus.NOT_ACCEPTABLE)
-            return self.fs.file_open((storage['folder'], storage['zipfile']), "rb"), "application/zip"
+            return self.fs.file_open((storage['folder'], storage['zipfile']), "rb"), accept_zip
 
 
 class VnfdTopic(DescriptorTopic):
@@ -385,6 +388,138 @@ class VnfdTopic(DescriptorTopic):
 
     def _validate_input_new(self, indata, force=False):
         # TODO validate with pyangbind, serialize
+
+        # 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"]),
+                                      http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
+        for vdu in get_iterable(indata.get("vdu")):
+            for interface in get_iterable(vdu.get("interface")):
+                if 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"):
+                    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"]),
+                                              http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+        for ivld in get_iterable(indata.get("internal-vld")):
+            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"]),
+                        http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+        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
+                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"]),
+                                          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"]),
+                                          http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
+
+        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"]),
+                                              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)
         return indata
 
     def _validate_input_edit(self, indata, force=False):