# 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("virtual-link-desc")):
self.validate_vld_mgmt_network_with_virtual_link_protocol_data(vld, indata)
+ for fg in get_iterable(indata.get("vnffgd")):
+ self.validate_vnffgd_data(fg, indata)
self.validate_vnf_profiles_vnfd_id(indata)
http_code=HTTPStatus.UNPROCESSABLE_ENTITY,
)
+ @staticmethod
+ def validate_vnffgd_data(fg, indata):
+ position_list = []
+ all_vnf_ids = set(get_iterable(fg.get("vnf-profile-id")))
+ for fgposition in get_iterable(fg.get("nfp-position-element")):
+ position_list.append(fgposition["id"])
+
+ for nfpd in get_iterable(fg.get("nfpd")):
+ nfp_position = []
+ for position in get_iterable(nfpd.get("position-desc-id")):
+ nfp_position = position.get("nfp-position-element-id")
+ if position == "nfp-position-element-id":
+ nfp_position = position.get("nfp-position-element-id")
+ if nfp_position[0] not in position_list:
+ raise EngineException(
+ "Error at vnffgd nfpd[id='{}']:nfp-position-element-id='{}' "
+ "does not match any nfp-position-element".format(
+ nfpd["id"], nfp_position[0]
+ ),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY,
+ )
+
+ for cp in get_iterable(position.get("cp-profile-id")):
+ for cpe in get_iterable(cp.get("constituent-profile-elements")):
+ constituent_base_element_id = cpe.get(
+ "constituent-base-element-id"
+ )
+ if (
+ constituent_base_element_id
+ and constituent_base_element_id not in all_vnf_ids
+ ):
+ raise EngineException(
+ "Error at vnffgd constituent_profile[id='{}']:vnfd-id='{}' "
+ "does not match any constituent-base-element-id".format(
+ cpe["id"], constituent_base_element_id
+ ),
+ http_code=HTTPStatus.UNPROCESSABLE_ENTITY,
+ )
+
@staticmethod
def validate_vnf_profiles_vnfd_id(indata):
all_vnfd_ids = set(get_iterable(indata.get("vnfd-id")))
"image": [],
"affinity-or-anti-affinity-group": [],
"shared-volumes": [],
+ "vnffgd": [],
}
if "revision" in nsd["_admin"]:
nsr_descriptor["revision"] = nsd["_admin"]["revision"]
)
vld["name"] = vld["id"]
nsr_descriptor["vld"] = nsr_vld
+ if nsd.get("vnffgd"):
+ vnffgd = nsd.get("vnffgd")
+ for vnffg in vnffgd:
+ info = {}
+ for k, v in vnffg.items():
+ if k == "id":
+ info.update({k: v})
+ if k == "nfpd":
+ info.update({k: v})
+ nsr_descriptor["vnffgd"].append(info)
+
return nsr_descriptor
def _get_affinity_or_anti_affinity_group_data_from_vnfd(
db_nsds_text,
vnfd_exploit_text,
vnfd_exploit_fixed_text,
+ db_sfc_nsds_text,
)
from osm_nbi.descriptor_topics import VnfdTopic, NsdTopic
from osm_nbi.engine import EngineException
"Wrong exception text",
)
+ def test_validate_vnffgd_descriptor_on_valid_descriptor(self):
+ indata = yaml.safe_load(db_sfc_nsds_text)[0]
+ vnffgd = indata.get("vnffgd")
+ fg = vnffgd[0]
+ self.topic.validate_vnffgd_data(fg, indata)
+
+ def test_validate_vnffgd_descriptor_not_matching_nfp_position_element(self):
+ indata = yaml.safe_load(db_sfc_nsds_text)[0]
+ vnffgd = indata.get("vnffgd")
+ fg = vnffgd[0]
+ nfpd = fg.get("nfpd")[0]
+ with self.assertRaises(EngineException) as e:
+ fg.update({"nfp-position-element": [{"id": "test1"}]})
+ self.topic.validate_vnffgd_data(fg, indata)
+ self.assertEqual(
+ e.exception.http_code,
+ HTTPStatus.UNPROCESSABLE_ENTITY,
+ "Wrong HTTP status code",
+ )
+ self.assertIn(
+ norm(
+ "Error at vnffgd nfpd[id='{}']:nfp-position-element-id='{}' "
+ "does not match any nfp-position-element".format(nfpd["id"], "test")
+ ),
+ norm(str(e.exception)),
+ "Wrong exception text",
+ )
+
+ def test_validate_vnffgd_descriptor_not_matching_constituent_base_element_id(
+ self,
+ ):
+ indata = yaml.safe_load(db_sfc_nsds_text)[0]
+ vnffgd = indata.get("vnffgd")
+ fg = vnffgd[0]
+ fg["nfpd"][0]["position-desc-id"][0]["cp-profile-id"][0][
+ "constituent-profile-elements"
+ ][0]["constituent-base-element-id"] = "error_vnf"
+ with self.assertRaises(EngineException) as e:
+ self.topic.validate_vnffgd_data(fg, indata)
+ self.assertEqual(
+ e.exception.http_code,
+ HTTPStatus.UNPROCESSABLE_ENTITY,
+ "Wrong HTTP status code",
+ )
+ self.assertIn(
+ norm(
+ "Error at vnffgd constituent_profile[id='{}']:vnfd-id='{}' "
+ "does not match any constituent-base-element-id".format(
+ "vnf1", "error_vnf"
+ )
+ ),
+ norm(str(e.exception)),
+ "Wrong exception text",
+ )
+
if __name__ == "__main__":
unittest.main()
- constituent-base-element-id: hackfest_vnf2
constituent-cpd-id: vnf-data-ext
"""
+
+db_sfc_nsds_text = """
+- _admin:
+ userDefinedData: {}
+ revision: 1
+ created: 1683713524.2696395
+ modified: 1683713524.3553684
+ projects_read:
+ - 93601899-b310-4a56-a765-91539d5f675d
+ projects_write:
+ - 93601899-b310-4a56-a765-91539d5f675d
+ onboardingState: ONBOARDED
+ operationalState: ENABLED
+ usageState: NOT_IN_USE
+ storage:
+ fs: mongo
+ path: /app/storage/
+ folder: '2eb45633-03e3-4909-a87d-a564f5943948:1'
+ pkg-dir: cirros_vnffg_ns
+ descriptor: cirros_vnffg_ns/cirros_vnffg_nsd.yaml
+ zipfile: package.tar.gz
+ _id: 2eb45633-03e3-4909-a87d-a564f5943948
+ id: cirros_vnffg-ns
+ designer: OSM
+ version: '1.0'
+ name: cirros_vnffg-ns
+
+ vnfd-id:
+ - cirros_vnffg-vnf
+
+ virtual-link-desc:
+ - id: osm-ext
+ mgmt-network: true
+
+ vnffgd:
+ - id: vnffg1
+ vnf-profile-id:
+ - Mid-vnf1
+ nfpd:
+ - id: forwardingpath1
+ position-desc-id:
+ - id: position1
+ cp-profile-id:
+ - id: cpprofile2
+ constituent-profile-elements:
+ - id: vnf1
+ order: 0
+ constituent-base-element-id: Mid-vnf1
+ ingress-constituent-cpd-id: vnf-cp0-ext
+ egress-constituent-cpd-id: vnf-cp0-ext
+ match-attributes:
+ - id: rule1_80
+ ip-proto: 6
+ source-ip-address: 20.20.1.2
+ destination-ip-address: 20.20.3.5
+ source-port: 0
+ destination-port: 80
+ nfp-position-element-id:
+ - test
+ nfp-position-element:
+ - id: test
+
+ df:
+ - id: default-df
+ vnf-profile:
+ - id: '1'
+ virtual-link-connectivity:
+ - constituent-cpd-id:
+ - constituent-base-element-id: '1'
+ constituent-cpd-id: eth0-ext
+ virtual-link-profile-id: osm-ext
+ vnfd-id: cirros_vnffg-vnf
+ description: Simple NS example with vnffgd
+"""