def test_create_passed_mapped_exception_and_detail(self, mock_utcnow): # passed Detail should be ignored because this is a mapped exception CONF.set_override('message_ttl', 300) mock_utcnow.return_value = datetime.datetime.utcnow() expected_expires_at = timeutils.utcnow() + datetime.timedelta( seconds=300) expected_message_record = { 'project_id': 'fakeproject', 'request_id': 'fakerequestid', 'resource_type': 'fake_resource_type', 'resource_uuid': None, 'action_id': message_field.Action.UPDATE_ATTACHMENT[0], 'detail_id': message_field.Detail.NOT_ENOUGH_SPACE_FOR_IMAGE[0], 'message_level': 'ERROR', 'expires_at': expected_expires_at, 'event_id': "VOLUME_fake_resource_type_004_007", } exc = exception.ImageTooBig(image_id='fake_image', reason='MYOB') self.message_api.create( self.ctxt, action=message_field.Action.UPDATE_ATTACHMENT, detail=message_field.Detail.VOLUME_ATTACH_MODE_INVALID, exception=exc, resource_type="fake_resource_type") self.message_api.db.message_create.assert_called_once_with( self.ctxt, expected_message_record) mock_utcnow.assert_called_with()
def test_create_passed_exception_no_detail(self, mock_utcnow): # Detail should be automatically supplied based on the # message_field.Detail.EXCEPTION_DETAIL_MAPPINGS CONF.set_override('message_ttl', 300) mock_utcnow.return_value = datetime.datetime.utcnow() expected_expires_at = timeutils.utcnow() + datetime.timedelta( seconds=300) expected_message_record = { 'project_id': 'fakeproject', 'request_id': 'fakerequestid', 'resource_type': 'fake_resource_type', 'resource_uuid': None, 'action_id': message_field.Action.SCHEDULE_ALLOCATE_VOLUME[0], # this is determined by the exception we'll be passing 'detail_id': message_field.Detail.NOT_ENOUGH_SPACE_FOR_IMAGE[0], 'message_level': 'ERROR', 'expires_at': expected_expires_at, 'event_id': "VOLUME_fake_resource_type_001_007", } exc = exception.ImageTooBig(image_id='fake_image', reason='MYOB') self.message_api.create( self.ctxt, action=message_field.Action.SCHEDULE_ALLOCATE_VOLUME, exception=exc, resource_type="fake_resource_type") self.message_api.db.message_create.assert_called_once_with( self.ctxt, expected_message_record) mock_utcnow.assert_called_with()
def check_available_space(dest, image_size, image_id): # TODO(e0ne): replace psutil with shutil.disk_usage when we drop # Python 2.7 support. if not os.path.isdir(dest): dest = os.path.dirname(dest) free_space = psutil.disk_usage(dest).free if free_space <= image_size: msg = ('There is no space to convert image. ' 'Requested: %(image_size)s, available: %(free_space)s' ) % {'image_size': image_size, 'free_space': free_space} raise exception.ImageTooBig(image_id=image_id, reason=msg)
def fetch(context: context.RequestContext, image_service: glance.GlanceImageService, image_id: str, path: str, _user_id, _project_id) -> None: # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. start_time = timeutils.utcnow() with fileutils.remove_path_on_error(path): with open(path, "wb") as image_file: try: image_service.download(context, image_id, tpool.Proxy(image_file)) except IOError as e: if e.errno == errno.ENOSPC: params = {'path': os.path.dirname(path), 'image': image_id} reason = _("No space left in image_conversion_dir " "path (%(path)s) while fetching " "image %(image)s.") % params LOG.exception(reason) raise exception.ImageTooBig(image_id=image_id, reason=reason) reason = ("IOError: %(errno)s %(strerror)s" % { 'errno': e.errno, 'strerror': e.strerror }) LOG.error(reason) raise exception.ImageDownloadFailed(image_href=image_id, reason=reason) duration = timeutils.delta_seconds(start_time, timeutils.utcnow()) # NOTE(jdg): use a default of 1, mostly for unit test, but in # some incredible event this is 0 (cirros image?) don't barf if duration < 1: duration = 1 fsz_mb = os.stat(image_file.name).st_size / units.Mi mbps = (fsz_mb / duration) msg = ("Image fetch details: dest %(dest)s, size %(sz).2f MB, " "duration %(duration).2f sec") LOG.debug(msg, { "dest": image_file.name, "sz": fsz_mb, "duration": duration }) msg = "Image download %(sz).2f MB at %(mbps).2f MB/s" LOG.info(msg, {"sz": fsz_mb, "mbps": mbps})
def test_volume_reimage_raise_exception(self): volume = tests_utils.create_volume(self.context) self.volume.create_volume(self.context, volume) with mock.patch.object(self.volume.driver, 'copy_image_to_volume' ) as mock_cp_img: mock_cp_img.side_effect = processutils.ProcessExecutionError self.assertRaises(exception.ImageCopyFailure, self.volume.reimage, self.context, volume, self.image_meta) self.assertEqual(volume.previous_status, 'available') self.assertEqual(volume.status, 'error') mock_cp_img.side_effect = exception.ImageUnacceptable( image_id=self.image_meta['id'], reason='') self.assertRaises(exception.ImageUnacceptable, self.volume.reimage, self.context, volume, self.image_meta) mock_cp_img.side_effect = exception.ImageConversionNotAllowed( image_id=self.image_meta['id'], reason='') with mock.patch.object( self.volume.message_api, 'create' ) as mock_msg_create: self.assertRaises( exception.ImageConversionNotAllowed, self.volume.reimage, self.context, volume, self.image_meta) mock_msg_create.assert_called_with( self.context, message_field.Action.REIMAGE_VOLUME, resource_uuid=volume.id, detail=message_field.Detail.IMAGE_FORMAT_UNACCEPTABLE) mock_cp_img.side_effect = exception.ImageTooBig( image_id=self.image_meta['id'], reason='') self.assertRaises(exception.ImageTooBig, self.volume.reimage, self.context, volume, self.image_meta) mock_cp_img.side_effect = Exception self.assertRaises(exception.ImageCopyFailure, self.volume.reimage, self.context, volume, self.image_meta) mock_cp_img.side_effect = exception.ImageCopyFailure(reason='') self.assertRaises(exception.ImageCopyFailure, self.volume.reimage, self.context, volume, self.image_meta)
class GenericVolumeDriverTestCase(BaseDriverTestCase): """Test case for VolumeDriver.""" driver_name = "cinder.tests.fake_driver.FakeLoggingVolumeDriver" def test_create_temp_cloned_volume(self): with mock.patch.object( self.volume.driver, 'create_cloned_volume') as mock_create_cloned_volume: model_update = {'provider_location': 'dummy'} mock_create_cloned_volume.return_value = model_update vol = tests_utils.create_volume(self.context, status='backing-up') cloned_vol = self.volume.driver._create_temp_cloned_volume( self.context, vol) self.assertEqual('dummy', cloned_vol.provider_location) self.assertEqual('available', cloned_vol.status) mock_create_cloned_volume.return_value = None vol = tests_utils.create_volume(self.context, status='backing-up') cloned_vol = self.volume.driver._create_temp_cloned_volume( self.context, vol) self.assertEqual('available', cloned_vol.status) def test_get_backup_device_available(self): vol = tests_utils.create_volume(self.context) self.context.user_id = fake.USER_ID self.context.project_id = fake.PROJECT_ID backup_obj = tests_utils.create_backup(self.context, vol['id']) (backup_device, is_snapshot) = self.volume.driver.get_backup_device( self.context, backup_obj) volume = objects.Volume.get_by_id(self.context, vol.id) self.assertNotIn('temporary', backup_device.admin_metadata.keys()) self.assertEqual(volume, backup_device) self.assertFalse(is_snapshot) backup_obj.refresh() self.assertIsNone(backup_obj.temp_volume_id) def test_get_backup_device_in_use(self): vol = tests_utils.create_volume(self.context, status='backing-up', previous_status='in-use') admin_meta = {'temporary': 'True'} temp_vol = tests_utils.create_volume(self.context, admin_metadata=admin_meta) self.context.user_id = fake.USER_ID self.context.project_id = fake.PROJECT_ID backup_obj = tests_utils.create_backup(self.context, vol['id']) with mock.patch.object( self.volume.driver, '_create_temp_cloned_volume') as mock_create_temp: mock_create_temp.return_value = temp_vol (backup_device, is_snapshot) = ( self.volume.driver.get_backup_device(self.context, backup_obj)) self.assertEqual(temp_vol, backup_device) self.assertFalse(is_snapshot) backup_obj.refresh() self.assertEqual(temp_vol.id, backup_obj.temp_volume_id) def test_create_temp_volume_from_snapshot(self): volume_dict = {'id': fake.SNAPSHOT_ID, 'host': 'fakehost', 'cluster_name': 'fakecluster', 'availability_zone': 'fakezone', 'size': 1, 'volume_type_id': fake.VOLUME_TYPE_ID} vol = fake_volume.fake_volume_obj(self.context, **volume_dict) snapshot = fake_snapshot.fake_snapshot_obj(self.context) with mock.patch.object( self.volume.driver, 'create_volume_from_snapshot'): temp_vol = self.volume.driver._create_temp_volume_from_snapshot( self.context, vol, snapshot) self.assertEqual(fields.VolumeAttachStatus.DETACHED, temp_vol.attach_status) self.assertEqual('fakezone', temp_vol.availability_zone) self.assertEqual('fakecluster', temp_vol.cluster_name) @mock.patch.object(utils, 'brick_get_connector_properties') @mock.patch.object(cinder.volume.manager.VolumeManager, '_attach_volume') @mock.patch.object(cinder.volume.manager.VolumeManager, '_detach_volume') @mock.patch.object(volume_utils, 'copy_volume') @mock.patch.object(volume_rpcapi.VolumeAPI, 'get_capabilities') @mock.patch.object(cinder.volume.volume_types, 'volume_types_encryption_changed') @ddt.data(False, True) def test_copy_volume_data_mgr(self, encryption_changed, mock_encryption_changed, mock_get_capabilities, mock_copy, mock_detach, mock_attach, mock_get_connector): """Test function of _copy_volume_data.""" src_vol = tests_utils.create_volume(self.context, size=1, host=CONF.host) dest_vol = tests_utils.create_volume(self.context, size=1, host=CONF.host) mock_get_connector.return_value = {} mock_encryption_changed.return_value = encryption_changed self.volume.driver._throttle = mock.MagicMock() attach_expected = [ mock.call(self.context, dest_vol, {}, remote=False, attach_encryptor=encryption_changed), mock.call(self.context, src_vol, {}, remote=False, attach_encryptor=encryption_changed)] detach_expected = [ mock.call(self.context, {'device': {'path': 'bar'}}, dest_vol, {}, force=True, remote=False, attach_encryptor=encryption_changed), mock.call(self.context, {'device': {'path': 'foo'}}, src_vol, {}, force=True, remote=False, attach_encryptor=encryption_changed)] attach_volume_returns = [ {'device': {'path': 'bar'}}, {'device': {'path': 'foo'}} ] # Test case for sparse_copy_volume = False mock_attach.side_effect = attach_volume_returns mock_get_capabilities.return_value = {} self.volume._copy_volume_data(self.context, src_vol, dest_vol) self.assertEqual(attach_expected, mock_attach.mock_calls) mock_copy.assert_called_with('foo', 'bar', 1024, '1M', sparse=False) self.assertEqual(detach_expected, mock_detach.mock_calls) # Test case for sparse_copy_volume = True mock_attach.reset_mock() mock_detach.reset_mock() mock_attach.side_effect = attach_volume_returns mock_get_capabilities.return_value = {'sparse_copy_volume': True} self.volume._copy_volume_data(self.context, src_vol, dest_vol) self.assertEqual(attach_expected, mock_attach.mock_calls) mock_copy.assert_called_with('foo', 'bar', 1024, '1M', sparse=True) self.assertEqual(detach_expected, mock_detach.mock_calls) # cleanup resource db.volume_destroy(self.context, src_vol['id']) db.volume_destroy(self.context, dest_vol['id']) @mock.patch(driver_name + '.initialize_connection') @mock.patch(driver_name + '.create_export', return_value=None) @mock.patch(driver_name + '._connect_device') def test_attach_volume_encrypted(self, connect_mock, export_mock, initialize_mock): properties = {'host': 'myhost', 'ip': '192.168.1.43', 'initiator': u'iqn.1994-05.com.redhat:d9be887375', 'multipath': False, 'os_type': 'linux2', 'platform': 'x86_64'} data = {'target_discovered': True, 'target_iqn': 'iqn.2010-10.org.openstack:volume-00000001', 'target_portal': '127.0.0.0.1:3260', 'volume_id': 1, 'discard': False} passed_conn = {'driver_volume_type': 'iscsi', 'data': data.copy()} initialize_mock.return_value = passed_conn # _attach_volume adds the encrypted value based on the volume expected_conn = {'driver_volume_type': 'iscsi', 'data': data.copy()} expected_conn['data']['encrypted'] = True volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) attach_info, vol = self.volume.driver._attach_volume(self.context, volume, properties) export_mock.assert_called_once_with(self.context, volume, properties) initialize_mock.assert_called_once_with(volume, properties) connect_mock.assert_called_once_with(expected_conn) self.assertEqual(connect_mock.return_value, attach_info) self.assertEqual(volume, vol) @mock.patch.object(os_brick.initiator.connector, 'get_connector_properties') @mock.patch.object(image_utils, 'fetch_to_raw') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_attach_volume') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_detach_volume') @mock.patch.object(cinder.utils, 'brick_attach_volume_encryptor') @mock.patch.object(cinder.utils, 'brick_detach_volume_encryptor') def test_copy_image_to_encrypted_volume(self, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() local_path = 'dev/sda' attach_info = {'device': {'path': local_path}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] self.volume.driver.copy_image_to_encrypted_volume( self.context, volume, image_service, fake.IMAGE_ID) encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) mock_fetch_to_raw.assert_called_once_with( self.context, image_service, fake.IMAGE_ID, local_path, '1M', size=2) mock_detach_encryptor.assert_called_once_with( attach_info, encryption) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True) @mock.patch.object(os_brick.initiator.connector, 'get_connector_properties') @mock.patch.object(image_utils, 'fetch_to_raw') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_attach_volume') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_detach_volume') @mock.patch.object(cinder.utils, 'brick_attach_volume_encryptor') @mock.patch.object(cinder.utils, 'brick_detach_volume_encryptor') def test_copy_image_to_encrypted_volume_failed_attach_encryptor( self, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() attach_info = {'device': {'path': 'dev/sda'}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] raised_exception = os_brick.exception.VolumeEncryptionNotSupported( volume_id = "123", volume_type = "abc") mock_attach_encryptor.side_effect = raised_exception self.assertRaises(os_brick.exception.VolumeEncryptionNotSupported, self.volume.driver.copy_image_to_encrypted_volume, self.context, volume, image_service, fake.IMAGE_ID) encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) self.assertFalse(mock_fetch_to_raw.called) self.assertFalse(mock_detach_encryptor.called) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True) @mock.patch.object(os_brick.initiator.connector, 'get_connector_properties') @mock.patch.object(image_utils, 'fetch_to_raw') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_attach_volume') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_detach_volume') @mock.patch.object(cinder.utils, 'brick_attach_volume_encryptor') @mock.patch.object(cinder.utils, 'brick_detach_volume_encryptor') @ddt.data(exception.ImageUnacceptable( reason='fake', image_id=fake.IMAGE_ID), exception.ImageTooBig( reason='fake image size exceeded', image_id=fake.IMAGE_ID)) def test_copy_image_to_encrypted_volume_failed_fetch( self, excep, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() local_path = 'dev/sda' attach_info = {'device': {'path': local_path}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] mock_fetch_to_raw.side_effect = excep encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} self.assertRaises(type(excep), self.volume.driver.copy_image_to_encrypted_volume, self.context, volume, image_service, fake.IMAGE_ID) mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) mock_fetch_to_raw.assert_called_once_with( self.context, image_service, fake.IMAGE_ID, local_path, '1M', size=2) mock_detach_encryptor.assert_called_once_with( attach_info, encryption) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True) @mock.patch('cinder.volume.driver.brick_exception') @mock.patch('cinder.tests.fake_driver.FakeLoggingVolumeDriver.' 'terminate_connection', side_effect=Exception) @mock.patch('cinder.tests.fake_driver.FakeLoggingVolumeDriver.' 'remove_export', side_effect=Exception) def test_detach_volume_force(self, remove_mock, terminate_mock, exc_mock): """Test force parameter on _detach_volume. On the driver if we receive the force parameter we will do everything even with Exceptions on disconnect, terminate, and remove export. """ connector = mock.Mock() connector.disconnect_volume.side_effect = Exception # TODO(geguileo): Remove this ExceptionChainer simulation once we # release OS-Brick version with it and bump min version. exc = exc_mock.ExceptionChainer.return_value exc.context.return_value.__enter__.return_value = exc exc.context.return_value.__exit__.return_value = True volume = {'id': fake.VOLUME_ID} attach_info = {'device': {}, 'connector': connector, 'conn': {'data': {}, }} # TODO(geguileo): Change TypeError to ExceptionChainer once we release # OS-Brick version with it and bump min version. self.assertRaises(TypeError, self.volume.driver._detach_volume, self.context, attach_info, volume, {}, force=True) self.assertTrue(connector.disconnect_volume.called) self.assertTrue(remove_mock.called) self.assertTrue(terminate_mock.called) self.assertEqual(3, exc.context.call_count) @ddt.data({'cfg_value': '10', 'valid': True}, {'cfg_value': 'auto', 'valid': True}, {'cfg_value': '1', 'valid': True}, {'cfg_value': '1.2', 'valid': True}, {'cfg_value': '100', 'valid': True}, {'cfg_value': '20.15', 'valid': True}, {'cfg_value': 'True', 'valid': False}, {'cfg_value': 'False', 'valid': False}, {'cfg_value': '10.0.0', 'valid': False}, {'cfg_value': '0.00', 'valid': True}, {'cfg_value': 'anything', 'valid': False},) @ddt.unpack def test_auto_max_subscription_ratio_options(self, cfg_value, valid): # This tests the max_over_subscription_ratio option as it is now # checked by a regex def _set_conf(config, value): config.set_override('max_over_subscription_ratio', value) config = conf.Configuration(None) config.append_config_values(driver.volume_opts) if valid: _set_conf(config, cfg_value) self.assertEqual(cfg_value, config.safe_get( 'max_over_subscription_ratio')) else: self.assertRaises(ValueError, _set_conf, config, cfg_value)
def fake_copy_image_to_volume(context, volume, image_service, image_id): raise exception.ImageTooBig(image_id=image_id, reason='')
class GenericVolumeDriverTestCase(BaseDriverTestCase): """Test case for VolumeDriver.""" driver_name = "cinder.tests.fake_driver.FakeLoggingVolumeDriver" def test_create_temp_cloned_volume(self): with mock.patch.object( self.volume.driver, 'create_cloned_volume') as mock_create_cloned_volume: model_update = {'provider_location': 'dummy'} mock_create_cloned_volume.return_value = model_update vol = tests_utils.create_volume(self.context, status='backing-up') cloned_vol = self.volume.driver._create_temp_cloned_volume( self.context, vol) self.assertEqual('dummy', cloned_vol.provider_location) self.assertEqual('available', cloned_vol.status) mock_create_cloned_volume.return_value = None vol = tests_utils.create_volume(self.context, status='backing-up') cloned_vol = self.volume.driver._create_temp_cloned_volume( self.context, vol) self.assertEqual('available', cloned_vol.status) def test_get_backup_device_available(self): vol = tests_utils.create_volume(self.context) self.context.user_id = fake.USER_ID self.context.project_id = fake.PROJECT_ID backup_obj = tests_utils.create_backup(self.context, vol['id']) (backup_device, is_snapshot) = self.volume.driver.get_backup_device( self.context, backup_obj) volume = objects.Volume.get_by_id(self.context, vol.id) self.assertEqual(volume, backup_device) self.assertFalse(is_snapshot) backup_obj.refresh() self.assertIsNone(backup_obj.temp_volume_id) def test_get_backup_device_in_use(self): vol = tests_utils.create_volume(self.context, status='backing-up', previous_status='in-use') temp_vol = tests_utils.create_volume(self.context) self.context.user_id = fake.USER_ID self.context.project_id = fake.PROJECT_ID backup_obj = tests_utils.create_backup(self.context, vol['id']) with mock.patch.object( self.volume.driver, '_create_temp_cloned_volume') as mock_create_temp: mock_create_temp.return_value = temp_vol (backup_device, is_snapshot) = ( self.volume.driver.get_backup_device(self.context, backup_obj)) self.assertEqual(temp_vol, backup_device) self.assertFalse(is_snapshot) backup_obj.refresh() self.assertEqual(temp_vol.id, backup_obj.temp_volume_id) def test__create_temp_volume_from_snapshot(self): volume_dict = {'id': fake.SNAPSHOT_ID, 'host': 'fakehost', 'cluster_name': 'fakecluster', 'availability_zone': 'fakezone', 'size': 1} vol = fake_volume.fake_volume_obj(self.context, **volume_dict) snapshot = fake_snapshot.fake_snapshot_obj(self.context) with mock.patch.object( self.volume.driver, 'create_volume_from_snapshot'): temp_vol = self.volume.driver._create_temp_volume_from_snapshot( self.context, vol, snapshot) self.assertEqual(fields.VolumeAttachStatus.DETACHED, temp_vol.attach_status) self.assertEqual('fakezone', temp_vol.availability_zone) self.assertEqual('fakecluster', temp_vol.cluster_name) @mock.patch.object(utils, 'brick_get_connector_properties') @mock.patch.object(cinder.volume.manager.VolumeManager, '_attach_volume') @mock.patch.object(cinder.volume.manager.VolumeManager, '_detach_volume') @mock.patch.object(volutils, 'copy_volume') @mock.patch.object(volume_rpcapi.VolumeAPI, 'get_capabilities') @mock.patch.object(cinder.volume.volume_types, 'volume_types_encryption_changed') @ddt.data(False, True) def test_copy_volume_data_mgr(self, encryption_changed, mock_encryption_changed, mock_get_capabilities, mock_copy, mock_detach, mock_attach, mock_get_connector): """Test function of _copy_volume_data.""" src_vol = tests_utils.create_volume(self.context, size=1, host=CONF.host) dest_vol = tests_utils.create_volume(self.context, size=1, host=CONF.host) mock_get_connector.return_value = {} mock_encryption_changed.return_value = encryption_changed self.volume.driver._throttle = mock.MagicMock() attach_expected = [ mock.call(self.context, dest_vol, {}, remote=False, attach_encryptor=encryption_changed), mock.call(self.context, src_vol, {}, remote=False, attach_encryptor=encryption_changed)] detach_expected = [ mock.call(self.context, {'device': {'path': 'bar'}}, dest_vol, {}, force=True, remote=False, attach_encryptor=encryption_changed), mock.call(self.context, {'device': {'path': 'foo'}}, src_vol, {}, force=True, remote=False, attach_encryptor=encryption_changed)] attach_volume_returns = [ {'device': {'path': 'bar'}}, {'device': {'path': 'foo'}} ] # Test case for sparse_copy_volume = False mock_attach.side_effect = attach_volume_returns mock_get_capabilities.return_value = {} self.volume._copy_volume_data(self.context, src_vol, dest_vol) self.assertEqual(attach_expected, mock_attach.mock_calls) mock_copy.assert_called_with('foo', 'bar', 1024, '1M', sparse=False) self.assertEqual(detach_expected, mock_detach.mock_calls) # Test case for sparse_copy_volume = True mock_attach.reset_mock() mock_detach.reset_mock() mock_attach.side_effect = attach_volume_returns mock_get_capabilities.return_value = {'sparse_copy_volume': True} self.volume._copy_volume_data(self.context, src_vol, dest_vol) self.assertEqual(attach_expected, mock_attach.mock_calls) mock_copy.assert_called_with('foo', 'bar', 1024, '1M', sparse=True) self.assertEqual(detach_expected, mock_detach.mock_calls) # cleanup resource db.volume_destroy(self.context, src_vol['id']) db.volume_destroy(self.context, dest_vol['id']) @mock.patch.object(os_brick.initiator.connector, 'get_connector_properties') @mock.patch.object(image_utils, 'fetch_to_raw') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_attach_volume') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_detach_volume') @mock.patch.object(cinder.utils, 'brick_attach_volume_encryptor') @mock.patch.object(cinder.utils, 'brick_detach_volume_encryptor') def test_copy_image_to_encrypted_volume(self, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() local_path = 'dev/sda' attach_info = {'device': {'path': local_path}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] self.volume.driver.copy_image_to_encrypted_volume( self.context, volume, image_service, fake.IMAGE_ID) encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) mock_fetch_to_raw.assert_called_once_with( self.context, image_service, fake.IMAGE_ID, local_path, '1M', size=2) mock_detach_encryptor.assert_called_once_with( attach_info, encryption) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True) @mock.patch.object(os_brick.initiator.connector, 'get_connector_properties') @mock.patch.object(image_utils, 'fetch_to_raw') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_attach_volume') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_detach_volume') @mock.patch.object(cinder.utils, 'brick_attach_volume_encryptor') @mock.patch.object(cinder.utils, 'brick_detach_volume_encryptor') def test_copy_image_to_encrypted_volume_failed_attach_encryptor( self, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() attach_info = {'device': {'path': 'dev/sda'}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] raised_exception = os_brick.exception.VolumeEncryptionNotSupported( volume_id = "123", volume_type = "abc") mock_attach_encryptor.side_effect = raised_exception self.assertRaises(os_brick.exception.VolumeEncryptionNotSupported, self.volume.driver.copy_image_to_encrypted_volume, self.context, volume, image_service, fake.IMAGE_ID) encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) self.assertFalse(mock_fetch_to_raw.called) self.assertFalse(mock_detach_encryptor.called) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True) @mock.patch.object(os_brick.initiator.connector, 'get_connector_properties') @mock.patch.object(image_utils, 'fetch_to_raw') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_attach_volume') @mock.patch.object(cinder.volume.driver.VolumeDriver, '_detach_volume') @mock.patch.object(cinder.utils, 'brick_attach_volume_encryptor') @mock.patch.object(cinder.utils, 'brick_detach_volume_encryptor') @ddt.data(exception.ImageUnacceptable( reason='fake', image_id=fake.IMAGE_ID), exception.ImageTooBig( reason='fake image size exceeded', image_id=fake.IMAGE_ID)) def test_copy_image_to_encrypted_volume_failed_fetch( self, excep, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() local_path = 'dev/sda' attach_info = {'device': {'path': local_path}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] mock_fetch_to_raw.side_effect = excep encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} self.assertRaises(type(excep), self.volume.driver.copy_image_to_encrypted_volume, self.context, volume, image_service, fake.IMAGE_ID) mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) mock_fetch_to_raw.assert_called_once_with( self.context, image_service, fake.IMAGE_ID, local_path, '1M', size=2) mock_detach_encryptor.assert_called_once_with( attach_info, encryption) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True) @mock.patch('cinder.volume.driver.brick_exception') @mock.patch('cinder.tests.fake_driver.FakeLoggingVolumeDriver.' 'terminate_connection', side_effect=Exception) @mock.patch('cinder.tests.fake_driver.FakeLoggingVolumeDriver.' 'remove_export', side_effect=Exception) def test_detach_volume_force(self, remove_mock, terminate_mock, exc_mock): """Test force parameter on _detach_volume. On the driver if we receive the force parameter we will do everything even with Exceptions on disconnect, terminate, and remove export. """ connector = mock.Mock() connector.disconnect_volume.side_effect = Exception # TODO(geguileo): Remove this ExceptionChainer simulation once we # release OS-Brick version with it and bump min version. exc = exc_mock.ExceptionChainer.return_value exc.context.return_value.__enter__.return_value = exc exc.context.return_value.__exit__.return_value = True volume = {'id': fake.VOLUME_ID} attach_info = {'device': {}, 'connector': connector, 'conn': {'data': {}, }} # TODO(geguileo): Change TypeError to ExceptionChainer once we release # OS-Brick version with it and bump min version. self.assertRaises(TypeError, self.volume.driver._detach_volume, self.context, attach_info, volume, {}, force=True) self.assertTrue(connector.disconnect_volume.called) self.assertTrue(remove_mock.called) self.assertTrue(terminate_mock.called) self.assertEqual(3, exc.context.call_count)