diff --git a/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py b/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py index f3845c563a7..09b37752950 100644 --- a/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py +++ b/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py @@ -1251,7 +1251,8 @@ def _test_copy_image_to_volume_stream_optimized(self, get_disk_type, get_profile_id, select_ds_for_volume, - download_error=False): + download_error=False, + duplicate_name=False): host = mock.sentinel.host rp = mock.sentinel.rp folder = mock.sentinel.folder @@ -1278,6 +1279,10 @@ def _test_copy_image_to_volume_stream_optimized(self, if download_error: download_image.side_effect = exceptions.VimException vops.get_backing.return_value = backing + elif duplicate_name: + download_image.side_effect = [exceptions.DuplicateName, + backing] + vops.get_backing.return_value = backing else: download_image.return_value = backing @@ -1300,11 +1305,19 @@ def _test_copy_image_to_volume_stream_optimized(self, context, volume, image_service, image_id, image_size, adapter_type) - select_ds_for_volume.assert_called_once_with(volume) - vops.get_create_spec.assert_called_once_with( + if duplicate_name: + select_ds_for_volume.assert_called_with(volume) + vops.get_create_spec.assert_called_with( + volume['name'], volume_size_kb, disk_type, summary.name, + profile_id=profile_id, adapter_type=adapter_type, + extra_config=extra_config) + else: + select_ds_for_volume.assert_called_once_with(volume) + vops.get_create_spec.assert_called_once_with( volume['name'], volume_size_kb, disk_type, summary.name, profile_id=profile_id, adapter_type=adapter_type, extra_config=extra_config) + self.assertEqual(vm_create_spec, import_spec.configSpec) download_image.assert_called_with( context, @@ -1323,6 +1336,10 @@ def _test_copy_image_to_volume_stream_optimized(self, if download_error: self.assertFalse(vops.update_backing_disk_uuid.called) vops.delete_backing.assert_called_once_with(backing) + elif duplicate_name: + vops.delete_backing.assert_called_once_with(backing) + vops.update_backing_disk_uuid.assert_called_once_with( + backing, volume['id']) else: vops.update_backing_disk_uuid.assert_called_once_with( backing, volume['id']) @@ -1333,6 +1350,9 @@ def test_copy_image_to_volume_stream_optimized(self): def test_copy_image_to_volume_stream_optimized_with_download_error(self): self._test_copy_image_to_volume_stream_optimized(download_error=True) + def test_copy_image_to_volume_stream_optimized_with_duplicate_name(self): + self._test_copy_image_to_volume_stream_optimized(duplicate_name=True) + @mock.patch.object(VMDK_DRIVER, '_in_use', return_value=True) def test_copy_volume_to_image_when_attached(self, in_use): volume = self._create_volume_dict( diff --git a/cinder/volume/drivers/vmware/vmdk.py b/cinder/volume/drivers/vmware/vmdk.py index 90918a49209..d867e3ecf67 100644 --- a/cinder/volume/drivers/vmware/vmdk.py +++ b/cinder/volume/drivers/vmware/vmdk.py @@ -49,6 +49,7 @@ from cinder.image import image_utils from cinder import interface from cinder.keymgr import kmip +from cinder import utils from cinder.objects import snapshot as snapshot_obj from cinder.scheduler import rpcapi as scheduler_rpcapi from cinder.volume import configuration @@ -1864,6 +1865,9 @@ def _create_volume_from_non_stream_optimized_image( self._delete_temp_disk( vmdk_path.get_descriptor_ds_file_path(), dc_ref) + # Retry is needed for VolumeManager.reimage, which triggers the exception + # and a subsequent deletion of the backing. The retry reimages the volume. + @utils.retry(retry_param=exceptions.DuplicateName) def _fetch_stream_optimized_image(self, context, volume, image_service, image_id, image_size, adapter_type): """Creates volume from image using HttpNfc VM import.