# Copyright 2022 Infinidat Ltd. # 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. """Unit tests for INFINIDAT InfiniBox volume driver.""" import collections import copy import functools import itertools import platform import socket from unittest import mock import uuid import ddt from oslo_utils import units from cinder import exception from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import test from cinder import version from cinder.volume import configuration from cinder.volume.drivers import infinidat TEST_LUN = 1 TEST_WWN_1 = '00:11:22:33:44:55:66:77' TEST_WWN_2 = '11:11:22:33:44:55:66:77' TEST_IP_ADDRESS1 = '1.1.1.1' TEST_IP_ADDRESS2 = '2.2.2.2' TEST_IP_ADDRESS3 = '3.3.3.3' TEST_IP_ADDRESS4 = '4.4.4.4' TEST_INITIATOR_IQN = 'iqn.2012-07.org.initiator:01' TEST_INITIATOR_IQN2 = 'iqn.2012-07.org.initiator:02' TEST_TARGET_IQN = 'iqn.2012-07.org.target:01' TEST_ISCSI_TCP_PORT1 = 3261 TEST_ISCSI_TCP_PORT2 = 3262 TEST_ISCSI_NAMESPACE1 = 'netspace1' TEST_ISCSI_NAMESPACE2 = 'netspace2' TEST_TARGET_PORTAL1 = '{}:{}'.format(TEST_IP_ADDRESS1, TEST_ISCSI_TCP_PORT1) TEST_TARGET_PORTAL2 = '{}:{}'.format(TEST_IP_ADDRESS2, TEST_ISCSI_TCP_PORT1) TEST_TARGET_PORTAL3 = '{}:{}'.format(TEST_IP_ADDRESS3, TEST_ISCSI_TCP_PORT2) TEST_TARGET_PORTAL4 = '{}:{}'.format(TEST_IP_ADDRESS4, TEST_ISCSI_TCP_PORT2) TEST_FC_PROTOCOL = 'fc' TEST_ISCSI_PROTOCOL = 'iscsi' TEST_VOLUME_SOURCE_NAME = 'test-volume' TEST_VOLUME_TYPE = 'MASTER' TEST_VOLUME_SOURCE_ID = 12345 TEST_VOLUME_METADATA = {'cinder_id': fake.VOLUME_ID} TEST_SNAPSHOT_SOURCE_NAME = 'test-snapshot' TEST_SNAPSHOT_SOURCE_ID = 67890 TEST_SNAPSHOT_METADATA = {'cinder_id': fake.SNAPSHOT_ID} TEST_POOL_NAME = 'pool' TEST_POOL_NAME2 = 'pool2' TEST_SYSTEM_SERIAL = 123 TEST_SYSTEM_SERIAL2 = 456 test_volume = mock.Mock(id=fake.VOLUME_ID, name_id=fake.VOLUME_ID, size=1, volume_type_id=fake.VOLUME_TYPE_ID, group_id=None, multiattach=False, volume_attachment=None) test_volume2 = mock.Mock(id=fake.VOLUME2_ID, name_id=fake.VOLUME2_ID, size=1, volume_type_id=None, group_id=None, multiattach=False, volume_attachment=None) test_volume3 = mock.Mock(id=fake.VOLUME3_ID, name_id=fake.VOLUME3_ID, size=1, volume_type_id=fake.VOLUME_TYPE_ID, group_id=fake.GROUP_ID, multiattach=True, volume_attachment=None) test_snapshot = mock.Mock(id=fake.SNAPSHOT_ID, volume=test_volume) test_clone = mock.Mock(id=fake.VOLUME4_ID, name_id=fake.VOLUME4_ID, size=1, volume_type_id=fake.VOLUME_TYPE_ID, group_id=None, multiattach=False, volume_attachment=None) test_group = mock.Mock(id=fake.GROUP_ID) test_snapgroup = mock.Mock(id=fake.GROUP_SNAPSHOT_ID, group=test_group) test_connector = dict(wwpns=[TEST_WWN_1], initiator=TEST_INITIATOR_IQN) test_connector2 = dict(wwpns=[TEST_WWN_2], initiator=TEST_INITIATOR_IQN2) test_connector3 = dict(wwpns=None, initiator=None) test_attachment1 = mock.Mock(connector=test_connector) test_attachment2 = mock.Mock(connector=test_connector2) test_attachment3 = mock.Mock(connector=None) def skip_driver_setup(func): @functools.wraps(func) def f(*args, **kwargs): return func(*args, **kwargs) f.__skip_driver_setup = True return f class FakeInfinisdkException(Exception): pass class InfiniboxDriverTestCaseBase(test.TestCase): def _test_skips_driver_setup(self): test_method_name = self.id().split('.')[-1] test_method = getattr(self, test_method_name) return getattr(test_method, '__skip_driver_setup', False) def setUp(self): super(InfiniboxDriverTestCaseBase, self).setUp() self.configuration = configuration.Configuration(None) self.configuration.append_config_values(infinidat.infinidat_opts) self.override_config('san_ip', 'infinibox', configuration.SHARED_CONF_GROUP) self.override_config('san_login', 'user', configuration.SHARED_CONF_GROUP) self.override_config('san_password', 'password', configuration.SHARED_CONF_GROUP) self.override_config('infinidat_pool_name', TEST_POOL_NAME) self.driver = infinidat.InfiniboxVolumeDriver( configuration=self.configuration) self._system = self._infinibox_mock() # mock external library dependencies infinisdk = self.patch("cinder.volume.drivers.infinidat.infinisdk") capacity = self.patch("cinder.volume.drivers.infinidat.capacity") self._log = self.patch("cinder.volume.drivers.infinidat.LOG") self._iqn = self.patch("cinder.volume.drivers.infinidat.iqn") self._wwn = self.patch("cinder.volume.drivers.infinidat.wwn") self._wwn.WWN = mock.Mock self._iqn.IQN = mock.Mock capacity.byte = 1 capacity.GiB = units.Gi infinisdk.core.exceptions.InfiniSDKException = FakeInfinisdkException infinisdk.InfiniBox.return_value = self._system if not self._test_skips_driver_setup(): self.driver.do_setup(None) def _infinibox_mock(self): result = mock.Mock() self._mock_volume = mock.Mock() self._mock_new_volume = mock.Mock() self._mock_volume.get_id.return_value = TEST_VOLUME_SOURCE_ID self._mock_volume.get_name.return_value = TEST_VOLUME_SOURCE_NAME self._mock_volume.get_type.return_value = TEST_VOLUME_TYPE self._mock_volume.get_pool_name.return_value = TEST_POOL_NAME self._mock_volume.get_size.return_value = 1 * units.Gi self._mock_volume.has_children.return_value = False self._mock_volume.get_qos_policy.return_value = None self._mock_volume.get_logical_units.return_value = [] self._mock_volume.get_all_metadata.return_value = {} self._mock_volume.create_snapshot.return_value = self._mock_volume self._mock_snapshot = mock.Mock() self._mock_snapshot.get_parent.return_value = self._mock_volume self._mock_host = mock.Mock() self._mock_host.get_luns.return_value = [] self._mock_host.map_volume().get_lun.return_value = TEST_LUN self._mock_pool = mock.Mock() self._mock_pool.get_free_physical_capacity.return_value = units.Gi self._mock_pool.get_physical_capacity.return_value = units.Gi self._mock_pool.get_volumes.return_value = [self._mock_volume] self._mock_name_space1 = mock.Mock() self._mock_name_space2 = mock.Mock() self._mock_name_space1.get_ips.return_value = [ mock.Mock(ip_address=TEST_IP_ADDRESS1, enabled=True)] self._mock_name_space2.get_ips.return_value = [ mock.Mock(ip_address=TEST_IP_ADDRESS3, enabled=True)] self._mock_name_space1.get_properties.return_value = mock.Mock( iscsi_iqn=TEST_TARGET_IQN, iscsi_tcp_port=TEST_ISCSI_TCP_PORT1) self._mock_name_space2.get_properties.return_value = mock.Mock( iscsi_iqn=TEST_TARGET_IQN, iscsi_tcp_port=TEST_ISCSI_TCP_PORT2) self._mock_group = mock.Mock() self._mock_qos_policy = mock.Mock() result.volumes.safe_get.return_value = self._mock_volume result.volumes.create.return_value = self._mock_volume result.pools.safe_get.return_value = self._mock_pool result.hosts.safe_get.return_value = self._mock_host result.cons_groups.safe_get.return_value = self._mock_group result.cons_groups.create.return_value = self._mock_group result.hosts.create.return_value = self._mock_host result.network_spaces.safe_get.return_value = self._mock_name_space1 result.components.nodes.get_all.return_value = [] result.qos_policies.create.return_value = self._mock_qos_policy result.qos_policies.safe_get.return_value = None result.get_serial.return_value = TEST_SYSTEM_SERIAL return result def _raise_infinisdk(self, *args, **kwargs): raise FakeInfinisdkException() @ddt.ddt class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase): def _generate_mock_object_metadata(self, cinder_object): return {"system": "openstack", "openstack_version": version.version_info.release_string(), "cinder_id": cinder_object.id, "cinder_name": cinder_object.name, "host.created_by": infinidat._INFINIDAT_CINDER_IDENTIFIER} def _validate_object_metadata(self, infinidat_object, cinder_object): infinidat_object.set_metadata_from_dict.assert_called_once_with( self._generate_mock_object_metadata(cinder_object)) def _generate_mock_host_metadata(self): return {"system": "openstack", "openstack_version": version.version_info.release_string(), "hostname": socket.gethostname(), "platform": platform.platform(), "host.created_by": infinidat._INFINIDAT_CINDER_IDENTIFIER} def _validate_host_metadata(self): self._mock_host.set_metadata_from_dict.assert_called_once_with( self._generate_mock_host_metadata()) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_get_oslo_driver_opts') def test_get_driver_options(self, _get_oslo_driver_opts): _get_oslo_driver_opts.return_value = [] result = self.driver.get_driver_options() actual = (infinidat.infinidat_opts) self.assertEqual(actual, result) @skip_driver_setup def test__setup_and_get_system_object(self): # This test should skip the driver setup, as it generates more calls to # the add_auto_retry, set_source_identifier and login methods: auth = (self.configuration.san_login, self.configuration.san_password) self.driver._setup_and_get_system_object( self.configuration.san_ip, auth) self._system.api.add_auto_retry.assert_called_once() self._system.api.set_source_identifier.assert_called_once_with( infinidat._INFINIDAT_CINDER_IDENTIFIER) self._system.login.assert_called_once() @skip_driver_setup @mock.patch('cinder.volume.drivers.infinidat.infinisdk', None) def test_do_setup_no_infinisdk(self): self.assertRaises(exception.VolumeDriverException, self.driver.do_setup, None) @mock.patch('cinder.volume.drivers.infinidat.infinisdk.InfiniBox') @ddt.data(True, False) def test_ssl_options(self, use_ssl, infinibox): auth = (self.configuration.san_login, self.configuration.san_password) self.override_config('driver_use_ssl', use_ssl) self.driver.do_setup(None) infinibox.assert_called_once_with(self.configuration.san_ip, auth=auth, use_ssl=use_ssl) def test_create_export_snapshot(self): self.assertIsNone(self.driver.create_export_snapshot( None, test_snapshot, test_connector)) def test_remove_export_snapshot(self): self.assertIsNone(self.driver.remove_export_snapshot( None, test_snapshot)) def test_backup_use_temp_snapshot(self): self.assertTrue(self.driver.backup_use_temp_snapshot()) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_get_infinidat_snapshot') def test_initialize_connection_snapshot(self, get_snapshot): result = self.driver.initialize_connection_snapshot( test_snapshot, test_connector) get_snapshot.assert_called_once_with(test_snapshot) self.assertEqual(1, result["data"]["target_lun"]) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_get_infinidat_volume') def test_initialize_connection(self, get_volume): self._system.hosts.safe_get.return_value = None result = self.driver.initialize_connection(test_volume, test_connector) get_volume.assert_called_once_with(test_volume) self.assertEqual(1, result["data"]["target_lun"]) def test_initialize_connection_host_exists(self): result = self.driver.initialize_connection(test_volume, test_connector) self.assertEqual(1, result["data"]["target_lun"]) def test_initialize_connection_mapping_exists(self): mock_mapping = mock.Mock() mock_mapping.get_volume.return_value = self._mock_volume mock_mapping.get_lun.return_value = 888 self._mock_host.get_luns.return_value = [mock_mapping] result = self.driver.initialize_connection(test_volume, test_connector) self.assertEqual(888, result["data"]["target_lun"]) def test_initialize_connection_mapping_not_found(self): mock_mapping = mock.Mock() mock_mapping.get_volume.return_value = None self._mock_host.get_luns.return_value = [mock_mapping] result = self.driver.initialize_connection(test_volume, test_connector) self.assertEqual(TEST_LUN, result["data"]["target_lun"]) def test_initialize_connection_volume_doesnt_exist(self): self._system.volumes.safe_get.return_value = None self.assertRaises(exception.VolumeNotFound, self.driver.initialize_connection, test_volume, test_connector) def test_initialize_connection_create_fails(self): self._system.hosts.safe_get.return_value = None self._system.hosts.create.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.initialize_connection, test_volume, test_connector) def test_initialize_connection_map_fails(self): self._mock_host.map_volume.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.initialize_connection, test_volume, test_connector) def test_initialize_connection_metadata(self): self._system.hosts.safe_get.return_value = None self.driver.initialize_connection(test_volume, test_connector) self._validate_host_metadata() @ddt.data({'connector': None, 'multiattach': True, 'attachment': [test_attachment1, test_attachment1]}, {'connector': test_connector3, 'multiattach': True, 'attachment': [test_attachment1, test_attachment1]}, {'connector': test_connector, 'multiattach': False, 'attachment': [test_attachment1]}, {'connector': test_connector, 'multiattach': True, 'attachment': None}, {'connector': test_connector, 'multiattach': True, 'attachment': [test_attachment2, test_attachment3]}) @ddt.unpack def test__is_volume_multiattached_negative(self, connector, multiattach, attachment): volume = copy.deepcopy(test_volume) volume.multiattach = multiattach volume.volume_attachment = attachment self.assertFalse(self.driver._is_volume_multiattached(volume, connector)) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_terminate_connection') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_get_infinidat_volume') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_is_volume_multiattached') def test_terminate_connection(self, volume_multiattached, get_volume, terminate_connection): volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1] volume_multiattached.return_value = False get_volume.return_value = self._mock_volume self.assertFalse(self.driver.terminate_connection(volume, test_connector)) volume_multiattached.assert_called_once_with(volume, test_connector) get_volume.assert_called_once_with(volume) terminate_connection.assert_called_once_with(self._mock_volume, test_connector) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_terminate_connection') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_get_infinidat_snapshot') def test_terminate_connection_snapshot(self, get_snapshot, terminate_connection): get_snapshot.return_value = self._mock_snapshot self.assertIsNone(self.driver.terminate_connection_snapshot( test_snapshot, test_connector)) get_snapshot.assert_called_once_with(test_snapshot) terminate_connection.assert_called_once_with(self._mock_snapshot, test_connector) def test_terminate_connection_delete_host(self): self._mock_host.get_luns.return_value = [object()] volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1] self.assertFalse(self.driver.terminate_connection(volume, test_connector)) self.assertEqual(0, self._mock_host.safe_delete.call_count) self._mock_host.get_luns.return_value = [] self.assertFalse(self.driver.terminate_connection(volume, test_connector)) self.assertEqual(1, self._mock_host.safe_delete.call_count) def test_terminate_connection_volume_doesnt_exist(self): self._system.volumes.safe_get.return_value = None self.assertRaises(exception.VolumeNotFound, self.driver.terminate_connection, test_volume, test_connector) def test_terminate_connection_api_fail(self): self._mock_host.unmap_volume.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.terminate_connection, test_volume, test_connector) def test_get_volume_stats_refreshes(self): result = self.driver.get_volume_stats() self.assertEqual(1, result["free_capacity_gb"]) # change the "free space" in the pool self._mock_pool.get_free_physical_capacity.return_value = 0 # no refresh - free capacity should stay the same result = self.driver.get_volume_stats(refresh=False) self.assertEqual(1, result["free_capacity_gb"]) # refresh - free capacity should change to 0 result = self.driver.get_volume_stats(refresh=True) self.assertEqual(0, result["free_capacity_gb"]) def test_get_volume_stats_pool_not_found(self): self._system.pools.safe_get.return_value = None self.assertRaises(exception.VolumeDriverException, self.driver.get_volume_stats) def test_get_volume_stats_max_over_subscription_ratio(self): self.override_config('san_thin_provision', True) self.override_config('max_over_subscription_ratio', 10.0) result = self.driver.get_volume_stats() self.assertEqual('10.0', result['max_over_subscription_ratio']) self.assertTrue(result['thin_provisioning_support']) self.assertFalse(result['thick_provisioning_support']) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume(self, *mocks): self.driver.create_volume(test_volume) def test_create_volume_pool_not_found(self): self._system.pools.safe_get.return_value = None self.assertRaises(exception.VolumeDriverException, self.driver.create_volume, test_volume) def test_create_volume_api_fail(self): self._system.pools.safe_get.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_volume, test_volume) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume_metadata(self, *mocks): self.driver.create_volume(test_volume) self._validate_object_metadata(self._mock_volume, test_volume) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume_compression_enabled(self, *mocks): self.override_config('infinidat_use_compression', True) self.driver.create_volume(test_volume) self.assertTrue( self._system.volumes.create.call_args[1]["compression_enabled"] ) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume_compression_not_enabled(self, *mocks): self.override_config('infinidat_use_compression', False) self.driver.create_volume(test_volume) self.assertFalse( self._system.volumes.create.call_args[1]["compression_enabled"] ) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume_compression_not_available(self, *mocks): self._system.compat.has_compression.return_value = False self.driver.create_volume(test_volume) self.assertNotIn( "compression_enabled", self._system.volumes.create.call_args[1] ) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.volume_utils.group_get_by_id') @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_volume_within_group(self, *mocks): self.driver.create_volume(test_volume3) self._mock_group.add_member.assert_called_once() @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.volume_utils.group_get_by_id') @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_create_volume_within_no_cg_group(self, *mocks): self.driver.create_volume(test_volume3) self._mock_group.add_member.assert_not_called() def test_delete_volume(self): self.driver.delete_volume(test_volume) def test_delete_volume_doesnt_exist(self): self._system.volumes.safe_get.return_value = None # should not raise an exception self.driver.delete_volume(test_volume) def test_delete_volume_with_children(self): self._mock_volume.has_children.return_value = True self.assertRaises(exception.VolumeIsBusy, self.driver.delete_volume, test_volume) def test_extend_volume(self): self.driver.extend_volume(test_volume, 2) self._mock_volume.resize.assert_called_with(1 * units.Gi) def test_extend_volume_api_fail(self): self._mock_volume.resize.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.extend_volume, test_volume, 2) def test_create_snapshot(self): self.driver.create_snapshot(test_snapshot) def test_create_snapshot_metadata(self): self._mock_volume.create_snapshot.return_value = self._mock_volume self.driver.create_snapshot(test_snapshot) self._validate_object_metadata(self._mock_volume, test_snapshot) def test_create_snapshot_volume_doesnt_exist(self): self._system.volumes.safe_get.return_value = None self.assertRaises(exception.VolumeNotFound, self.driver.create_snapshot, test_snapshot) def test_create_snapshot_api_fail(self): self._mock_volume.create_snapshot.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_snapshot, test_snapshot) @mock.patch("cinder.volume.volume_utils.copy_volume") @mock.patch("cinder.volume.volume_utils.brick_get_connector") @mock.patch("cinder.volume.volume_utils.brick_get_connector_properties", return_value=test_connector) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume_from_snapshot(self, *mocks): self.driver.create_volume_from_snapshot(test_clone, test_snapshot) def test_create_volume_from_snapshot_doesnt_exist(self): self._system.volumes.safe_get.return_value = None self.assertRaises(exception.SnapshotNotFound, self.driver.create_volume_from_snapshot, test_clone, test_snapshot) def test_create_volume_from_snapshot_create_fails(self): self._system.volumes.create.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_volume_from_snapshot, test_clone, test_snapshot) @mock.patch("cinder.volume.volume_utils.brick_get_connector_properties", return_value=test_connector) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_volume_from_snapshot_map_fails(self, *mocks): self._mock_host.map_volume.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_volume_from_snapshot, test_clone, test_snapshot) @mock.patch('cinder.volume.volume_utils.brick_get_connector') @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.volume_utils.brick_get_connector_properties') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_connect_device') def test_create_volume_from_snapshot_connect_fails(self, connect_device, connector_properties, *mocks): connector_properties.return_value = test_connector connect_device.side_effect = exception.DeviceUnavailable( path='/dev/sdb', reason='Block device required') self.assertRaises(exception.DeviceUnavailable, self.driver.create_volume_from_snapshot, test_clone, test_snapshot) def test_delete_snapshot(self): self.driver.delete_snapshot(test_snapshot) def test_delete_snapshot_doesnt_exist(self): self._system.volumes.safe_get.return_value = None # should not raise an exception self.driver.delete_snapshot(test_snapshot) def test_delete_snapshot_api_fail(self): self._mock_volume.safe_delete.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.delete_snapshot, test_snapshot) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' 'delete_snapshot') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' 'create_volume_from_snapshot') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' 'create_snapshot') @mock.patch('uuid.uuid4') def test_create_cloned_volume(self, mock_uuid, create_snapshot, create_volume_from_snapshot, delete_snapshot): mock_uuid.return_value = uuid.UUID(test_snapshot.id) snapshot_attributes = ('id', 'name', 'volume') Snapshot = collections.namedtuple('Snapshot', snapshot_attributes) snapshot_id = test_snapshot.id snapshot_name = self.configuration.snapshot_name_template % snapshot_id snapshot = Snapshot(id=snapshot_id, name=snapshot_name, volume=test_volume) self.driver.create_cloned_volume(test_clone, test_volume) create_snapshot.assert_called_once_with(snapshot) create_volume_from_snapshot.assert_called_once_with(test_clone, snapshot) delete_snapshot.assert_called_once_with(snapshot) def test_create_cloned_volume_create_fails(self): self._system.volumes.create.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_cloned_volume, test_clone, test_volume) @mock.patch("cinder.volume.volume_utils.brick_get_connector_properties", return_value=test_connector) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_cloned_volume_map_fails(self, *mocks): self._mock_host.map_volume.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_cloned_volume, test_clone, test_volume) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group(self, *mocks): self.driver.create_group(None, test_group) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_create_generic_group(self, *mocks): self.assertRaises(NotImplementedError, self.driver.create_group, None, test_group) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group_metadata(self, *mocks): self.driver.create_group(None, test_group) self._validate_object_metadata(self._mock_group, test_group) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group_twice(self, *mocks): self.driver.create_group(None, test_group) self.driver.create_group(None, test_group) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group_api_fail(self, *mocks): self._system.cons_groups.create.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_group, None, test_group) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group(self, *mocks): self.driver.delete_group(None, test_group, [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_delete_generic_group(self, *mocks): self.assertRaises(NotImplementedError, self.driver.delete_group, None, test_group, [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group_doesnt_exist(self, *mocks): self._system.cons_groups.safe_get.return_value = None self.driver.delete_group(None, test_group, [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group_api_fail(self, *mocks): self._mock_group.safe_delete.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.delete_group, None, test_group, [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_update_group_add_and_remove(self, *mocks): self.driver.update_group(None, test_group, [test_volume], [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_update_generic_group_add_and_remove(self, *mocks): self.assertRaises(NotImplementedError, self.driver.update_group, None, test_group, [test_volume], [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_update_group_api_fail(self, *mocks): self._mock_group.add_member.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.update_group, None, test_group, [test_volume], [test_volume]) @mock.patch("cinder.volume.volume_utils.copy_volume") @mock.patch("cinder.volume.volume_utils.brick_get_connector") @mock.patch("cinder.volume.volume_utils.brick_get_connector_properties", return_value=test_connector) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_group_from_src_snaps(self, *mocks): self.driver.create_group_from_src(None, test_group, [test_volume], test_snapgroup, [test_snapshot], None, None) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_create_genericgroup_from_src_snaps(self, *mocks): self.assertRaises(NotImplementedError, self.driver.create_group_from_src, None, test_group, [test_volume], test_snapgroup, [test_snapshot], None, None) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group_from_empty_sources(self, *mocks): self.assertRaises(exception.InvalidInput, self.driver.create_group_from_src, None, test_group, [test_volume], None, None, None, None) @mock.patch("cinder.volume.volume_utils.copy_volume") @mock.patch("cinder.volume.volume_utils.brick_get_connector") @mock.patch("cinder.volume.volume_utils.brick_get_connector_properties", return_value=test_connector) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_create_group_from_src_vols(self, *mocks): self.driver.create_group_from_src(None, test_group, [test_volume], None, None, test_group, [test_volume]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group_snap(self, *mocks): mock_snapgroup = mock.Mock() mock_snapgroup.get_members.return_value = [self._mock_snapshot, self._mock_snapshot] self._mock_volume.get_name.side_effect = [fake.VOLUME_NAME, fake.VOLUME2_NAME] self._mock_group.create_snapshot.return_value = mock_snapgroup self.driver.create_group_snapshot(None, test_snapgroup, [test_snapshot, test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_create_generic_group_snap(self, *mocks): self.assertRaises(NotImplementedError, self.driver.create_group_snapshot, None, test_snapgroup, [test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_create_group_snap_api_fail(self, *mocks): self._mock_group.create_snapshot.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.create_group_snapshot, None, test_snapgroup, [test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group_snap(self, *mocks): self.driver.delete_group_snapshot(None, test_snapgroup, [test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=False) def test_delete_generic_group_snap(self, *mocks): self.assertRaises(NotImplementedError, self.driver.delete_group_snapshot, None, test_snapgroup, [test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group_snap_does_not_exist(self, *mocks): self._system.cons_groups.safe_get.return_value = None self.driver.delete_group_snapshot(None, test_snapgroup, [test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group_snap_invalid_group(self, *mocks): self._mock_group.is_snapgroup.return_value = False self.assertRaises(exception.InvalidGroupSnapshot, self.driver.delete_group_snapshot, None, test_snapgroup, [test_snapshot]) @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type', return_value=True) def test_delete_group_snap_api_fail(self, *mocks): self._mock_group.safe_delete.side_effect = self._raise_infinisdk self.assertRaises(exception.VolumeBackendAPIException, self.driver.delete_group_snapshot, None, test_snapgroup, [test_snapshot]) def test_snapshot_revert_use_temp_snapshot(self): result = self.driver.snapshot_revert_use_temp_snapshot() self.assertFalse(result) @ddt.data((1, 1), (1, 2)) @ddt.unpack def test_revert_to_snapshot_resize(self, volume_size, snapshot_size): volume = copy.deepcopy(test_volume) snapshot = copy.deepcopy(test_snapshot) snapshot.volume.size = snapshot_size self._system.volumes.safe_get.side_effect = [self._mock_snapshot, self._mock_volume, self._mock_volume] self._mock_volume.get_size.side_effect = [volume_size * units.Gi, volume_size * units.Gi] self.driver.revert_to_snapshot(None, volume, snapshot) self._mock_volume.restore.assert_called_once_with(self._mock_snapshot) if volume_size == snapshot_size: self._mock_volume.resize.assert_not_called() else: delta = (snapshot_size - volume_size) * units.Gi self._mock_volume.resize.assert_called_with(delta) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_by_source_name(self, *mocks): existing_ref = {'source-name': TEST_VOLUME_SOURCE_NAME} self.driver.manage_existing(test_volume, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_by_source_id(self, *mocks): existing_ref = {'source-id': TEST_VOLUME_SOURCE_ID} self.driver.manage_existing(test_volume, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_by_invalid_source(self, *mocks): existing_ref = {'source-path': None} self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing, test_volume, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.volume_utils.check_already_managed_volume', return_value=False) def test_manage_existing_not_managed(self, *mocks): self._mock_volume.get_all_metadata.return_value = ( TEST_VOLUME_METADATA) existing_ref = {'source-name': TEST_VOLUME_SOURCE_NAME} self.driver.manage_existing(test_volume, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.volume_utils.check_already_managed_volume', return_value=True) def test_manage_existing_already_managed(self, *mocks): self._mock_volume.get_all_metadata.return_value = ( TEST_VOLUME_METADATA) existing_ref = {'source-name': TEST_VOLUME_SOURCE_NAME} self.assertRaises(exception.ManageExistingAlreadyManaged, self.driver.manage_existing, test_volume, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_invalid_pool(self, *mocks): existing_ref = {'source-name': TEST_VOLUME_SOURCE_NAME} self._mock_volume.get_pool_name.return_value = TEST_POOL_NAME2 self.assertRaises(exception.InvalidConfigurationValue, self.driver.manage_existing, test_volume, existing_ref) def test_manage_existing_get_size(self): existing_ref = {'source-name': TEST_VOLUME_SOURCE_NAME} size = self.driver.manage_existing_get_size(test_volume, existing_ref) self.assertEqual(test_volume.size, size) def test_get_manageable_volumes(self): cinder_volumes = [test_volume] self._mock_volume.is_snapshot.return_value = False self._mock_volume.get_all_metadata.return_value = { 'cinder_id': fake.VOLUME2_ID } self.driver.get_manageable_volumes(cinder_volumes, None, 1, 0, [], []) def test_get_manageable_volumes_already_managed(self): cinder_volumes = [test_volume] self._mock_volume.get_id.return_value = TEST_VOLUME_SOURCE_ID self._mock_volume.get_all_metadata.return_value = ( TEST_VOLUME_METADATA) self._mock_volume.is_snapshot.return_value = False self.driver.get_manageable_volumes(cinder_volumes, None, 1, 0, [], []) def test_get_manageable_volumes_but_snapshots(self): cinder_volumes = [test_volume] self._mock_volume.is_snapshot.return_value = True self.driver.get_manageable_volumes(cinder_volumes, None, 1, 0, [], []) def test_get_manageable_volumes_has_mappings(self): cinder_volumes = [test_volume] self._mock_volume.is_snapshot.return_value = False self._mock_volume.get_all_metadata.return_value = { 'cinder_id': fake.VOLUME2_ID } lun = mock.Mock() self._mock_volume.get_logical_units.return_value = [lun] self.driver.get_manageable_volumes(cinder_volumes, None, 1, 0, [], []) def test_get_manageable_volumes_has_snapshots(self): cinder_volumes = [test_volume] self._mock_volume.is_snapshot.return_value = False self._mock_volume.has_children.return_value = True self._mock_volume.get_all_metadata.return_value = { 'cinder_id': fake.VOLUME2_ID } self.driver.get_manageable_volumes(cinder_volumes, None, 1, 0, [], []) def test_unmanage(self): self.driver.unmanage(test_volume) @mock.patch('cinder.objects.Snapshot.exists', return_value=True) def test__check_already_managed_snapshot(self, *mocks): self.driver._check_already_managed_snapshot(test_snapshot.id) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_snapshot_by_source_name(self, *mocks): existing_ref = {'source-name': TEST_SNAPSHOT_SOURCE_NAME} self.driver.manage_existing_snapshot(test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_snapshot_by_source_id(self, *mocks): existing_ref = {'source-id': TEST_SNAPSHOT_SOURCE_ID} self.driver.manage_existing_snapshot(test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_snapshot_but_volume(self, *mocks): existing_ref = {'source-id': TEST_SNAPSHOT_SOURCE_ID} self._mock_volume.is_snapshot.return_value = False self.assertRaises(exception.InvalidSnapshot, self.driver.manage_existing_snapshot, test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_snapshot_by_invalid_source(self, *mocks): existing_ref = {'source-path': None} self.assertRaises(exception.ManageExistingInvalidReference, self.driver.manage_existing_snapshot, test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_snapshot_by_non_cinder_id(self, *mocks): self._mock_volume.get_all_metadata.return_value = {'cinder_id': 'x'} existing_ref = {'source-id': TEST_SNAPSHOT_SOURCE_ID} self.driver.manage_existing_snapshot(test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_check_already_managed_snapshot', return_value=False) def test_manage_existing_snapshot_not_managed(self, *mocks): self._mock_volume.get_all_metadata.return_value = ( TEST_SNAPSHOT_METADATA) existing_ref = {'source-name': TEST_SNAPSHOT_SOURCE_NAME} self.driver.manage_existing(test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_check_already_managed_snapshot', return_value=True) def test_manage_existing_snapshot_already_managed(self, *mocks): self._mock_volume.get_all_metadata.return_value = ( TEST_SNAPSHOT_METADATA) existing_ref = {'source-name': TEST_SNAPSHOT_SOURCE_NAME} self.assertRaises(exception.ManageExistingAlreadyManaged, self.driver.manage_existing_snapshot, test_snapshot, existing_ref) @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') def test_manage_existing_snapshot_invalid_pool(self, *mocks): existing_ref = {'source-name': TEST_SNAPSHOT_SOURCE_NAME} self._mock_volume.get_pool_name.return_value = TEST_POOL_NAME2 self.assertRaises(exception.InvalidConfigurationValue, self.driver.manage_existing_snapshot, test_snapshot, existing_ref) def test_manage_existing_snapshot_get_size(self): existing_ref = {'source-name': TEST_SNAPSHOT_SOURCE_NAME} size = self.driver.manage_existing_snapshot_get_size(test_volume, existing_ref) self.assertEqual(test_snapshot.volume.size, size) def test_get_manageable_snapshots(self): cinder_snapshots = [test_snapshot] self._mock_volume.is_snapshot.return_value = True self._mock_volume.get_all_metadata.return_value = { 'cinder_id': fake.SNAPSHOT2_ID } self.driver.get_manageable_snapshots(cinder_snapshots, None, 1, 0, [], []) def test_get_manageable_snapshots_already_managed(self): cinder_snapshots = [test_snapshot] self._mock_volume.get_id.return_value = TEST_SNAPSHOT_SOURCE_ID self._mock_volume.get_all_metadata.return_value = ( TEST_SNAPSHOT_METADATA) self._mock_volume.is_snapshot.return_value = True self.driver.get_manageable_snapshots(cinder_snapshots, None, 1, 0, [], []) def test_get_manageable_snapshots_but_volumes(self): cinder_snapshots = [test_snapshot] self._mock_volume.is_snapshot.return_value = False self.driver.get_manageable_snapshots(cinder_snapshots, None, 1, 0, [], []) def test_get_manageable_snapshots_has_mappings(self): cinder_snapshots = [test_snapshot] self._mock_volume.is_snapshot.return_value = True self._mock_volume.get_all_metadata.return_value = { 'cinder_id': fake.SNAPSHOT2_ID } lun = mock.Mock() self._mock_volume.get_logical_units.return_value = [lun] self.driver.get_manageable_snapshots(cinder_snapshots, None, 1, 0, [], []) def test_get_manageable_snapshots_has_clones(self): cinder_snapshots = [test_snapshot] self._mock_volume.is_snapshot.return_value = True self._mock_volume.has_children.return_value = True self._mock_volume.get_all_metadata.return_value = { 'cinder_id': fake.SNAPSHOT2_ID } self.driver.get_manageable_snapshots(cinder_snapshots, None, 1, 0, [], []) def test_unmanage_snapshot(self): self.driver.unmanage_snapshot(test_snapshot) def test_terminate_connection_no_attachment_connector(self): volume = copy.deepcopy(test_volume) volume.multiattach = True volume.volume_attachment = [test_attachment3] self.assertFalse(self.driver.terminate_connection(volume, test_connector)) def test_terminate_connection_no_host(self): self._system.hosts.safe_get.return_value = None volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1] self.assertFalse(self.driver.terminate_connection(volume, test_connector)) def test_terminate_connection_no_mapping(self): self._mock_host.unmap_volume.side_effect = KeyError volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1] self.assertFalse(self.driver.terminate_connection(volume, test_connector)) def test_update_migrated_volume_new_volume_not_found(self): self._system.volumes.safe_get.side_effect = [ None, self._mock_volume] self.assertRaises(exception.VolumeNotFound, self.driver.update_migrated_volume, None, test_volume, test_volume2, 'available') @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_set_cinder_object_metadata') def test_update_migrated_volume_volume_not_found(self, set_metadata): self._system.volumes.safe_get.side_effect = [ self._mock_new_volume, None] update = self.driver.update_migrated_volume(None, test_volume, test_volume2, 'available') expected = {'_name_id': None, 'provider_location': None} self.assertEqual(expected, update) set_metadata.assert_called_once_with(self._mock_new_volume, test_volume) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_set_cinder_object_metadata') def test_update_migrated_new_volume_rename_error(self, set_metadata): self._system.volumes.safe_get.side_effect = [ self._mock_new_volume, None] self._mock_new_volume.update_name.side_effect = [ FakeInfinisdkException] update = self.driver.update_migrated_volume(None, test_volume, test_volume2, 'available') expected = {'_name_id': test_volume2.name_id, 'provider_location': None} self.assertEqual(expected, update) set_metadata.assert_called_once_with(self._mock_new_volume, test_volume) @mock.patch('cinder.volume.drivers.infinidat.InfiniboxVolumeDriver.' '_set_cinder_object_metadata') def test_update_migrated(self, set_metadata): self._system.volumes.safe_get.side_effect = [ self._mock_new_volume, self._mock_volume] self._mock_new_volume.update_name.side_effect = None update = self.driver.update_migrated_volume(None, test_volume, test_volume2, 'available') expected = {'_name_id': test_volume2.name_id, 'provider_location': None} self.assertEqual(expected, update) set_metadata.assert_called_once_with(self._mock_new_volume, test_volume) self.assertEqual(0, self._log.error.call_count) @ddt.data(None, {}) def test_migrate_volume_no_host(self, host): expected = False, None update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) @ddt.data(None, {}) def test_migrate_volume_no_capabilities(self, capabilities): expected = False, None host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) @ddt.data(None, 123, 'location') def test_migrate_volume_invalid_location_info(self, location_info): expected = False, None capabilities = {'location_info': location_info} host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) def test_migrate_volume_invalid_driver(self): expected = False, None location_info = 'vendor:0:/path' capabilities = {'location_info': location_info} host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) def test_migrate_volume_invalid_serial(self): expected = False, None location_info = '%s:%s:%s' % (self.driver.__class__.__name__, TEST_SYSTEM_SERIAL2, TEST_POOL_NAME2) capabilities = {'location_info': location_info} host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) def test_migrate_volume_same_pool(self): expected = True, None location_info = '%s:%s:%s' % (self.driver.__class__.__name__, TEST_SYSTEM_SERIAL, TEST_POOL_NAME) capabilities = {'location_info': location_info} host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) def test_migrate_volume_no_pool(self): expected = False, None self._system.pools.safe_get.return_value = None location_info = '%s:%s:%s' % (self.driver.__class__.__name__, TEST_SYSTEM_SERIAL, TEST_POOL_NAME2) capabilities = {'location_info': location_info} host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) def test_migrate_volume(self): expected = True, None location_info = '%s:%s:%s' % (self.driver.__class__.__name__, TEST_SYSTEM_SERIAL, TEST_POOL_NAME2) capabilities = {'location_info': location_info} host = {'capabilities': capabilities} update = self.driver.migrate_volume(None, test_volume, host) self.assertEqual(expected, update) @ddt.ddt class InfiniboxDriverTestCaseFC(InfiniboxDriverTestCaseBase): @ddt.data(*itertools.product(('UP', 'DOWN'), ('OK', 'ERROR'))) @ddt.unpack def test_initialize_connection_nodes_ports(self, link_state, port_state): node = mock.Mock() port = mock.Mock() port.get_link_state.return_value = link_state port.get_state.return_value = port_state node.get_fc_ports.return_value = [port] self._system.components.nodes.get_all.return_value = [node] result = self.driver.initialize_connection(test_volume, test_connector) self.assertEqual(1, result["data"]["target_lun"]) def test_initialize_connection_multiple_wwpns(self): connector = {'wwpns': [TEST_WWN_1, TEST_WWN_2]} result = self.driver.initialize_connection(test_volume, connector) self.assertEqual(1, result["data"]["target_lun"]) def test_validate_connector(self): fc_connector = {'wwpns': [TEST_WWN_1, TEST_WWN_2]} iscsi_connector = {'initiator': TEST_INITIATOR_IQN} self.driver.validate_connector(fc_connector) self.assertRaises(exception.InvalidConnectorException, self.driver.validate_connector, iscsi_connector) @ddt.data({'connector': test_connector, 'attachment': [test_attachment1, test_attachment1]}, {'connector': test_connector2, 'attachment': [test_attachment2, test_attachment2]}) @ddt.unpack def test__is_volume_multiattached_positive(self, connector, attachment): volume = copy.deepcopy(test_volume) volume.multiattach = True volume.volume_attachment = attachment self.assertTrue(self.driver._is_volume_multiattached(volume, connector)) def test_terminate_connection_multiattached_volume(self): volume = copy.deepcopy(test_volume) volume.multiattach = True volume.volume_attachment = [test_attachment1, test_attachment1] self.assertTrue(self.driver.terminate_connection(volume, test_connector)) def test_terminate_connection_force_detach(self): mock_infinidat_host = mock.Mock() mock_infinidat_host.get_ports.return_value = [ self._wwn.WWN(TEST_WWN_1)] mock_mapping = mock.Mock() mock_mapping.get_host.return_value = mock_infinidat_host self._mock_volume.get_logical_units.return_value = [mock_mapping] volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1, test_attachment2] self.assertTrue(self.driver.terminate_connection(volume, None)) self._mock_host.unmap_volume.assert_called_once() self._mock_host.safe_delete.assert_called_once() @ddt.ddt class InfiniboxDriverTestCaseISCSI(InfiniboxDriverTestCaseBase): def setUp(self): super(InfiniboxDriverTestCaseISCSI, self).setUp() self.override_config('infinidat_storage_protocol', TEST_ISCSI_PROTOCOL) self.override_config('infinidat_iscsi_netspaces', [TEST_ISCSI_NAMESPACE1]) self.override_config('use_chap_auth', False) self.driver.do_setup(None) def test_setup_without_netspaces_configured(self): self.override_config('infinidat_iscsi_netspaces', []) self.assertRaises(exception.VolumeDriverException, self.driver.do_setup, None) def test_initialize_connection(self): result = self.driver.initialize_connection(test_volume, test_connector) expected = { 'driver_volume_type': TEST_ISCSI_PROTOCOL, 'data': { 'target_discovered': True, 'target_portal': TEST_TARGET_PORTAL1, 'target_iqn': TEST_TARGET_IQN, 'target_lun': TEST_LUN, 'target_portals': [ TEST_TARGET_PORTAL1 ], 'target_iqns': [ TEST_TARGET_IQN ], 'target_luns': [ TEST_LUN ] } } self.assertEqual(expected, result) def test_initialize_netspace_does_not_exist(self): self._system.network_spaces.safe_get.return_value = None self.assertRaises(exception.VolumeDriverException, self.driver.initialize_connection, test_volume, test_connector) def test_initialize_netspace_has_no_ips(self): self._mock_name_space1.get_ips.return_value = [] self.assertRaises(exception.VolumeDriverException, self.driver.initialize_connection, test_volume, test_connector) def test_initialize_connection_with_chap(self): self.override_config('use_chap_auth', True) result = self.driver.initialize_connection(test_volume, test_connector) self.assertEqual(1, result['data']['target_lun']) self.assertEqual('CHAP', result['data']['auth_method']) self.assertIn('auth_username', result['data']) self.assertIn('auth_password', result['data']) def test_initialize_connection_multiple_netspaces(self): self.override_config('infinidat_iscsi_netspaces', [TEST_ISCSI_NAMESPACE1, TEST_ISCSI_NAMESPACE2]) self._system.network_spaces.safe_get.side_effect = [ self._mock_name_space1, self._mock_name_space2] result = self.driver.initialize_connection(test_volume, test_connector) expected = { 'driver_volume_type': TEST_ISCSI_PROTOCOL, 'data': { 'target_discovered': True, 'target_portal': TEST_TARGET_PORTAL1, 'target_iqn': TEST_TARGET_IQN, 'target_lun': TEST_LUN, 'target_portals': [ TEST_TARGET_PORTAL1, TEST_TARGET_PORTAL3 ], 'target_iqns': [ TEST_TARGET_IQN, TEST_TARGET_IQN ], 'target_luns': [ TEST_LUN, TEST_LUN ] } } self.assertEqual(expected, result) def test_initialize_connection_multiple_netspaces_multipath(self): self.override_config('infinidat_iscsi_netspaces', [TEST_ISCSI_NAMESPACE1, TEST_ISCSI_NAMESPACE2]) self._system.network_spaces.safe_get.side_effect = [ self._mock_name_space1, self._mock_name_space2] self._mock_name_space1.get_ips.return_value = [ mock.Mock(ip_address=TEST_IP_ADDRESS1, enabled=True), mock.Mock(ip_address=TEST_IP_ADDRESS2, enabled=True)] self._mock_name_space2.get_ips.return_value = [ mock.Mock(ip_address=TEST_IP_ADDRESS3, enabled=True), mock.Mock(ip_address=TEST_IP_ADDRESS4, enabled=True)] result = self.driver.initialize_connection(test_volume, test_connector) expected = { 'driver_volume_type': TEST_ISCSI_PROTOCOL, 'data': { 'target_discovered': True, 'target_portal': TEST_TARGET_PORTAL1, 'target_iqn': TEST_TARGET_IQN, 'target_lun': TEST_LUN, 'target_portals': [ TEST_TARGET_PORTAL1, TEST_TARGET_PORTAL2, TEST_TARGET_PORTAL3, TEST_TARGET_PORTAL4 ], 'target_iqns': [ TEST_TARGET_IQN, TEST_TARGET_IQN, TEST_TARGET_IQN, TEST_TARGET_IQN ], 'target_luns': [ TEST_LUN, TEST_LUN, TEST_LUN, TEST_LUN ] } } self.assertEqual(expected, result) def test_initialize_connection_disabled_interface(self): self._mock_name_space1.get_ips.return_value = [ mock.Mock(ip_address=TEST_IP_ADDRESS1, enabled=False), mock.Mock(ip_address=TEST_IP_ADDRESS2, enabled=True)] result = self.driver.initialize_connection(test_volume, test_connector) expected = { 'driver_volume_type': TEST_ISCSI_PROTOCOL, 'data': { 'target_discovered': True, 'target_portal': TEST_TARGET_PORTAL2, 'target_iqn': TEST_TARGET_IQN, 'target_lun': TEST_LUN, 'target_portals': [ TEST_TARGET_PORTAL2 ], 'target_iqns': [ TEST_TARGET_IQN ], 'target_luns': [ TEST_LUN ] } } self.assertEqual(expected, result) def test_initialize_connection_multiple_interfaces(self): self._mock_name_space1.get_ips.return_value = [ mock.Mock(ip_address=TEST_IP_ADDRESS1, enabled=True), mock.Mock(ip_address=TEST_IP_ADDRESS2, enabled=True)] self._mock_name_space1.get_properties.return_value = mock.Mock( iscsi_iqn=TEST_TARGET_IQN, iscsi_tcp_port=TEST_ISCSI_TCP_PORT1) result = self.driver.initialize_connection(test_volume, test_connector) expected = { 'driver_volume_type': TEST_ISCSI_PROTOCOL, 'data': { 'target_discovered': True, 'target_portal': TEST_TARGET_PORTAL1, 'target_iqn': TEST_TARGET_IQN, 'target_lun': TEST_LUN, 'target_portals': [ TEST_TARGET_PORTAL1, TEST_TARGET_PORTAL2 ], 'target_iqns': [ TEST_TARGET_IQN, TEST_TARGET_IQN ], 'target_luns': [ TEST_LUN, TEST_LUN ] } } self.assertEqual(expected, result) @ddt.data({'connector': test_connector, 'attachment': [test_attachment1, test_attachment1]}, {'connector': test_connector2, 'attachment': [test_attachment2, test_attachment2]}) @ddt.unpack def test__is_volume_multiattached_positive(self, connector, attachment): volume = copy.deepcopy(test_volume) volume.multiattach = True volume.volume_attachment = attachment self.assertTrue(self.driver._is_volume_multiattached(volume, connector)) def test_terminate_connection(self): volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1] self.assertFalse(self.driver.terminate_connection(volume, test_connector)) def test_terminate_connection_force_detach(self): mock_infinidat_host = mock.Mock() mock_infinidat_host.get_ports.return_value = [ self._iqn.IQN(TEST_TARGET_IQN)] mock_mapping = mock.Mock() mock_mapping.get_host.return_value = mock_infinidat_host self._mock_volume.get_logical_units.return_value = [mock_mapping] volume = copy.deepcopy(test_volume) volume.volume_attachment = [test_attachment1, test_attachment2] self.assertTrue(self.driver.terminate_connection(volume, None)) self._mock_host.unmap_volume.assert_called_once() self._mock_host.safe_delete.assert_called_once() def test_validate_connector(self): fc_connector = {'wwpns': [TEST_WWN_1, TEST_WWN_2]} iscsi_connector = {'initiator': TEST_INITIATOR_IQN} self.driver.validate_connector(iscsi_connector) self.assertRaises(exception.InvalidConnectorException, self.driver.validate_connector, fc_connector) class InfiniboxDriverTestCaseQoS(InfiniboxDriverTestCaseBase): @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_no_qos(self, qos_specs): qos_specs.return_value = None self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_not_called() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_max_ipos(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'back-end', 'specs': {'maxIOPS': 1000, 'maxBWS': None}}} self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_called_once() self._mock_qos_policy.assign_entity.assert_called_once() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_max_bws(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'back-end', 'specs': {'maxIOPS': None, 'maxBWS': 10000}}} self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_called_once() self._mock_qos_policy.assign_entity.assert_called_once() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_no_compat(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'back-end', 'specs': {'maxIOPS': 1000, 'maxBWS': 10000}}} self._system.compat.has_qos.return_value = False self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_not_called() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_volume_type_id_none(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'back-end', 'specs': {'maxIOPS': 1000, 'maxBWS': 10000}}} self.driver.create_volume(test_volume2) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_not_called() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_no_specs(self, qos_specs): qos_specs.return_value = {'qos_specs': None} self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_not_called() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_front_end(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'front-end', 'specs': {'maxIOPS': 1000, 'maxBWS': 10000}}} self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_not_called() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_specs_empty(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'back-end', 'specs': {'maxIOPS': None, 'maxBWS': None}}} self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_not_called() @mock.patch("cinder.volume.volume_types.get_volume_type_qos_specs") def test_qos_policy_exists(self, qos_specs): qos_specs.return_value = {'qos_specs': {'id': 'qos_name', 'consumer': 'back-end', 'specs': {'maxIOPS': 1000, 'maxBWS': 10000}}} self._system.qos_policies.safe_get.return_value = self._mock_qos_policy self.driver.create_volume(test_volume) self._system.qos_policies.create.assert_not_called() self._mock_qos_policy.assign_entity.assert_called()