diff --git a/lower-constraints.txt b/lower-constraints.txt index 3bbe109ac..feb673f33 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -94,6 +94,7 @@ pycadf==2.7.0 pycparser==2.18 Pygments==2.2.0 pyinotify==0.9.6 +PyMySQL==0.10.1 PyNaCl==1.2.1 pyOpenSSL==17.5.0 pyparsing==2.2.0 diff --git a/releasenotes/notes/refactor-mgmt-driver-with-sol001-a18c3a174062447a.yaml b/releasenotes/notes/refactor-mgmt-driver-with-sol001-a18c3a174062447a.yaml new file mode 100644 index 000000000..0f3567663 --- /dev/null +++ b/releasenotes/notes/refactor-mgmt-driver-with-sol001-a18c3a174062447a.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Enable VNF vendors to customize configuration methods + for applications via MgmtDriver. These customizations + are specified by "interface" definition in ETSI + NFV-SOL001 v2.6.1. With MgmtDriver, users can execute + preamble and postamble of the base LCM operation. + Customization of LCM itself is not supported by + MgmtDriver. diff --git a/requirements.txt b/requirements.txt index 9bf12990b..0170a3d9d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -50,6 +50,7 @@ kubernetes>=11.0.0 # Apache-2.0 setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=21.0.0 # PSF/ZPL tooz>=1.58.0 # Apache-2.0 PyYAML>=5.1 # MIT +PyMySQL>=0.10.1 # MIT # Glance Store glance-store>=2.4.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index 70c64eaa6..acb74bfe0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,6 +61,7 @@ tacker.tacker.vnfm.drivers = tacker.tacker.mgmt.drivers = noop = tacker.vnfm.mgmt_drivers.noop:VnfMgmtNoop openwrt = tacker.vnfm.mgmt_drivers.openwrt.openwrt:VnfMgmtOpenWRT + vnflcm_noop = tacker.vnfm.mgmt_drivers.vnflcm_noop:VnflcmMgmtNoop tacker.tacker.monitor.drivers = ping = tacker.vnfm.monitor_drivers.ping.ping:VNFMonitorPing http_ping = tacker.vnfm.monitor_drivers.http_ping.http_ping:VNFMonitorHTTPPing @@ -92,6 +93,7 @@ oslo.config.opts = tacker.vnfm.monitor_drivers.ping.ping = tacker.vnfm.monitor_drivers.ping.ping:config_opts tacker.vnfm.monitor_drivers.ceilometer.ceilometer = tacker.vnfm.monitor_drivers.ceilometer.ceilometer:config_opts tacker.vnfm.monitor_drivers.zabbix.zabbix = tacker.vnfm.monitor_drivers.zabbix.zabbix:config_opts + tacker.vnflcm.vnflcm_drivers = tacker.vnflcm.vnflcm_drivers:config_opts tacker.alarm_receiver = tacker.alarm_receiver:config_opts tacker.plugins.fenix = tacker.plugins.fenix:config_opts diff --git a/tacker/common/exceptions.py b/tacker/common/exceptions.py index b938375e5..fa56a1609 100644 --- a/tacker/common/exceptions.py +++ b/tacker/common/exceptions.py @@ -376,3 +376,33 @@ class DBAccessError(TackerException): class SeeOther(TackerException): code = 303 + + +class MgmtDriverHashMatchFailure(TackerException): + message = _('The hash verification of VNF Package MgmtDriver ' + 'and Tacker MgmtDriver does not match.') + + +class MgmtDriverInconsistent(TackerException): + message = _('The %(MgmtDriver)s specified in the VNFD is inconsistent ' + 'with the MgmtDriver in the configuration file.') + + +class MgmtDriverNotFound(TackerException): + message = _('The %(param)s in the additionalParams does not exist.') + + +class MgmtDriverParamInvalid(TackerException): + message = _('The %(param)s in the additionalParams is invalid.') + + +class MgmtDriverRemoteCommandError(TackerException): + message = _('Failed to execute remote command.') + + +class MgmtDriverRemoteCommandTimeOut(TackerException): + message = _('The execution of the remote command timed out.') + + +class MgmtDriverOtherError(TackerException): + message = _('An error occurred in MgmtDriver: %(error_message)s.') diff --git a/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..abc175541 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,269 @@ +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 + - helloworld3_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: + # supporting only 'instantiate', 'terminate', 'modify' + # not supporting LCM script, supporting only default LCM + instantiate: [] + instantiate_start: + implementation: vnflcm_noop + instantiate_end: + implementation: vnflcm_noop + terminate: [] + terminate_start: + implementation: vnflcm_noop + terminate_end: + implementation: vnflcm_noop + artifacts: + vnflcm_noop: + description: Management driver instantiate + type: tosca.artifacts.Implementation.Python + file: Drivers/vnflcm_noop.py + + 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.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + 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.4.0-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.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + 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.4.0-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/refactor_mgmt_driver1/Definitions/helloworld3_types.yaml b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Definitions/helloworld3_types.yaml new file mode 100644 index 000000000..abcee8a8a --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Definitions/helloworld3_types.yaml @@ -0,0 +1,65 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: VNF type definition + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: + company.provider.VNF: + derived_from: tosca.nodes.nfv.VNF + properties: + id: + type: string + description: ID of this VNF + default: vnf_id + vendor: + type: string + description: name of the vendor who generate this VNF + default: vendor + version: + type: version + description: version of the software for this VNF + default: 1.0 + descriptor_id: + type: string + constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ] + default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + descriptor_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + provider: + type: string + constraints: [ valid_values: [ 'Company' ] ] + default: 'Company' + product_name: + type: string + constraints: [ valid_values: [ 'Sample VNF' ] ] + default: 'Sample VNF' + software_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + vnfm_info: + type: list + entry_schema: + type: string + constraints: [ valid_values: [ Tacker ] ] + default: [ Tacker ] + flavour_id: + type: string + constraints: [ valid_values: [ simple ] ] + default: simple + flavour_description: + type: string + default: "" + requirements: + - virtual_link_external: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_internal: + capability: tosca.capabilities.nfv.VirtualLinkable + interfaces: + Vnflcm: + type: tosca.interfaces.nfv.Vnflcm diff --git a/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Drivers/vnflcm_noop.py b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Drivers/vnflcm_noop.py new file mode 100644 index 000000000..6e520aa9f --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver1/Drivers/vnflcm_noop.py @@ -0,0 +1,68 @@ +# Copyright (C) 2020 FUJITSU +# 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/refactor_mgmt_driver2/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver2/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..4f8c176da --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver2/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,269 @@ +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 + - helloworld3_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: + # supporting only 'instantiate', 'terminate', 'modify' + # not supporting LCM script, supporting only default LCM + instantiate: [] + instantiate_start: + implementation: vnflcm_noop_false + instantiate_end: + implementation: vnflcm_noop_false + terminate: [] + terminate_start: + implementation: vnflcm_noop_false + terminate_end: + implementation: vnflcm_noop_false + artifacts: + vnflcm_noop: + description: Management driver instantiate + type: tosca.artifacts.Implementation.Python + file: Drivers/vnflcm_noop_false.py + + 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.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + 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.4.0-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.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + 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.4.0-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/refactor_mgmt_driver2/Drivers/vnflcm_noop_false.py b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver2/Drivers/vnflcm_noop_false.py new file mode 100644 index 000000000..f6b1fd646 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver2/Drivers/vnflcm_noop_false.py @@ -0,0 +1,88 @@ +# Copyright (C) 2020 FUJITSU +# 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 oslo_log import log as logging + +from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver + + +LOG = logging.getLogger(__name__) + + +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' + + def instantiate_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('instantiate_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def instantiate_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('instantiate_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def terminate_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('terminate_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def terminate_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('terminate_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def scale_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('scale_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def scale_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('scale_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def heal_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('heal_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def heal_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('heal_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass diff --git a/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver3/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver3/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..abc175541 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver3/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,269 @@ +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 + - helloworld3_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: + # supporting only 'instantiate', 'terminate', 'modify' + # not supporting LCM script, supporting only default LCM + instantiate: [] + instantiate_start: + implementation: vnflcm_noop + instantiate_end: + implementation: vnflcm_noop + terminate: [] + terminate_start: + implementation: vnflcm_noop + terminate_end: + implementation: vnflcm_noop + artifacts: + vnflcm_noop: + description: Management driver instantiate + type: tosca.artifacts.Implementation.Python + file: Drivers/vnflcm_noop.py + + 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.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + 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.4.0-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.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + 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.4.0-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/refactor_mgmt_driver3/Drivers/vnflcm_noop.py b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver3/Drivers/vnflcm_noop.py new file mode 100644 index 000000000..d3766064a --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/refactor_mgmt_driver3/Drivers/vnflcm_noop.py @@ -0,0 +1,81 @@ +# Copyright (C) 2020 FUJITSU +# 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 oslo_log import log as logging + +from tacker.vnfm.mgmt_drivers import vnflcm_abstract_driver + + +LOG = logging.getLogger(__name__) + + +class VnflcmMgmtNoop(vnflcm_abstract_driver.VnflcmMgmtAbstractDriver): + + # instantiate start + def instantiate_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('instantiate_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def instantiate_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('instantiate_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def terminate_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('terminate_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def terminate_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('terminate_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def scale_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('scale_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def scale_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('scale_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def heal_start(self, vnf_instance, additional_params, **kwargs): + LOG.debug('heal_start %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass + + def heal_end(self, vnf_instance, additional_params, **kwargs): + LOG.debug('heal_end %(vnf_instance)s ' + '%(additional_params)s %(kwargs)s', + {'vnf_instance': vnf_instance, + 'additional_params': additional_params, 'kwargs': kwargs}) + pass diff --git a/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..2547c3ac8 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,206 @@ +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 + - helloworld3_types.yaml + +topology_template: + inputs: + 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: [] + terminate: [] + terminate_start: [] + terminate_end: [] + instantiate_start: + implementation: vnflcm_noop + instantiate_end: + implementation: vnflcm_noop + artifacts: + vnflcm_noop: + description: Management driver for vnflcm_noop + type: tosca.artifacts.Implementation.Python + file: Scripts/vnflcm_noop.py + + 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: 3 + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 3 GB + requirements: + - virtual_storage: VirtualStorage + + VirtualStorage: + type: tosca.nodes.nfv.Vdu.VirtualBlockStorage + properties: + virtual_block_storage_data: + size_of_storage: 3 GB + rdma_enabled: true + sw_image_data: + name: VirtualStorage + version: '0.4.0' + checksum: + algorithm: sha-512 + hash: 6513f21e44aa3da349f248188a44bc304a3653a04122d8fb4535423c8e1d14cd6a153f735bb0982e2161b5b5186106570c17a9e58b64dd39390617cd5a350f78 + container_format: bare + disk_format: qcow2 + min_disk: 2 GB + min_ram: 256 MB + size: 1 GB + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.4.0-x86_64-disk.img + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL1 + + internalVL1: + 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: 33.33.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 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - 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 ] + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 1 + targets: [ VDU1 ] + + - internalVL1_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: [ internalVL1 ] diff --git a/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_top.vnfd.yaml b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_top.vnfd.yaml new file mode 100644 index 000000000..18d4fe64b --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_top.vnfd.yaml @@ -0,0 +1,31 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - helloworld3_types.yaml + - helloworld3_df_simple.yaml + +topology_template: + inputs: + selected_flavour: + type: string + description: VNF deployment flavour selected by the consumer. It is provided in the API + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_id: { get_input: selected_flavour } + descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + provider: Company + product_name: Sample VNF + software_version: '1.0' + descriptor_version: '1.0' + vnfm_info: + - Tacker + requirements: + #- virtual_link_external # mapped in lower-level templates + #- virtual_link_internal # mapped in lower-level templates diff --git a/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_types.yaml b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_types.yaml new file mode 100644 index 000000000..16a4ff5bc --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Definitions/helloworld3_types.yaml @@ -0,0 +1,53 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: VNF type definition + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: + company.provider.VNF: + derived_from: tosca.nodes.nfv.VNF + properties: + descriptor_id: + type: string + constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ] + default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + descriptor_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + provider: + type: string + constraints: [ valid_values: [ 'Company' ] ] + default: 'Company' + product_name: + type: string + constraints: [ valid_values: [ 'Sample VNF' ] ] + default: 'Sample VNF' + software_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + vnfm_info: + type: list + entry_schema: + type: string + constraints: [ valid_values: [ Tacker ] ] + default: [ Tacker ] + flavour_id: + type: string + constraints: [ valid_values: [ simple ] ] + default: simple + flavour_description: + type: string + default: "falvour" + requirements: + - virtual_link_external: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_internal: + capability: tosca.capabilities.nfv.VirtualLinkable + interfaces: + Vnflcm: + type: tosca.interfaces.nfv.Vnflcm diff --git a/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Scripts/vnflcm_noop.py b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Scripts/vnflcm_noop.py new file mode 100644 index 000000000..6e520aa9f --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/Scripts/vnflcm_noop.py @@ -0,0 +1,68 @@ +# Copyright (C) 2020 FUJITSU +# 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/test_inst_terminate_vnf_with_vnflcmnoop/TOSCA-Metadata/TOSCA.meta b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 000000000..b0413c5d7 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_inst_terminate_vnf_with_vnflcmnoop/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,12 @@ +TOSCA-Meta-File-Version: 1.0 +Created-by: dummy_user +CSAR-Version: 1.1 +Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml + +Name: Files/images/cirros-0.4.0-x86_64-disk.img +Content-type: application/x-iso9066-image + +Name: Scripts/vnflcm_noop.py +Content-Type: text/x-python +Algorithm: SHA-256 +Hash: ffea638bfdbde3fb01f191bbe75b031859b18d663b127100eb72b19eecd7ed51 diff --git a/tacker/tests/functional/sol/vnflcm/test_vnflcm_noop.py b/tacker/tests/functional/sol/vnflcm/test_vnflcm_noop.py new file mode 100644 index 000000000..0eb034d89 --- /dev/null +++ b/tacker/tests/functional/sol/vnflcm/test_vnflcm_noop.py @@ -0,0 +1,294 @@ +# Copyright (C) 2020 FUJITSU +# 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. + +import os +import time + +from oslo_serialization import jsonutils +from oslo_utils import uuidutils +from sqlalchemy import desc +from sqlalchemy.orm import joinedload + +from tacker.common import exceptions +from tacker import context as t_context +from tacker.db import api as db_api +from tacker.db.db_sqlalchemy import api +from tacker.db.db_sqlalchemy import models +from tacker.objects import fields +from tacker.tests.functional import base +from tacker.tests import utils + +VNF_PACKAGE_UPLOAD_TIMEOUT = 300 +VNF_INSTANTIATE_TIMEOUT = 600 +VNF_TERMINATE_TIMEOUT = 600 +VNF_HEAL_TIMEOUT = 600 +RETRY_WAIT_TIME = 5 + + +def _create_and_upload_vnf_package(tacker_client, csar_package_name, + user_defined_data): + # create vnf package + body = jsonutils.dumps({"userDefinedData": user_defined_data}) + resp, vnf_package = tacker_client.do_request( + '/vnfpkgm/v1/vnf_packages', "POST", body=body) + + # upload vnf package + csar_package_path = "../../../etc/samples/etsi/nfv/%s" % csar_package_name + file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + csar_package_path)) + + # Generating unique vnfd id. This is required when multiple workers + # are running concurrently. The call below creates a new temporary + # CSAR with unique vnfd id. + file_path, uniqueid = utils.create_csar_with_unique_vnfd_id(file_path) + + with open(file_path, 'rb') as file_object: + resp, resp_body = tacker_client.do_request( + '/vnfpkgm/v1/vnf_packages/{id}/package_content'.format( + id=vnf_package['id']), + "PUT", body=file_object, content_type='application/zip') + + # wait for onboard + timeout = VNF_PACKAGE_UPLOAD_TIMEOUT + start_time = int(time.time()) + show_url = os.path.join('/vnfpkgm/v1/vnf_packages', vnf_package['id']) + vnfd_id = None + while True: + resp, body = tacker_client.do_request(show_url, "GET") + if body['onboardingState'] == "ONBOARDED": + vnfd_id = body['vnfdId'] + break + + if ((int(time.time()) - start_time) > timeout): + raise Exception("Failed to onboard vnf package") + + time.sleep(1) + + # remove temporarily created CSAR file + os.remove(file_path) + return vnf_package['id'], vnfd_id + + +class VnfLcmTest(base.BaseTackerTest): + + @classmethod + def setUpClass(cls): + cls.tacker_client = base.BaseTackerTest.tacker_http_client() + + cls.vnf_package, cls.vnfd_id = \ + _create_and_upload_vnf_package( + cls.tacker_client, "test_inst_terminate_vnf_with_vnflcmnoop", + {"key": "file_functional"}) + + super(VnfLcmTest, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + # Update vnf package operational state to DISABLED + update_req_body = jsonutils.dumps({ + "operationalState": "DISABLED"}) + base_path = "/vnfpkgm/v1/vnf_packages" + for package_id in [cls.vnf_package]: + resp, resp_body = cls.tacker_client.do_request( + '{base_path}/{id}'.format(id=package_id, + base_path=base_path), + "PATCH", content_type='application/json', + body=update_req_body) + + # Delete vnf package + url = '/vnfpkgm/v1/vnf_packages/%s' % package_id + cls.tacker_client.do_request(url, "DELETE") + + super(VnfLcmTest, cls).tearDownClass() + + def setUp(self): + super(VnfLcmTest, self).setUp() + self.base_url = "/vnflcm/v1/vnf_instances" + self.context = t_context.get_admin_context() + + vim_list = self.client.list_vims() + if not vim_list: + self.skipTest("Vims are not configured") + + vim_id = 'VIM0' + vim = self.get_vim(vim_list, vim_id) + if not vim: + self.skipTest("Openstack VIM '%s' is missing" % vim_id) + self.vim_id = vim['id'] + + def _instantiate_vnf_instance_request( + self, flavour_id, vim_id=None, additional_param=None): + request_body = {"flavourId": flavour_id} + + if vim_id: + request_body["vimConnectionInfo"] = [ + {"id": uuidutils.generate_uuid(), + "vimId": vim_id, + "vimType": "openstack"}] + + if additional_param: + request_body["additionalParams"] = additional_param + + return request_body + + def _create_vnf_instance(self, vnfd_id, vnf_instance_name=None, + vnf_instance_description=None): + request_body = {'vnfdId': vnfd_id} + if vnf_instance_name: + request_body['vnfInstanceName'] = vnf_instance_name + + if vnf_instance_description: + request_body['vnfInstanceDescription'] = vnf_instance_description + + resp, response_body = self.http_client.do_request( + self.base_url, "POST", body=jsonutils.dumps(request_body)) + return resp, response_body + + def _delete_wait_vnf_instance(self, id): + timeout = VNF_TERMINATE_TIMEOUT + url = os.path.join(self.base_url, id) + start_time = int(time.time()) + while True: + resp, body = self.http_client.do_request(url, "DELETE") + if 204 == resp.status_code: + break + + if ((int(time.time()) - start_time) > timeout): + error = "Failed to delete vnf instance %s" + self.fail(error % id) + + time.sleep(RETRY_WAIT_TIME) + + def _delete_vnf_instance(self, id): + self._delete_wait_vnf_instance(id) + + # verify vnf instance is deleted + url = os.path.join(self.base_url, id) + resp, body = self.http_client.do_request(url, "GET") + self.assertEqual(404, resp.status_code) + + def _show_vnf_instance(self, id, expected_result=None): + show_url = os.path.join(self.base_url, id) + resp, vnf_instance = self.http_client.do_request(show_url, "GET") + self.assertEqual(200, resp.status_code) + + if expected_result: + self.assertDictSupersetOf(expected_result, vnf_instance) + + return vnf_instance + + def _vnf_instance_wait( + self, id, + instantiation_state=fields.VnfInstanceState.INSTANTIATED, + timeout=VNF_INSTANTIATE_TIMEOUT): + show_url = os.path.join(self.base_url, id) + start_time = int(time.time()) + while True: + resp, body = self.http_client.do_request(show_url, "GET") + if body['instantiationState'] == instantiation_state: + break + + if ((int(time.time()) - start_time) > timeout): + error = ("Vnf instance %(id)s status is %(current)s, " + "expected status should be %(expected)s") + self.fail(error % {"id": id, + "current": body['instantiationState'], + "expected": instantiation_state}) + + time.sleep(RETRY_WAIT_TIME) + + def _instantiate_vnf_instance(self, id, request_body): + url = os.path.join(self.base_url, id, "instantiate") + resp, body = self.http_client.do_request( + url, "POST", body=jsonutils.dumps(request_body)) + self.assertEqual(202, resp.status_code) + self._vnf_instance_wait(id) + + def _terminate_vnf_instance(self, id, request_body): + url = os.path.join(self.base_url, id, "terminate") + resp, body = self.http_client.do_request( + url, "POST", body=jsonutils.dumps(request_body)) + self.assertEqual(202, resp.status_code) + + timeout = request_body.get('gracefulTerminationTimeout') + start_time = int(time.time()) + + self._vnf_instance_wait( + id, instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED, + timeout=VNF_TERMINATE_TIMEOUT) + + # If gracefulTerminationTimeout is set, check whether vnf + # instantiation_state is set to NOT_INSTANTIATED after + # gracefulTerminationTimeout seconds. + if timeout and int(time.time()) - start_time < timeout: + self.fail("Vnf is terminated before graceful termination " + "timeout period") + + @db_api.context_manager.reader + def _vnf_notify_get_by_id(self, context, vnf_instance_id, + columns_to_join=None): + query = api.model_query( + context, models.VnfLcmOpOccs, + read_deleted="no", project_only=True).filter_by( + vnf_instance_id=vnf_instance_id).order_by( + desc("created_at")) + + if columns_to_join: + for column in columns_to_join: + query = query.options(joinedload(column)) + + result = query.first() + + if not result: + raise exceptions.VnfInstanceNotFound(id=vnf_instance_id) + + return result + + def test_instantiate_terminate_vnf_with_vnflcmnoop(self): + # create vnf instance + vnf_instance_name = "vnf_with_instantiation_level-%s" % \ + uuidutils.generate_uuid() + vnf_instance_description = "vnf with instantiation level 1" + resp, vnf_instance = self._create_vnf_instance( + self.vnfd_id, + vnf_instance_name=vnf_instance_name, + vnf_instance_description=vnf_instance_description) + self.assertIsNotNone(vnf_instance['id']) + self.assertEqual(201, resp.status_code) + # instantiate vnf instance + request_body = self._instantiate_vnf_instance_request( + "simple", vim_id=self.vim_id) + self._instantiate_vnf_instance(vnf_instance['id'], request_body) + time.sleep(20) + # show vnf instance + vnf_instance = self._show_vnf_instance(vnf_instance['id']) + self.assertEqual(vnf_instance['instantiationState'], 'INSTANTIATED') + vnflcm_op_occ_ins = self._vnf_notify_get_by_id( + self.context, vnf_instance['id'], columns_to_join=None) + self.assertEqual(vnflcm_op_occ_ins.operation_state, 'COMPLETED') + self.assertEqual(vnflcm_op_occ_ins.operation, 'INSTANTIATE') + time.sleep(20) + # terminate vnf instance + terminate_req_body = { + "terminationType": fields.VnfInstanceTerminationType.FORCEFUL, + } + self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body) + time.sleep(20) + vnflcm_op_occ_term = self._vnf_notify_get_by_id( + self.context, vnf_instance['id'], columns_to_join=None) + self.assertEqual(vnflcm_op_occ_term.operation_state, 'COMPLETED') + self.assertEqual(vnflcm_op_occ_term.operation, 'TERMINATE') + # delete vnf instance + self._delete_vnf_instance(vnf_instance['id']) diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 05d80c2fe..9de51931e 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -39,6 +39,11 @@ import tacker.conf CONF = tacker.conf.CONF +def return_vnf_interfaces(): + vnf_interface = 'vnflcm_noop' + return vnf_interface + + def return_default_vim(): default_vim = { 'vim_auth': { diff --git a/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py b/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py new file mode 100644 index 000000000..6c04a68d2 --- /dev/null +++ b/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py @@ -0,0 +1,248 @@ +# Copyright (C) 2020 FUJITSU +# 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. + + +import fixtures +import os +import shutil + +from oslo_config import cfg +from oslo_utils import uuidutils + +from tacker.common import exceptions +from tacker import context +from tacker.manager import TackerManager +from tacker import objects +from tacker.tests.unit.db import base as db_base +from tacker.tests.unit.nfvo.test_nfvo_plugin import FakeVNFMPlugin +from tacker.tests.unit.vnflcm import fakes +from tacker.tests import utils as test_utils +from tacker.tests import uuidsentinel +from tacker.vnflcm import vnflcm_driver +from tacker.vnflcm.vnflcm_driver import VnfLcmDriver +from unittest import mock + + +vnf_dict = { + 'id': uuidutils.generate_uuid(), + 'mgmt_ip_address': '{"VDU1": "a.b.c.d"}', + 'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff', + 'instance_id': 'a737497c-761c-11e5-89c3-9cb6541d805d', + 'vnfd': { + 'attributes': { + 'heat_template': { + 'resources': { + 'VDU1': { + 'properties': { + 'networks': [{'port': {'get_resource': 'CP1'}}]} + } + } + } + } + } +} + + +class InfraDriverException(Exception): + pass + + +class FakeDriverManager(mock.Mock): + def __init__(self, fail_method_name=None, vnf_resource_count=1): + super(FakeDriverManager, self).__init__() + self.fail_method_name = fail_method_name + self.vnf_resource_count = vnf_resource_count + + def invoke(self, *args, **kwargs): + if 'pre_instantiation_vnf' in args: + vnf_resource_list = [fakes.return_vnf_resource() for index in + range(self.vnf_resource_count)] + return {'node_name': vnf_resource_list} + if 'instantiate_vnf' in args: + if self.fail_method_name and \ + self.fail_method_name == 'instantiate_vnf': + raise InfraDriverException("instantiate_vnf failed") + + instance_id = uuidsentinel.instance_id + vnfd_dict = kwargs.get('vnfd_dict') + vnfd_dict['instance_id'] = instance_id + return instance_id + if 'create_wait' in args: + if self.fail_method_name and \ + self.fail_method_name == 'create_wait': + raise InfraDriverException("create_wait failed") + elif 'post_vnf_instantiation' in args: + pass + if 'mgmt-drivers-custom' in args: + if self.fail_method_name and \ + self.fail_method_name == 'mgmt-drivers-custom': + raise InfraDriverException("mgmt-drivers-custom failed") + + +class FakeVimClient(mock.Mock): + pass + + +class FakeTackerManager(mock.MagicMock): + pass + + +class MgmtVnfLcmDriverTest(db_base.SqlTestCase): + + def setUp(self): + super(MgmtVnfLcmDriverTest, self).setUp() + self.addCleanup(mock.patch.stopall) + self.context = context.get_admin_context() + self._mock_vim_client() + self._stub_get_vim() + self.temp_dir = self.useFixture(fixtures.TempDir()).path + + def _mock_vnf_manager(self, fail_method_name=None, vnf_resource_count=1): + self._vnf_manager = mock.Mock(wraps=FakeDriverManager( + fail_method_name=fail_method_name, + vnf_resource_count=vnf_resource_count)) + self._vnf_manager.__contains__ = mock.Mock( + return_value=True) + fake_vnf_manager = mock.Mock() + fake_vnf_manager.return_value = self._vnf_manager + self._mock( + 'tacker.common.driver_manager.DriverManager', fake_vnf_manager) + + def _mock_vim_client(self): + self.vim_client = mock.Mock(wraps=FakeVimClient()) + fake_vim_client = mock.Mock() + fake_vim_client.return_value = self.vim_client + self._mock( + 'tacker.vnfm.vim_client.VimClient', fake_vim_client) + + def _stub_get_vim(self): + vim_obj = {'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff', + 'vim_name': 'fake_vim', 'vim_auth': + {'auth_url': 'http://localhost/identity', 'password': + 'test_pw', 'username': 'test_user', 'project_name': + 'test_project'}, 'vim_type': 'openstack'} + self.vim_client.get_vim.return_value = vim_obj + + @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_vnf(self, mock_vnf_instance_save, + mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict): + 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() + + 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, "refactor_mgmt_driver1") + self._mock_vnf_manager() + driver = vnflcm_driver.VnfLcmDriver() + vnf_dict = {"vnfd": {"attributes": {}}, "attributes": {}} + 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(5, self._vnf_manager.invoke.call_count) + shutil.rmtree(fake_csar) + + @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_vnf_py_name_false( + self, mock_vnf_instance_save, mock_vnf_package_vnfd, + mock_create, mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict): + 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() + + 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, "refactor_mgmt_driver2") + self._mock_vnf_manager() + driver = vnflcm_driver.VnfLcmDriver() + vnf_dict = {"vnfd": {"attributes": {}}, "attributes": {}} + self.assertRaises(exceptions.MgmtDriverInconsistent, + driver.instantiate_vnf, self.context, + vnf_instance_obj, vnf_dict, + instantiate_vnf_req_obj) + shutil.rmtree(fake_csar) + + @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_vnf_py_hash_false( + self, mock_vnf_instance_save, mock_vnf_package_vnfd, + mock_create, mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict): + 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() + + 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, "refactor_mgmt_driver3") + self._mock_vnf_manager() + driver = vnflcm_driver.VnfLcmDriver() + vnf_dict = {"vnfd": {"attributes": {}}, "attributes": {}} + self.assertRaises(exceptions.MgmtDriverHashMatchFailure, + driver.instantiate_vnf, self.context, + vnf_instance_obj, vnf_dict, + instantiate_vnf_req_obj) + shutil.rmtree(fake_csar) diff --git a/tacker/tests/unit/vnflcm/test_vnflcm_driver.py b/tacker/tests/unit/vnflcm/test_vnflcm_driver.py index 7ed5a0ee1..d21c26036 100644 --- a/tacker/tests/unit/vnflcm/test_vnflcm_driver.py +++ b/tacker/tests/unit/vnflcm/test_vnflcm_driver.py @@ -40,6 +40,7 @@ from tacker.tests.unit.vnflcm import fakes from tacker.tests import utils as test_utils from tacker.tests import uuidsentinel from tacker.vnflcm import vnflcm_driver +from tacker.vnflcm.vnflcm_driver import VnfLcmDriver from tacker.vnfm.infra_drivers.openstack import heat_client from tacker.vnfm.infra_drivers.openstack import openstack as opn from tacker.vnfm import plugin @@ -181,15 +182,25 @@ class TestVnflcmDriver(db_base.SqlTestCase): self.vim_client.get_vim.return_value = vim_obj @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_vnf(self, mock_vnf_instance_save, - mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, - mock_final_vnf_dict): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_instantiate_vnf( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -210,18 +221,29 @@ class TestVnflcmDriver(db_base.SqlTestCase): instantiate_vnf_req_obj) self.assertEqual(1, mock_vnf_instance_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(5, self._vnf_manager.invoke.call_count) shutil.rmtree(fake_csar) @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") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_instantiate_vnf_with_ext_virtual_links( - self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, mock_final_vnf_dict): + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -244,18 +266,29 @@ class TestVnflcmDriver(db_base.SqlTestCase): instantiate_vnf_req_obj) self.assertEqual(1, mock_vnf_instance_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(5, self._vnf_manager.invoke.call_count) shutil.rmtree(fake_csar) @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") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_instantiate_vnf_vim_connection_info( - self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, mock_final_vnf_dict): + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -278,18 +311,29 @@ class TestVnflcmDriver(db_base.SqlTestCase): instantiate_vnf_req_obj) self.assertEqual(1, mock_vnf_instance_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(5, self._vnf_manager.invoke.call_count) shutil.rmtree(fake_csar) @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") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_instantiate_vnf_infra_fails_to_instantiate( - self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, mock_final_vnf_dict): + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -319,20 +363,31 @@ class TestVnflcmDriver(db_base.SqlTestCase): vnf_instance_obj.instantiation_state) # 2->1 reason: rollback_vnf_instantiated_resources deleted self.assertEqual(1, mock_vnf_instance_save.call_count) - self.assertEqual(2, self._vnf_manager.invoke.call_count) + self.assertEqual(3, self._vnf_manager.invoke.call_count) mock_final_vnf_dict.assert_called_once() shutil.rmtree(fake_csar) @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") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_instantiate_vnf_infra_fails_to_wait_after_instantiate( - self, mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, mock_final_vnf_dict): + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, mock_create, + mock_get_service_plugins, mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -369,19 +424,31 @@ class TestVnflcmDriver(db_base.SqlTestCase): # 3->1 reason: rollback_vnf_instantiated_resources deleted self.assertEqual(1, mock_vnf_instance_save.call_count) # 5->3 reason: rollback_vnf_instantiated_resources deleted - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(4, self._vnf_manager.invoke.call_count) shutil.rmtree(fake_csar) @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_vnf_with_short_notation(self, mock_vnf_instance_save, - mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, mock_final_vnf_dict): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_instantiate_vnf_with_short_notation( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, + mock_create, mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -408,14 +475,26 @@ class TestVnflcmDriver(db_base.SqlTestCase): shutil.rmtree(fake_csar) @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_vnf_with_single_vnfd(self, mock_vnf_instance_save, - mock_vnf_package_vnfd, mock_create, - mock_get_service_plugins, mock_final_vnf_dict): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_instantiate_vnf_with_single_vnfd( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_vnf_instance_save, mock_vnf_package_vnfd, + mock_create, mock_get_service_plugins, mock_init_hash, + mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -441,12 +520,25 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vim_client.VimClient, "get_vim") @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") @mock.patch.object(objects.VnfResource, "destroy") - def test_terminate_vnf(self, mock_resource_destroy, mock_resource_list, - mock_vim, mock_vnf_instance_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_terminate_vnf( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_resource_destroy, mock_resource_list, + mock_vim, mock_vnf_instance_save, mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) vnf_instance.instantiated_vnf_info.instance_id =\ @@ -461,17 +553,29 @@ class TestVnflcmDriver(db_base.SqlTestCase): driver.terminate_vnf(self.context, vnf_instance, terminate_vnf_req) self.assertEqual(2, mock_vnf_instance_save.call_count) self.assertEqual(1, mock_resource_destroy.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(5, self._vnf_manager.invoke.call_count) @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vim_client.VimClient, "get_vim") @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") @mock.patch.object(objects.VnfResource, "destroy") - def test_terminate_vnf_graceful_no_timeout(self, mock_resource_destroy, + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_terminate_vnf_graceful_no_timeout( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_resource_destroy, mock_resource_list, mock_vim, mock_vnf_instance_save, - mock_get_service_plugins): + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) vnf_instance.instantiated_vnf_info.instance_id =\ @@ -489,10 +593,21 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vim_client.VimClient, "get_vim") - def test_terminate_vnf_delete_instance_failed(self, mock_vim, - mock_vnf_instance_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_terminate_vnf_delete_instance_failed( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_vim, + mock_vnf_instance_save, mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) vnf_instance.instantiated_vnf_info.instance_id =\ @@ -507,14 +622,26 @@ class TestVnflcmDriver(db_base.SqlTestCase): self.context, vnf_instance, terminate_vnf_req) self.assertEqual("delete failed", str(error)) self.assertEqual(1, mock_vnf_instance_save.call_count) - self.assertEqual(1, self._vnf_manager.invoke.call_count) + self.assertEqual(2, self._vnf_manager.invoke.call_count) @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vim_client.VimClient, "get_vim") - def test_terminate_vnf_delete_wait_instance_failed(self, mock_vim, - mock_vnf_instance_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_terminate_vnf_delete_wait_instance_failed( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_vim, + mock_vnf_instance_save, mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) vnf_instance.instantiated_vnf_info.instance_id =\ @@ -528,15 +655,28 @@ class TestVnflcmDriver(db_base.SqlTestCase): self.context, vnf_instance, terminate_vnf_req) self.assertEqual("delete_wait failed", str(error)) self.assertEqual(2, mock_vnf_instance_save.call_count) - self.assertEqual(2, self._vnf_manager.invoke.call_count) + self.assertEqual(3, self._vnf_manager.invoke.call_count) @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vim_client.VimClient, "get_vim") @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") - def test_terminate_vnf_delete_vnf_resource_failed(self, mock_resource_list, - mock_vim, mock_vnf_instance_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_terminate_vnf_delete_vnf_resource_failed( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_resource_list, + mock_vim, mock_vnf_instance_save, mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) vnf_instance.instantiated_vnf_info.instance_id =\ @@ -551,9 +691,11 @@ class TestVnflcmDriver(db_base.SqlTestCase): self.context, vnf_instance, terminate_vnf_req) self.assertEqual("delete_vnf_resource failed", str(error)) self.assertEqual(2, mock_vnf_instance_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(4, self._vnf_manager.invoke.call_count) @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('tacker.vnflcm.utils._make_final_vnf_dict') @@ -564,11 +706,20 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_without_vnfc_instance(self, mock_log, mock_save, + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_without_vnfc_instance( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_log, mock_save, mock_vnf_resource_list, mock_resource_destroy, mock_resource_create, mock_vim, mock_vnf_package_vnfd, mock_make_final_vnf_dict, mock_get_service_plugins, - mock_final_vnf_dict): + mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -611,7 +762,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): self.assertEqual(1, mock_resource_create.call_count) # Invoke will be called 7 times, 3 for deleting the vnf # resources and 4 during instantiation. - self.assertEqual(7, self._vnf_manager.invoke.call_count) + self.assertEqual(9, self._vnf_manager.invoke.call_count) expected_msg = ("Request received for healing vnf '%s' " "is completed successfully") mock_log.info.assert_called_with(expected_msg, @@ -621,10 +772,21 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_without_vnfc_instance_infra_delete_fail(self, mock_log, - mock_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_without_vnfc_instance_infra_delete_fail( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_log, + mock_save, mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() # Heal as per SOL003 i.e. without vnfcInstanceId heal_vnf_req = objects.HealVnfRequest() @@ -640,7 +802,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): driver.heal_vnf, self.context, vnf_instance, vnf_dict, heal_vnf_req) self.assertEqual(1, mock_save.call_count) - self.assertEqual(1, self._vnf_manager.invoke.call_count) + self.assertEqual(2, self._vnf_manager.invoke.call_count) self.assertEqual(fields.VnfInstanceTaskState.ERROR, vnf_instance.task_state) expected_msg = ('Failed to delete vnf resources for vnf instance %s ' @@ -649,6 +811,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_log.error.assert_called_with(expected_msg % vnf_instance.id) @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('tacker.vnflcm.utils._make_final_vnf_dict') @@ -659,11 +823,20 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_without_vnfc_instance_infra_instantiate_vnf_fail(self, + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_without_vnfc_instance_infra_instantiate_vnf_fail( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_log, mock_save, mock_vnf_resource_list, mock_resource_destroy, mock_resource_create, mock_vim, mock_vnf_package_vnfd, mock_make_final_vnf_dict, - mock_get_service_plugins, mock_final_vnf_dict): + mock_get_service_plugins, mock_init_hash, mock_final_vnf_dict): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() 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 @@ -696,7 +869,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): # instantiation. self.assertEqual(1, mock_resource_create.call_count) - self.assertEqual(5, self._vnf_manager.invoke.call_count) + self.assertEqual(6, self._vnf_manager.invoke.call_count) self.assertEqual(fields.VnfInstanceTaskState.ERROR, vnf_instance.task_state) expected_msg = ('Failed to instantiate vnf instance %s ' @@ -709,10 +882,21 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_with_vnfc_instance(self, mock_log, mock_save, - mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_with_vnfc_instance( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_log, mock_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() heal_vnf_req = objects.HealVnfRequest(vnfc_instance_id=[ uuidsentinel.vnfc_instance_id_1]) @@ -724,7 +908,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): driver = vnflcm_driver.VnfLcmDriver() driver.heal_vnf(self.context, vnf_instance, mock.ANY, heal_vnf_req) self.assertEqual(1, mock_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(5, self._vnf_manager.invoke.call_count) self.assertEqual(None, vnf_instance.task_state) expected_msg = ("Request received for healing vnf '%s' " @@ -734,24 +918,34 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_with_infra_heal_vnf_fail(self, mock_log, mock_save, - mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_with_infra_heal_vnf_fail( + self, mock_vnf_interfaces, mock_vnfd_dict, + mock_log, mock_save, mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } heal_vnf_req = objects.HealVnfRequest(vnfc_instance_id=[ uuidsentinel.vnfc_instance_id_1]) vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED, task_state=fields.VnfInstanceTaskState.HEALING) - + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() self._mock_vnf_manager(fail_method_name='heal_vnf') driver = vnflcm_driver.VnfLcmDriver() self.assertRaises(exceptions.VnfHealFailed, driver.heal_vnf, self.context, vnf_instance, mock.ANY, heal_vnf_req) self.assertEqual(1, mock_save.call_count) - self.assertEqual(1, self._vnf_manager.invoke.call_count) + self.assertEqual(2, self._vnf_manager.invoke.call_count) self.assertEqual(fields.VnfInstanceTaskState.ERROR, vnf_instance.task_state) @@ -762,10 +956,21 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_with_infra_heal_vnf_wait_fail(self, mock_log, - mock_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_with_infra_heal_vnf_wait_fail( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_log, + mock_save, mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() heal_vnf_req = objects.HealVnfRequest(vnfc_instance_id=[ uuidsentinel.vnfc_instance_id_1]) @@ -787,7 +992,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): driver.heal_vnf(self.context, vnf_instance, mock.ANY, heal_vnf_req) self.assertEqual(1, mock_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(5, self._vnf_manager.invoke.call_count) self.assertEqual(None, vnf_instance.task_state) expected_msg = ('Failed to update vnf %(id)s resources for ' @@ -799,10 +1004,21 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfInstance, "save") @mock.patch('tacker.vnflcm.vnflcm_driver.LOG') - def test_heal_vnf_with_infra_post_heal_vnf_fail(self, mock_log, - mock_save, mock_get_service_plugins): + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') + def test_heal_vnf_with_infra_post_heal_vnf_fail( + self, mock_vnf_interfaces, mock_vnfd_dict, mock_log, + mock_save, mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() heal_vnf_req = objects.HealVnfRequest(vnfc_instance_id=[ uuidsentinel.vnfc_instance_id_1]) @@ -818,7 +1034,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): driver.heal_vnf, self.context, vnf_instance, mock.ANY, heal_vnf_req) self.assertEqual(1, mock_save.call_count) - self.assertEqual(3, self._vnf_manager.invoke.call_count) + self.assertEqual(4, self._vnf_manager.invoke.call_count) self.assertEqual(fields.VnfInstanceTaskState.ERROR, vnf_instance.task_state) @@ -832,8 +1048,15 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(driver_manager.DriverManager, "invoke") - def test_scale_true(self, mock_invoke, mock_get_service_plugins): + def test_scale_true(self, mock_invoke, mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_info = fakes._get_vnf() vnf_info['attributes']['scale_group'] = '{\"scaleGroupDict\": ' + \ '{ \"SP1\": { \"vdu\": [\"VDU1\"], \"num\": ' + \ @@ -850,10 +1073,17 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(yaml, "safe_load") @mock.patch.object(driver_manager.DriverManager, "invoke") def test_scale_false_in(self, mock_invoke, mock_safe_load, - mock_get_service_plugins): + mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_info = fakes._get_vnf() vnf_info['attributes']['scale_group'] = '{\"scaleGroupDict\": ' + \ '{ \"SP1\": { \"vdu\": [\"VDU1\"], \"num\": ' + \ @@ -873,10 +1103,17 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(yaml, "safe_load") @mock.patch.object(driver_manager.DriverManager, "invoke") def test_scale_false_out_initial(self, mock_invoke, mock_safe_load, - mock_get_service_plugins): + mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_info = fakes._get_vnf() vnf_info['attributes']['scale_group'] = '{\"scaleGroupDict\": ' + \ '{ \"SP1\": { \"vdu\": [\"VDU1\"], \"num\": ' + \ @@ -896,10 +1133,17 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(yaml, "safe_load") @mock.patch.object(driver_manager.DriverManager, "invoke") def test_scale_false_out_level_up(self, mock_invoke, mock_safe_load, - mock_get_service_plugins): + mock_init_hash, + mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_info = fakes._get_vnf() vnf_info['attributes']['scale_group'] = '{\"scaleGroupDict\": ' + \ '{ \"SP1\": { \"vdu\": [\"VDU1\"], \"num\": ' + \ @@ -919,19 +1163,30 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_7( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -953,6 +1208,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -965,7 +1222,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -987,6 +1249,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -999,7 +1263,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1021,6 +1290,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -1033,7 +1304,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1055,6 +1331,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -1067,7 +1345,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1089,19 +1372,30 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_scale( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1127,6 +1421,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -1139,7 +1435,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1165,6 +1466,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -1177,7 +1480,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1203,6 +1511,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -1215,7 +1525,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1241,6 +1556,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(VNFLcmRPCAPI, "send_notification") @mock.patch.object(objects.VnfInstance, "save") @@ -1253,7 +1570,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_insta_save, mock_notification, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1279,9 +1601,15 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") - def test_rollback_vnf_save_error(self, mock_lcm_save, + def test_rollback_vnf_save_error(self, mock_lcm_save, mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1305,6 +1633,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @@ -1322,7 +1652,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1351,6 +1686,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @@ -1368,6 +1705,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1405,6 +1743,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @@ -1413,8 +1753,11 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(opn.OpenStack, "delete") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_delete_error( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_delete, @@ -1422,7 +1765,13 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1448,6 +1797,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @@ -1457,8 +1808,11 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(opn.OpenStack, "delete_wait") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_delete_wait_error( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_delete_wait, @@ -1467,7 +1821,13 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1494,6 +1854,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @@ -1501,23 +1863,31 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(heat_client.HeatClient, "resource_get") @mock.patch.object(heat_client.HeatClient, "resource_get_list") @mock.patch.object(opn.OpenStack, "get_rollback_ids") - @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_rollback_mgmt_call") @mock.patch.object(opn.OpenStack, "scale_in_reverse") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_scale_update_error( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_scale, - mock_mgmt, mock_resource_get, mock_resource_get_list, mock_resource, mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() + vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1552,6 +1922,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @@ -1559,25 +1931,33 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(heat_client.HeatClient, "resource_get") @mock.patch.object(heat_client.HeatClient, "resource_get_list") @mock.patch.object(opn.OpenStack, "get_rollback_ids") - @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_rollback_mgmt_call") @mock.patch.object(opn.OpenStack, "scale_in_reverse") @mock.patch.object(opn.OpenStack, "scale_update_wait") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_scale_update_wait_error( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_wait, mock_scale, - mock_mgmt, mock_resource_get, mock_resource_get_list, mock_resource, mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() + vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1613,30 +1993,40 @@ class TestVnflcmDriver(db_base.SqlTestCase): @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': FakeVNFMPlugin()}) + @mock.patch.object(VnfLcmDriver, + '_init_mgmt_driver_hash') @mock.patch.object(objects.VnfLcmOpOcc, "save") @mock.patch.object(common_services_db_plugin.CommonServicesPluginDb, "create_event") @mock.patch.object(heat_client.HeatClient, "__init__") @mock.patch.object(opn.OpenStack, "get_rollback_ids") - @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_rollback_mgmt_call") @mock.patch.object(opn.OpenStack, "scale_in_reverse") @mock.patch.object(opn.OpenStack, "scale_update_wait") @mock.patch.object(opn.OpenStack, "scale_resource_update") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback_pre") @mock.patch.object(vnflcm_driver.VnfLcmDriver, "_update_vnf_rollback") + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch('tacker.vnflcm.vnflcm_driver.VnfLcmDriver.' + '_load_vnf_interface') def test_rollback_vnf_scale_resource_get_error( - self, + self, mock_vnf_interfaces, mock_vnfd_dict, mock_update, mock_up, mock_scale_resource, mock_wait, mock_scale, - mock_mgmt, mock_resource_get, mock_init, mock_event, mock_lcm_save, + mock_init_hash, mock_get_service_plugins): + mock_init_hash.return_value = { + "vnflcm_noop": "ffea638bfdbde3fb01f191bbe75b031859" + "b18d663b127100eb72b19eecd7ed51" + } + mock_vnf_interfaces.return_value = fakes.return_vnf_interfaces() + vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) diff --git a/tacker/vnflcm/vnflcm_driver.py b/tacker/vnflcm/vnflcm_driver.py index 65efaa308..74c9bf855 100644 --- a/tacker/vnflcm/vnflcm_driver.py +++ b/tacker/vnflcm/vnflcm_driver.py @@ -16,7 +16,9 @@ import copy from datetime import datetime import functools +import hashlib import inspect +import os import re import time import traceback @@ -28,10 +30,9 @@ from oslo_serialization import jsonutils from oslo_utils import encodeutils from oslo_utils import excutils -from tacker.common import log - from tacker.common import driver_manager from tacker.common import exceptions +from tacker.common import log from tacker.common import safe_utils from tacker.common import utils from tacker.conductor.conductorrpc import vnf_lcm_rpc @@ -40,10 +41,10 @@ from tacker import objects from tacker.objects import fields from tacker.vnflcm import abstract_driver from tacker.vnflcm import utils as vnflcm_utils -from tacker.vnfm.mgmt_drivers import constants as mgmt_constants LOG = logging.getLogger(__name__) CONF = cfg.CONF +DEFAULT_VNFLCM_MGMT_DRIVER = "vnflcm_noop" @utils.expects_func_args('vnf_info', 'vnf_instance', 'scale_vnf_request') @@ -281,7 +282,24 @@ def revert_to_error_rollback(function): return decorated_function +def config_opts(): + return [('tacker', VnfLcmDriver.OPTS)] + + class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): + OPTS = [ + cfg.ListOpt( + 'vnflcm_infra_driver', default=['openstack', 'kubernetes'], + help=_('Hosting vnf drivers tacker plugin will use') + ), + cfg.ListOpt( + 'vnflcm_mgmt_driver', default=[DEFAULT_VNFLCM_MGMT_DRIVER], + help=_('MGMT driver to communicate with ' + 'Hosting VNF/logical service ' + 'instance tacker plugin will use') + ) + ] + cfg.CONF.register_opts(OPTS, 'tacker') def __init__(self): super(VnfLcmDriver, self).__init__() @@ -289,7 +307,18 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): self._vnfm_plugin = manager.TackerManager.get_service_plugins()['VNFM'] self._vnf_manager = driver_manager.DriverManager( 'tacker.tacker.vnfm.drivers', - cfg.CONF.tacker.infra_driver) + cfg.CONF.tacker.vnflcm_infra_driver) + self._mgmt_manager = driver_manager.DriverManager( + 'tacker.tacker.mgmt.drivers', cfg.CONF.tacker.vnflcm_mgmt_driver) + self._mgmt_driver_hash = self._init_mgmt_driver_hash() + + def _init_mgmt_driver_hash(self): + + driver_hash = {} + for mgmt_driver in cfg.CONF.tacker.vnflcm_mgmt_driver: + path = inspect.getfile(self._mgmt_manager[mgmt_driver].__class__) + driver_hash[mgmt_driver] = self._get_file_hash(path) + return driver_hash def _vnf_instance_update(self, context, vnf_instance, **kwargs): """Update vnf instance in the database using kwargs as value.""" @@ -377,6 +406,57 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): id=vnf_instance.id, error=encodeutils.exception_to_unicode(exp)) + def _get_file_hash(self, path): + hash_obj = hashlib.sha256() + with open(path) as f: + hash_obj.update(f.read().encode('utf-8')) + return hash_obj.hexdigest() + + def _check_mgmt_driver(self, artifact_mgmt_driver, artifacts_value, + vnf_package_path): + # 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)) + raise exceptions.MgmtDriverInconsistent( + MgmtDriver=artifact_mgmt_driver) + + # check file content + pkg_mgmt_driver_path = os.path.join(vnf_package_path, + artifacts_value[artifact_mgmt_driver]['file']) + pkg_mgmt_driver_hash = self._get_file_hash(pkg_mgmt_driver_path) + if pkg_mgmt_driver_hash == \ + self._mgmt_driver_hash[artifact_mgmt_driver]: + return artifact_mgmt_driver + else: + LOG.error('The hash verification of VNF Package MgmtDriver ' + 'and Tacker MgmtDriver does not match.') + raise exceptions.MgmtDriverHashMatchFailure() + + def _load_vnf_interface(self, context, method_name, + vnf_instance, vnfd_dict): + VNF_value = vnfd_dict['topology_template']['node_templates']['VNF'] + tacker_mgmt_driver = DEFAULT_VNFLCM_MGMT_DRIVER + interfaces_vnflcm_value = \ + VNF_value.get('interfaces', {}).get('Vnflcm', {}) + if not interfaces_vnflcm_value: + return tacker_mgmt_driver + artifacts_value = VNF_value.get('artifacts') + if not artifacts_value: + return tacker_mgmt_driver + vnf_package_path = vnflcm_utils._get_vnf_package_path( + context, vnf_instance.vnfd_id) + + if interfaces_vnflcm_value.get(method_name): + 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) + + return tacker_mgmt_driver + @log.log def instantiate_vnf(self, context, vnf_instance, vnf_dict, instantiate_vnf_req): @@ -394,9 +474,26 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): vim_connection_info = objects.VimConnectionInfo.obj_from_primitive( vim_info, context) + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, instantiate_vnf_req.flavour_id) + + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'instantiate_start', vnf_instance, vnfd_dict), + 'instantiate_start', context=context, + vnf_instance=vnf_instance, + additional_params=instantiate_vnf_req.additional_params) + self._instantiate_vnf(context, vnf_instance, vnf_dict, vim_connection_info, instantiate_vnf_req) + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'instantiate_end', vnf_instance, vnfd_dict), + 'instantiate_end', context=context, + vnf_instance=vnf_instance, + additional_params=instantiate_vnf_req.additional_params) + @log.log @revert_to_error_task_state def terminate_vnf(self, context, vnf_instance, terminate_vnf_req): @@ -407,6 +504,16 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): vim_connection_info = objects.VimConnectionInfo.obj_from_primitive( vim_info, context) + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, + vnf_instance.instantiated_vnf_info.flavour_id) + + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'terminate_start', vnf_instance, vnfd_dict), + 'terminate_start', context=context, + vnf_instance=vnf_instance, + additional_params=terminate_vnf_req.additional_params) LOG.info("Terminating vnf %s", vnf_instance.id) try: self._delete_vnf_instance_resources(context, vnf_instance, @@ -422,6 +529,12 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): LOG.error("Unable to terminate vnf '%s' instance. " "Error: %s", vnf_instance.id, encodeutils.exception_to_unicode(exp)) + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'terminate_end', vnf_instance, vnfd_dict), + 'terminate_end', context=context, + vnf_instance=vnf_instance, + additional_params=terminate_vnf_req.additional_params) def _delete_vnf_instance_resources(self, context, vnf_instance, vim_connection_info, terminate_vnf_req=None, @@ -578,6 +691,17 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): vim_connection_info = objects.VimConnectionInfo.obj_from_primitive( vim_info, context) + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, + vnf_instance.instantiated_vnf_info.flavour_id) + + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'heal_start', vnf_instance, vnfd_dict), + 'heal_start', context=context, + vnf_instance=vnf_instance, + additional_params=heal_vnf_request.additional_params) + if not heal_vnf_request.vnfc_instance_id: self._respawn_vnf(context, vnf_instance, vnf_dict, vim_connection_info, heal_vnf_request) @@ -587,6 +711,12 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): LOG.info("Request received for healing vnf '%s' is completed " "successfully", vnf_instance.id) + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'heal_end', vnf_instance, vnfd_dict), + 'heal_end', context=context, + vnf_instance=vnf_instance, + additional_params=heal_vnf_request.additional_params) def _scale_vnf_pre(self, context, vnf_info, vnf_instance, scale_vnf_request, vim_connection_info): @@ -600,15 +730,10 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): grp_id = None vnf_info['policy_name'] = scale_vnf_request.aspect_id if scale_vnf_request.type == 'SCALE_IN': - vnfd_yaml = vnf_info['vnfd']['attributes'].get( - 'vnfd_' + vnf_instance.instantiated_vnf_info.flavour_id, '') - vnfd_dict = yaml.safe_load(vnfd_yaml) - # mgmt_driver from vnfd - vnf_node = self._get_node_template_for_vnf(vnfd_dict) - if vnf_node and vnf_node.get('interfaces'): - if vnf_node['interfaces']['Vnflcm']['scale_start']: - vnf_info['vnfd']['mgmt_driver'] = \ - vnf_node['interfaces']['Vnflcm']['scale_start'] + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, + vnf_instance.instantiated_vnf_info.flavour_id) + vnf_info['action'] = 'in' scale_id_list, scale_name_list, grp_id, res_num = \ self._vnf_manager.invoke( @@ -627,21 +752,13 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): vnf_info['res_num'] = res_num # mgmt_driver pre - if len(scale_id_list) != 0 and vnf_info['vnfd'].get('mgmt_driver'): - if len(scale_id_list) > 1: - stack_value = [] - stack_value = scale_id_list - else: - stack_value = scale_id_list[0] - kwargs = { - mgmt_constants.KEY_ACTION: - mgmt_constants.ACTION_SCALE_IN_VNF, - mgmt_constants.KEY_KWARGS: - {'vnf': vnf_info}, - mgmt_constants.KEY_SCALE: - stack_value, - } - self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs) + if len(scale_id_list) != 0: + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'scale_start', vnf_instance, vnfd_dict), + 'scale_start', context=context, + vnf_instance=vnf_instance, + additional_params=scale_vnf_request.additional_params) else: vnf_info['action'] = 'out' scale_id_list = self._vnf_manager.invoke( @@ -672,18 +789,10 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): vnf_lcm_op_occ = vnf_info['vnf_lcm_op_occ'] vnf_lcm_op_occ.error_point = 6 if scale_vnf_request.type == 'SCALE_OUT': - vnfd_yaml =\ - vnf_info['vnfd']['attributes'].\ - get('vnfd_' + vnf_instance.instantiated_vnf_info.flavour_id, - '') - vnf_info['policy_name'] = scale_vnf_request.aspect_id - vnfd_dict = yaml.safe_load(vnfd_yaml) - # mgmt_driver from vnfd - vnf_node = self._get_node_template_for_vnf(vnfd_dict) - if vnf_node and vnf_node.get('interfaces'): - if vnf_node['interfaces']['Vnflcm']['scale_end']: - vnf_info['vnfd']['mgmt_driver'] = \ - vnf_node['interfaces']['Vnflcm']['scale_end'] + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, + vnf_instance.instantiated_vnf_info.flavour_id) + scale_id_after = self._vnf_manager.invoke( vim_connection_info.vim_type, 'get_scale_ids', @@ -696,21 +805,13 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): id_list = [] id_list = list(set(scale_id_after) - set(scale_id_list)) vnf_info['res_num'] = len(scale_id_after) - if len(id_list) != 0 and vnf_info['vnfd'].get('mgmt_driver'): - if len(id_list) > 1: - stack_value = [] - stack_value = id_list - else: - stack_value = id_list[0] - kwargs = { - mgmt_constants.KEY_ACTION: - mgmt_constants.ACTION_SCALE_OUT_VNF, - mgmt_constants.KEY_KWARGS: - {'vnf': vnf_info}, - mgmt_constants.KEY_SCALE: - stack_value, - } - self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs) + if len(id_list) != 0: + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'scale_end', vnf_instance, vnfd_dict), + 'scale_end', context=context, + vnf_instance=vnf_instance, + additional_params=scale_vnf_request.additional_params) vnf_lcm_op_occ.error_point = 7 vnf_instance.instantiated_vnf_info.scale_level =\ vnf_info['after_scale_level'] @@ -1214,57 +1315,32 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): ) if vnf_lcm_op_occs.error_point == 7: if vnf_lcm_op_occs.operation == 'SCALE': - vnfd_yaml = vnf_info['vnfd']['attributes'].\ - get('vnfd_' + - vnf_instance.instantiated_vnf_info.flavour_id, '') - vnfd_dict = yaml.safe_load(vnfd_yaml) - # mgmt_driver from vnfd - vnf_node = self._get_node_template_for_vnf(vnfd_dict) - if vnf_node and vnf_node.get('interfaces'): - if vnf_node['interfaces'].get('Vnflcm'): - if vnf_node['interfaces']['Vnflcm'].get('scale_start'): - vnf_info['vnfd']['mgmt_driver'] = \ - vnf_node['interfaces']['Vnflcm']['scale_start'] + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, + vnf_instance.instantiated_vnf_info.flavour_id) + vnf_info['action'] = 'in' - if len(scale_id_list) != 0 and vnf_info['vnfd'].get( - 'mgmt_driver'): - if len(scale_id_list) > 1: - stack_value = [] - stack_value = scale_id_list - else: - stack_value = scale_id_list[0] - kwargs = { - mgmt_constants.KEY_ACTION: - mgmt_constants.ACTION_SCALE_IN_VNF, - mgmt_constants.KEY_KWARGS: - {'vnf': vnf_info}, - mgmt_constants.KEY_SCALE: - stack_value, - } - self._rollback_mgmt_call(context, vnf_info, kwargs) + if len(scale_id_list) != 0: + self._mgmt_manager.invoke( + self._load_vnf_interface(context, 'scale_start', + vnf_instance, vnfd_dict), + 'scale_start', context=context, + vnf_instance=vnf_instance, + additional_params=scale_vnf_request.additional_params) else: - vnfd_yaml = vnf_info['vnfd']['attributes'].\ - get('vnfd_' + - vnf_instance.instantiated_vnf_info.flavour_id, '') - vnfd_dict = yaml.safe_load(vnfd_yaml) - # mgmt_driver from vnfd - vnf_node = self._get_node_template_for_vnf(vnfd_dict) - if vnf_node and vnf_node.get('interfaces'): - if vnf_node['interfaces'].get('Vnflcm'): - if vnf_node['interfaces']['Vnflcm'].get( - 'termination_start'): - vnf_info['vnfd']['mgmt_driver'] = vnf_node[ - 'interfaces']['Vnflcm']['termination_start'] - if len(scale_id_list) != 0 and vnf_info['vnfd'].get( - 'mgmt_driver'): - kwargs = { - mgmt_constants.KEY_ACTION: - mgmt_constants.ACTION_DELETE_VNF, - mgmt_constants.KEY_KWARGS: - {'vnf': vnf_info} - } - self._rollback_mgmt_call(context, vnf_info, kwargs) + vnfd_dict = vnflcm_utils._get_vnfd_dict( + context, vnf_instance.vnfd_id, + vnf_instance.instantiated_vnf_info.flavour_id) + + if len(scale_id_list) != 0: + self._mgmt_manager.invoke( + self._load_vnf_interface( + context, 'terminate_start', + vnf_instance, vnfd_dict), + 'terminate_start', context=context, + vnf_instance=vnf_instance, + additional_params=scale_vnf_request.additional_params) vnf_lcm_op_occs.error_point = 6 return scale_name_list, grp_id @@ -1336,9 +1412,6 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): def _update_vnf_rollback_status_err(self, context, vnf_info): self._vnfm_plugin.update_vnf_rollback_status_err(context, vnf_info) - def _rollback_mgmt_call(self, context, vnf_info, kwargs): - self._vnfm_plugin.mgmt_call(context, vnf_info, kwargs) - def _rollback_vnf_post( self, context, diff --git a/tacker/vnfm/mgmt_drivers/vnflcm_abstract_driver.py b/tacker/vnfm/mgmt_drivers/vnflcm_abstract_driver.py new file mode 100644 index 000000000..ee79c6026 --- /dev/null +++ b/tacker/vnfm/mgmt_drivers/vnflcm_abstract_driver.py @@ -0,0 +1,77 @@ +# Copyright (C) 2020 FUJITSU +# 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. + +import abc + +from oslo_log import log as logging + + +LOG = logging.getLogger(__name__) + + +class VnflcmMgmtAbstractDriver(metaclass=abc.ABCMeta): + @abc.abstractmethod + def get_type(self): + """Return one of predefined type of the hosting vnf drivers.""" + pass + + @abc.abstractmethod + def get_name(self): + """Return a symbolic name for the service VM plugin.""" + pass + + @abc.abstractmethod + def get_description(self): + pass + + @abc.abstractmethod + def instantiate_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def instantiate_end(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def terminate_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def terminate_end(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def scale_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def scale_end(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def heal_start(self, context, vnf_instance, + additional_params, **kwargs): + pass + + @abc.abstractmethod + def heal_end(self, context, vnf_instance, + additional_params, **kwargs): + pass diff --git a/tacker/vnfm/mgmt_drivers/vnflcm_noop.py b/tacker/vnfm/mgmt_drivers/vnflcm_noop.py new file mode 100644 index 000000000..6e520aa9f --- /dev/null +++ b/tacker/vnfm/mgmt_drivers/vnflcm_noop.py @@ -0,0 +1,68 @@ +# Copyright (C) 2020 FUJITSU +# 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/test-requirements.txt b/test-requirements.txt index cf804f489..fe0fc3db9 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -20,3 +20,4 @@ WebTest>=2.0.27 # MIT python-barbicanclient>=4.5.2 # Apache-2.0 python-blazarclient>=1.0.1 # Apache-2.0 requests-mock>=1.2.0 # Apache-2.0 +PyMySQL>=0.10.1 # MIT