diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..db10de72d --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,271 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Simple deployment flavour for Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + inputs: + id: + type: string + vendor: + type: string + version: + type: version + descriptor_id: + type: string + descriptor_version: + type: string + provider: + type: string + product_name: + type: string + software_version: + type: string + vnfm_info: + type: list + entry_schema: + type: string + flavour_id: + type: string + flavour_description: + type: string + + substitution_mappings: + node_type: company.provider.VNF + properties: + flavour_id: simple + requirements: + virtual_link_external: [ CP1, virtual_link ] + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_description: A simple flavour + interfaces: + Vnflcm: + instantiate: [] + instantiate_start: [] + instantiate_end: + implementation: + primary: vnflcm_noop + dependencies: + - mgmt-drivers-ansible-sample-end + terminate: [] + terminate_start: [] + terminate_end: [] + artifacts: + vnflcm_noop: + description: Management driver plugin + type: tosca.artifacts.Implementation.Python + file: Drivers/vnflcm_noop.py + + mgmt-drivers-ansible-sample-end: + description: Management driver sample + type: tosca.artifacts.Implementation.Yaml + file: ScriptANSIBLE/config_complex_end.yaml + + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + sw_image_data: + name: Software of VDU1 + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 1 GB + size: 1 GB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.5.2-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GB + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU2 + description: VDU2 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GB + requirements: + - virtual_storage: VirtualStorage + + VirtualStorage: + type: tosca.nodes.nfv.Vdu.VirtualBlockStorage + properties: + virtual_block_storage_data: + size_of_storage: 30 GB + rdma_enabled: true + sw_image_data: + name: VrtualStorage + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 2 GB + min_ram: 8192 MB + size: 2 GB + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.5.2-x86_64-disk.img + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + #- virtual_link: # the target node is determined in the NSD + + CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL2 + + CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU2 + - virtual_link: internalVL2 + + internalVL2: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 11.11.0.0/24 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU2_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU2 ] + + - VDU2_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU2 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] + + - VDU2_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 1 + targets: [ VDU2 ] + + - internalVL2_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ internalVL2 ] diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Drivers/vnflcm_noop.py b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Drivers/vnflcm_noop.py new file mode 100644 index 000000000..8fb7842b9 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Drivers/vnflcm_noop.py @@ -0,0 +1,68 @@ +# Copyright (C) 2022 NEC +# All Rights Reserved. +# +# 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. + +from tacker.common import log +from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver + + +class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver): + def get_type(self): + return 'vnflcm_noop' + + def get_name(self): + return 'vnflcm_noop' + + def get_description(self): + return 'Tacker VNFMgmt VnflcmNoop Driver' + + @log.log + def instantiate_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def instantiate_end(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def terminate_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def terminate_end(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def scale_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def scale_end(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def heal_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @log.log + def heal_end(self, context, vnf_instance, + additional_params, **kwargs): + pass diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/ScriptANSIBLE/config_complex_end.yaml b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/ScriptANSIBLE/config_complex_end.yaml new file mode 100644 index 000000000..bf2aa5331 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/ScriptANSIBLE/config_complex_end.yaml @@ -0,0 +1,19 @@ +configurable_properties: + _VAR_user: 'some_user' + _VAR_password: 'password' + _VAR_vdu_password: 'password' + +vdus: + VDU1: + config: + order: 1 + vm_app_config: + type: ansible + instantiation: + - path: _VAR_vnf_package_path/Scripts/complex/instantiation_end.yaml + params: + ansible_password: _VAR_password + order: 0 + username: _VAR_user + password: _VAR_vdu_password + diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Scripts/complex/instantiation_end.yaml b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Scripts/complex/instantiation_end.yaml new file mode 100644 index 000000000..a75ddfe1a --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment/Scripts/complex/instantiation_end.yaml @@ -0,0 +1,10 @@ +# This playbook prints a simple debug message +- name: Echo + hosts: 127.0.0.1 + connection: local + + tasks: + - name: Print debug message + debug: + msg: Complex INSTANTIATION END Hello, world! + diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..d4e5245c9 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,271 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Simple deployment flavour for Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + inputs: + id: + type: string + vendor: + type: string + version: + type: version + descriptor_id: + type: string + descriptor_version: + type: string + provider: + type: string + product_name: + type: string + software_version: + type: string + vnfm_info: + type: list + entry_schema: + type: string + flavour_id: + type: string + flavour_description: + type: string + + substitution_mappings: + node_type: company.provider.VNF + properties: + flavour_id: simple + requirements: + virtual_link_external: [ CP1, virtual_link ] + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_description: A simple flavour + interfaces: + Vnflcm: + instantiate: [] + instantiate_start: [] + instantiate_end: + implementation: + primary: ansible_driver + dependencies: + - mgmt-drivers-ansible-sample-end + terminate: [] + terminate_start: [] + terminate_end: [] + artifacts: + ansible_driver: + description: Management driver plugin + type: tosca.artifacts.Implementation.Python + file: /opt/stack/tacker/tacker/vnfm/mgmt_drivers/ansible/ansible.py + + mgmt-drivers-ansible-sample-end: + description: Management driver sample + type: tosca.artifacts.Implementation.Yaml + file: ScriptANSIBLE/config_complex_end.yaml + + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + sw_image_data: + name: Software of VDU1 + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 1 GB + size: 1 GB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.5.2-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GB + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU2 + description: VDU2 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GB + requirements: + - virtual_storage: VirtualStorage + + VirtualStorage: + type: tosca.nodes.nfv.Vdu.VirtualBlockStorage + properties: + virtual_block_storage_data: + size_of_storage: 30 GB + rdma_enabled: true + sw_image_data: + name: VrtualStorage + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 2 GB + min_ram: 8192 MB + size: 2 GB + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.5.2-x86_64-disk.img + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + #- virtual_link: # the target node is determined in the NSD + + CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL2 + + CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU2 + - virtual_link: internalVL2 + + internalVL2: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 11.11.0.0/24 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU2_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU2 ] + + - VDU2_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU2 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] + + - VDU2_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 1 + targets: [ VDU2 ] + + - internalVL2_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ internalVL2 ] diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/ScriptANSIBLE/config_complex_end.yaml b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/ScriptANSIBLE/config_complex_end.yaml new file mode 100644 index 000000000..bf2aa5331 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/ScriptANSIBLE/config_complex_end.yaml @@ -0,0 +1,19 @@ +configurable_properties: + _VAR_user: 'some_user' + _VAR_password: 'password' + _VAR_vdu_password: 'password' + +vdus: + VDU1: + config: + order: 1 + vm_app_config: + type: ansible + instantiation: + - path: _VAR_vnf_package_path/Scripts/complex/instantiation_end.yaml + params: + ansible_password: _VAR_password + order: 0 + username: _VAR_user + password: _VAR_vdu_password + diff --git a/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/Scripts/complex/instantiation_end.yaml b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/Scripts/complex/instantiation_end.yaml new file mode 100644 index 000000000..a75ddfe1a --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/multi_flavour_deployment_invalid/Scripts/complex/instantiation_end.yaml @@ -0,0 +1,10 @@ +# This playbook prints a simple debug message +- name: Echo + hosts: 127.0.0.1 + connection: local + + tasks: + - name: Print debug message + debug: + msg: Complex INSTANTIATION END Hello, world! + diff --git a/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py b/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py index 337d2e0fd..3abd39f29 100644 --- a/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py +++ b/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py @@ -258,3 +258,88 @@ class MgmtVnfLcmDriverTest(db_base.SqlTestCase): vnf_instance_obj, vnf_dict, instantiate_vnf_req_obj) shutil.rmtree(fake_csar) + + @mock.patch('tacker.vnflcm.utils.get_default_scale_status') + @mock.patch('tacker.vnflcm.utils._make_final_vnf_dict') + @mock.patch.object(VnfLcmDriver, '_init_mgmt_driver_hash') + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(objects.VnfResource, 'create') + @mock.patch.object(objects.VnfPackageVnfd, 'get_by_id') + @mock.patch.object(objects.VnfInstance, "save") + def test_instantiate_multi(self, mock_vnf_instance_save, + mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict, mock_default_status): + mock_init_hash.return_value = { + "vnflcm_noop": "10edbecaa6df7e782c610ef4cc5e57" + "e2b0405869a559e2f4cb40e6b11e367547" + } + vnf_package_vnfd = fakes.return_vnf_package_vnfd() + vnf_package_id = vnf_package_vnfd.package_uuid + mock_vnf_package_vnfd.return_value = vnf_package_vnfd + instantiate_vnf_req_dict = fakes.get_dummy_instantiate_vnf_request() + instantiate_vnf_req_obj = \ + objects.InstantiateVnfRequest.obj_from_primitive( + instantiate_vnf_req_dict, self.context) + vnf_instance_obj = fakes.return_vnf_instance() + mock_default_status.return_value = None + + fake_csar = os.path.join(self.temp_dir, vnf_package_id) + cfg.CONF.set_override('vnf_package_csar_path', self.temp_dir, + group='vnf_package') + test_utils.copy_csar_files(fake_csar, "multi_flavour_deployment") + self._mock_vnf_manager() + driver = vnflcm_driver.VnfLcmDriver() + vnf_dict = { + "vnfd": {"attributes": {}}, "attributes": {}, + "before_error_point": fields.ErrorPoint.VNF_CONFIG_START} + driver.instantiate_vnf(self.context, vnf_instance_obj, vnf_dict, + instantiate_vnf_req_obj) + + self.assertEqual(1, mock_vnf_instance_save.call_count) + self.assertEqual(6, self._vnf_manager.invoke.call_count) + shutil.rmtree(fake_csar) + + @mock.patch('tacker.vnflcm.utils.get_default_scale_status') + @mock.patch('tacker.vnflcm.utils._make_final_vnf_dict') + @mock.patch.object(VnfLcmDriver, '_init_mgmt_driver_hash') + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(objects.VnfResource, 'create') + @mock.patch.object(objects.VnfPackageVnfd, 'get_by_id') + @mock.patch.object(objects.VnfInstance, "save") + def test_instantiate_multi_invalid(self, mock_vnf_instance_save, + mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict, mock_default_status): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + vnf_package_vnfd = fakes.return_vnf_package_vnfd() + vnf_package_id = vnf_package_vnfd.package_uuid + mock_vnf_package_vnfd.return_value = vnf_package_vnfd + instantiate_vnf_req_dict = fakes.get_dummy_instantiate_vnf_request() + instantiate_vnf_req_obj = \ + objects.InstantiateVnfRequest.obj_from_primitive( + instantiate_vnf_req_dict, self.context) + vnf_instance_obj = fakes.return_vnf_instance() + mock_default_status.return_value = None + + fake_csar = os.path.join(self.temp_dir, vnf_package_id) + cfg.CONF.set_override('vnf_package_csar_path', self.temp_dir, + group='vnf_package') + test_utils.copy_csar_files(fake_csar, + "multi_flavour_deployment_invalid") + self._mock_vnf_manager() + driver = vnflcm_driver.VnfLcmDriver() + vnf_dict = { + "vnfd": {"attributes": {}}, "attributes": {}, + "before_error_point": fields.ErrorPoint.VNF_CONFIG_START} + + self.assertRaises(exceptions.MgmtDriverInconsistent, + driver.instantiate_vnf, self.context, + vnf_instance_obj, vnf_dict, + instantiate_vnf_req_obj) + shutil.rmtree(fake_csar) diff --git a/tacker/vnflcm/vnflcm_driver.py b/tacker/vnflcm/vnflcm_driver.py index 591f3e2ee..2448d7809 100644 --- a/tacker/vnflcm/vnflcm_driver.py +++ b/tacker/vnflcm/vnflcm_driver.py @@ -458,15 +458,28 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): return hash_obj.hexdigest() def _check_mgmt_driver(self, artifact_mgmt_driver, artifacts_value, - vnf_package_path): + vnf_package_path, + artifact_mgmt_driver_dependency=None): # check implementation and artifacts exist in cfg.CONF.tacker if artifact_mgmt_driver not in self._mgmt_driver_hash: - LOG.error('The {} specified in the VNFD ' - 'is inconsistent with the MgmtDriver in ' - 'the configuration file.'.format(artifact_mgmt_driver)) + LOG.error('The management driver {} specified in the VNFD ' + 'at vnf package path {} is inconsistent with ' + 'the MgmtDriver in the configuration file {}.' + .format(artifact_mgmt_driver, vnf_package_path, + cfg.CONF.default_config_files)) raise exceptions.MgmtDriverInconsistent( MgmtDriver=artifact_mgmt_driver) + if artifact_mgmt_driver_dependency is not None: + if artifact_mgmt_driver_dependency in self._mgmt_driver_hash: + LOG.error('The management driver dependencies {} specified in ' + 'the VNFD at vnf package path {} is inconsistent ' + ' with the MgmtDriver in the configuration file {}.' + .format(artifact_mgmt_driver, vnf_package_path, + cfg.CONF.default_config_files)) + raise exceptions.MgmtDriverInconsistent( + MgmtDriver=artifact_mgmt_driver_dependency) + # check file content pkg_mgmt_driver_path = os.path.join(vnf_package_path, artifacts_value[artifact_mgmt_driver]['file']) @@ -497,8 +510,25 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): artifact_mgmt_driver = interfaces_vnflcm_value.get( method_name).get('implementation') if artifact_mgmt_driver: - tacker_mgmt_driver = self._check_mgmt_driver( - artifact_mgmt_driver, artifacts_value, vnf_package_path) + # TODO(w-juso): Dependencies are defined List type in OASIS. + # This function handles dependencies as a List type, however + # currently only a single parameter in List can be read. + # If necessary, we need to implement the ability to load + # multiple definitions. + if isinstance(artifact_mgmt_driver, dict): + primary = artifact_mgmt_driver.get('primary') + dependencies = artifact_mgmt_driver.get('dependencies') + + if not isinstance(dependencies, list): + dependencies = [dependencies] + for dependency in dependencies: + tacker_mgmt_driver = self._check_mgmt_driver( + primary, artifacts_value, + vnf_package_path, dependency) + else: + tacker_mgmt_driver = self._check_mgmt_driver( + artifact_mgmt_driver, artifacts_value, + vnf_package_path) return tacker_mgmt_driver