From cc4fa321dc9addf090ac889ad8c9a8297f84be6a Mon Sep 17 00:00:00 2001 From: hongyuzhao Date: Wed, 21 Aug 2019 11:50:28 +0800 Subject: [PATCH] Add vnfd validity check Change-Id: I9fbdc1c8be274441abccef7f8ca879228037a8db Issue-ID: VFC-1490 Signed-off-by: hongyuzhao --- lcm/lcm/nf/biz/instantiate_vnf.py | 2 + lcm/lcm/pub/verifyvnfd/const.py | 305 +++++++++++++++++++++++++++++++++++ lcm/lcm/pub/verifyvnfd/tests.py | 15 +- lcm/lcm/pub/verifyvnfd/verifyvnfd.py | 35 +++- 4 files changed, 348 insertions(+), 9 deletions(-) diff --git a/lcm/lcm/nf/biz/instantiate_vnf.py b/lcm/lcm/nf/biz/instantiate_vnf.py index 13b29ead..788e582c 100644 --- a/lcm/lcm/nf/biz/instantiate_vnf.py +++ b/lcm/lcm/nf/biz/instantiate_vnf.py @@ -35,6 +35,7 @@ from lcm.nf.const import OPERATION_STATE_TYPE from lcm.nf.const import SUB_OPERATION_TASK from lcm.nf.biz import common from .operate_vnf_lcm_op_occ import VnfLcmOpOcc +from lcm.pub.verifyvnfd import verifyvnfd logger = logging.getLogger(__name__) @@ -122,6 +123,7 @@ class InstantiateVnf(Thread): vnf_package = query_vnfpackage_by_id(self.vnfd_id) pkg_info = ignore_case_get(vnf_package, "packageInfo") self.vnfd_info = json.loads(ignore_case_get(pkg_info, "vnfdModel")) + verifyvnfd.verify(self.vnfd_info) self.update_cps() metadata = ignore_case_get(self.vnfd_info, "metadata") diff --git a/lcm/lcm/pub/verifyvnfd/const.py b/lcm/lcm/pub/verifyvnfd/const.py index 6869dd85..a5a3516f 100644 --- a/lcm/lcm/pub/verifyvnfd/const.py +++ b/lcm/lcm/pub/verifyvnfd/const.py @@ -824,3 +824,308 @@ vnfd_model3 = { "template_author": "ZTE" } } + +vnfd_model_miss_required = { + "volume_storages": [ + { + "volume_storage_id": "test", + "properties": { + "location_info": { + "vimid": "vim_1", + "tenant": "chinamobile", + "availability_zone": "test", + }, + "volume_name": "test", + "custom_volume_type": "test", + "size_of_storage": "\"10 GB\"", + }, + "image_file": "test", + }, + ], + "vnf": { + "type": "tosca.nodes.nfv.VNF", + "requirements": { + "virtual_link": [ + "ext_cp", + "virtual_link" + ] + }, + "properties": { + "descriptor_id": "b1bb0ce7-1234-4fa7-95ed-4840d70a1179", + "flavour_description": "simple", + "descriptor_verison": "1.0", + "software_version": "1.0.0", + "template_name": "test", + "vnfm_info": [ + "vnfm" + ], + "descriptor_version": "1.0.0", + "provider": "zte", + "flavour_id": "simple", + "product_name": "test" + }, + "capabilities": { + + }, + "metadata": { + "template_name": "test", + "template_version": "1.0", + "template_author": "ZTE" + } + }, + "vdus": [ + { + "description": "", + "virtual_storages": [ + { + "virtual_storage_id": "test", + "type_of_storage": "ephemeral", + "size_of_storage": "10 GB", + } + ], + "volume_storages": [ + { + "volume_storage_id": "test", + } + ], + "vdu_id": "sunshine", + "artifacts": [ + { + "artifact_name": "sw_image", + "type": "tosca.artifacts.nfv.SwImage", + "file": "sss.vmdk" + } + ], + "dependencies": [ + + ], + "virtual_compute": { + "virtual_cpu": { + "num_virtual_cpu": 2 + }, + "virtual_memory": { + "virtual_mem_size": "4096 MB" + }, + }, + "vls": [ + + ], + "cps": [ + "ext_cp" + ], + "type": "tosca.nodes.nfv.Vdu.Compute", + "properties": { + "vdu_profile": { + "max_number_of_instances": 3, + "min_number_of_instances": 1 + }, + "name": "sunshine1234", + "sw_image_data": { + "operating_system": "linux", + "name": "ubuntu", + "checksum": { + "hash": "d0e7828293355a07c2dccaaa765c80b507e60e6167067c950dc2e6b0da0dbd34", + "algorithm": "SHA-256" + }, + "min_ram": "2 GB", + "disk_format": "qcow2", + "version": 16.04, + "container_format": "bare", + "min_disk": "2 GB", + "size": "2 GB" + }, + "description": "vdu test", + "location_info": { + "vimid": "", + "tenant": "", + "availability_zone": "", + "vnfId": "", + "vnfName": "", + "cloudOwner": "", + "cloudRegionId": "", + "vduInfo": [ + { + "vduName": "sunshine1234", + "flavorId": "12345", + "directive": "" + } + ] + } + } + } + ], + "description": "test", + "inputs": { + + }, + "graph": { + "sunshine": [ + "ext_cp" + ], + "ext_cp": [ + + ] + }, + "basepath": "/tmp/tmpil6wVG", + "vnf_exposed": { + "external_cps": [ + { + "key_name": "virtual_link", + "cpd_id": "ext_cp" + } + ], + "forward_cps": [ + + ] + }, + "policies": [ + { + "type": "tosca.policies.nfv.InstantiationLevels", + "targets": "", + "properties": { + "default_level": "instantiation_level_1", + "levels": { + "instantiation_level_1": { + "scale_info": { + "sunshine_aspect": { + "scale_level": 0 + } + }, + "description": "vnf test instantiation_level_1" + }, + "instantiation_level_2": { + "scale_info": { + "sunshine_aspect": { + "scale_level": 1 + } + }, + "description": "vnf test instantiation_level_2" + }, + "instantiation_level_3": { + "scale_info": { + "sunshine_aspect": { + "scale_level": 2 + } + }, + "description": "vnf test instantiation_level_3" + } + } + } + }, + { + "type": "tosca.policies.nfv.VduInstantiationLevels", + "targets": [ + "sunshine" + ], + "properties": { + "levels": { + "instantiation_level_1": { + "number_of_instances": 1 + }, + "instantiation_level_2": { + "number_of_instances": 2 + }, + "instantiation_level_3": { + "number_of_instances": 3 + } + } + } + }, + { + "type": "tosca.policies.nfv.ScalingAspects", + "targets": "", + "properties": { + "aspects": { + "sunshine_aspect": { + "max_scale_level": 2, + "description": "sunshine aspect", + "name": "sunshine_aspect", + "step_deltas": [ + "sunshine_delta" + ] + } + } + } + }, + { + "type": "tosca.policies.nfv.VduInitialDelta", + "targets": [ + "sunshine" + ], + "properties": { + "initial_delta": { + "number_of_instances": 1 + } + } + }, + { + "type": "tosca.policies.nfv.VduScalingAspectDeltas", + "targets": [ + "sunshine" + ], + "properties": { + "deltas": { + "sunshine_delta": { + "number_of_instances": 1 + } + }, + "aspect": "sunshine_aspect" + } + } + ], + "vls": [ + { + # "vl_id": "test", //required + "properties": { + "location_info": { + "vimid": "test", + "tenant": "chinamobile", + }, + "vl_profile": { + # "networkName": "test", //required + "networkType": "test", + "physicalNetwork": "test", + "vlanTransparent": "test", + "segmentationId": "1", + "cidr": "test", + "dhcpEnabled": "test", + "gatewayIp": "test", + "startIp": "test", + "endIp": "test", + }, + # "connectivity_type": { + # "layer_protocol": "ipv4", + # }, + "dns_nameservers": "test", + "host_routes": "test", + }, + "route_external": "test", + } + ], + "cps": [ + { + "vl_id": "", + "description": "", + "vdu_id": "sunshine", + "properties": { + "trunk_mode": "false", + "protocol_data": [{ + "address_data": { + "address_type": "ip_address", + # "l3_address_data": { + # "floating_ip_activated": False, + # "ip_address_assignment": False + # } + } + }] + }, + # "cp_id": "ext_cp", //required + "cpd_id": "ext_cp" + } + ], + "metadata": { + "template_name": "test", + "template_version": "1.0", + "template_author": "ZTE" + } +} diff --git a/lcm/lcm/pub/verifyvnfd/tests.py b/lcm/lcm/pub/verifyvnfd/tests.py index 86e2d045..bc0e974b 100644 --- a/lcm/lcm/pub/verifyvnfd/tests.py +++ b/lcm/lcm/pub/verifyvnfd/tests.py @@ -13,8 +13,9 @@ # limitations under the License. import unittest -from . import verifyvnfd +from lcm.pub.verifyvnfd import verifyvnfd from . import const +from lcm.pub.exceptions import NFLCMException class VerifyVnfdTest(unittest.TestCase): @@ -26,12 +27,18 @@ class VerifyVnfdTest(unittest.TestCase): def test_vnfd_verfify_success1(self): ret = verifyvnfd.verify(const.vnfd_model1) - self.assertEqual(ret, []) + self.assertEqual(ret, True) def test_vnfd_verfify_success2(self): ret = verifyvnfd.verify(const.vnfd_model2) - self.assertEqual(ret, []) + self.assertEqual(ret, True) def test_vnfd_verfify_success3(self): ret = verifyvnfd.verify(const.vnfd_model3) - self.assertEqual(ret, []) + self.assertEqual(ret, True) + + def test_vnfd_verfify_fail_for_missing_required(self): + try: + verifyvnfd.verify(const.vnfd_model_miss_required) + except NFLCMException as e: + self.assertNotEqual(e.args[0], "") diff --git a/lcm/lcm/pub/verifyvnfd/verifyvnfd.py b/lcm/lcm/pub/verifyvnfd/verifyvnfd.py index b4ed0408..6fa5ac2b 100644 --- a/lcm/lcm/pub/verifyvnfd/verifyvnfd.py +++ b/lcm/lcm/pub/verifyvnfd/verifyvnfd.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import re import os +import six import logging import jsonschema from lcm.pub.exceptions import NFLCMException @@ -21,6 +23,29 @@ from lcm.pub.exceptions import NFLCMException logger = logging.getLogger(__name__) +def _format_validation_error(error): + """ + :param error: validation error to format + :type error: jsonchema.exceptions.ValidationError + :returns: string representation of the validation error + :rtype: str + """ + match = re.search("(.+) is a required property", error.message) + if match: + message = 'Error: missing required property {}.'.format( + match.group(1)) + else: + message = 'Error: {}\n'.format(error.message) + if len(error.absolute_path) > 0: + message += 'Path: {}\n'.format( + '.'.join( + [six.text_type(path) + for path in error.absolute_path])) + message += 'Value: {}'.format(json.dumps(error.instance)) + + return message + + def verify(new_vnfd): errors_found = [] vnfd_schema_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "vnf_vnfd_schema.json") @@ -28,8 +53,8 @@ def verify(new_vnfd): vnfd_schema = json.load(fvnfd_schema) vnfd_validator = jsonschema.validators.Draft4Validator(schema=vnfd_schema) for error in vnfd_validator.iter_errors(new_vnfd): - logger.error("vnfd verify fail:%s" % error) - errors_found.append(error) - if len(errors_found) > 0: - raise NFLCMException(errors_found) - return errors_found + logger.error("vnfd verify fail,%s" % _format_validation_error(error)) + errors_found.append(_format_validation_error(error)) + if len(errors_found) > 0: + raise NFLCMException(errors_found) + return True -- 2.16.6