summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-04-05 23:15:44 +0000
committerGerrit Code Review <review@openstack.org>2015-04-05 23:15:44 +0000
commitaf79f87b9ee97f8ae56d97b6423c884889aec415 (patch)
tree5a68d815c5e4f7c45f65711a8d1669b4661e346e
parentfd8aa9b9c3446a3eca41d44c08abc4fe05b50a85 (diff)
parent753d6a8574fcc2c0680c9f75c31e7bc9035e1534 (diff)
downloadcinder-af79f87b9ee97f8ae56d97b6423c884889aec415.tar.gz
Merge "VMware: Skip vSAN for preallocated image download"
-rw-r--r--cinder/tests/test_vmware_vmdk.py179
-rw-r--r--cinder/tests/test_vmware_volumeops.py94
-rw-r--r--cinder/volume/drivers/vmware/datastore.py6
-rw-r--r--cinder/volume/drivers/vmware/vmdk.py102
-rw-r--r--cinder/volume/drivers/vmware/volumeops.py43
5 files changed, 366 insertions, 58 deletions
diff --git a/cinder/tests/test_vmware_vmdk.py b/cinder/tests/test_vmware_vmdk.py
index e32719c1f..a985d8383 100644
--- a/cinder/tests/test_vmware_vmdk.py
+++ b/cinder/tests/test_vmware_vmdk.py
@@ -898,53 +898,158 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
vops.delete_backing.assert_called_once_with(backing)
self.assertFalse(extend_disk.called)
+ @mock.patch.object(VMDK_DRIVER, '_copy_temp_virtual_disk')
+ @mock.patch.object(VMDK_DRIVER, '_get_temp_image_folder')
@mock.patch(
'cinder.volume.drivers.vmware.volumeops.FlatExtentVirtualDiskPath')
@mock.patch.object(VMDK_DRIVER, '_copy_image')
@mock.patch.object(VMDK_DRIVER, 'volumeops')
def test_create_virtual_disk_from_preallocated_image(
- self, vops, copy_image, flat_extent_path):
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
self._test_create_virtual_disk_from_preallocated_image(
- vops, copy_image, flat_extent_path)
+ vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk)
def _test_create_virtual_disk_from_preallocated_image(
- self, vops, copy_image, flat_extent_path):
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
context = mock.Mock()
image_service = mock.Mock()
image_id = mock.Mock()
image_size_in_bytes = 2 * units.Gi
- dc_ref = mock.Mock()
- ds_name = "nfs"
- folder_path = "A/B/"
- disk_name = "disk-1"
+ dest_dc_ref = mock.sentinel.dest_dc_ref
+ dest_ds_name = "nfs"
+ dest_folder_path = "A/B/"
+ dest_disk_name = "disk-1"
adapter_type = "ide"
- src_path = mock.Mock()
- flat_extent_path.return_value = src_path
+ dc_ref = mock.sentinel.dc_ref
+ ds_name = "local-0"
+ folder_path = "cinder_temp"
+ get_temp_image_folder.return_value = (dc_ref, ds_name, folder_path)
+
+ path = mock.Mock()
+ dest_path = mock.Mock()
+ flat_extent_path.side_effect = [path, dest_path]
ret = self._driver._create_virtual_disk_from_preallocated_image(
- context, image_service, image_id, image_size_in_bytes, dc_ref,
- ds_name, folder_path, disk_name, adapter_type)
+ context, image_service, image_id, image_size_in_bytes, dest_dc_ref,
+ dest_ds_name, dest_folder_path, dest_disk_name, adapter_type)
create_descriptor = vops.create_flat_extent_virtual_disk_descriptor
create_descriptor.assert_called_once_with(
- dc_ref, src_path, image_size_in_bytes / units.Ki, adapter_type,
+ dc_ref, path, image_size_in_bytes / units.Ki, adapter_type,
vmdk.EAGER_ZEROED_THICK_VMDK_TYPE)
copy_image.assert_called_once_with(
context, dc_ref, image_service, image_id, image_size_in_bytes,
- ds_name, src_path.get_flat_extent_file_path())
- self.assertEqual(src_path, ret)
+ ds_name, path.get_flat_extent_file_path())
+ copy_temp_virtual_disk.assert_called_once_with(dc_ref, path,
+ dest_dc_ref, dest_path)
+ self.assertEqual(dest_path, ret)
+
+ @mock.patch.object(VMDK_DRIVER, '_copy_temp_virtual_disk')
+ @mock.patch.object(VMDK_DRIVER, '_get_temp_image_folder')
+ @mock.patch(
+ 'cinder.volume.drivers.vmware.volumeops.FlatExtentVirtualDiskPath')
+ @mock.patch.object(VMDK_DRIVER, '_copy_image')
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ def test_create_virtual_disk_from_preallocated_image_with_no_disk_copy(
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
+ self._test_create_virtual_disk_from_preallocated_image_with_no_copy(
+ vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk)
+
+ def _test_create_virtual_disk_from_preallocated_image_with_no_copy(
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
+ context = mock.Mock()
+ image_service = mock.Mock()
+ image_id = mock.Mock()
+ image_size_in_bytes = 2 * units.Gi
+ dest_dc_ref = mock.Mock(value=mock.sentinel.dest_dc_ref)
+ dest_ds_name = "nfs"
+ dest_folder_path = "A/B/"
+ dest_disk_name = "disk-1"
+ adapter_type = "ide"
+
+ dc_ref = mock.Mock(value=mock.sentinel.dest_dc_ref)
+ ds_name = dest_ds_name
+ folder_path = "cinder_temp"
+ get_temp_image_folder.return_value = (dc_ref, ds_name, folder_path)
+
+ path = mock.Mock()
+ flat_extent_path.return_value = path
+
+ ret = self._driver._create_virtual_disk_from_preallocated_image(
+ context, image_service, image_id, image_size_in_bytes, dest_dc_ref,
+ dest_ds_name, dest_folder_path, dest_disk_name, adapter_type)
+
+ create_descriptor = vops.create_flat_extent_virtual_disk_descriptor
+ create_descriptor.assert_called_once_with(
+ dc_ref, path, image_size_in_bytes / units.Ki, adapter_type,
+ vmdk.EAGER_ZEROED_THICK_VMDK_TYPE)
+ copy_image.assert_called_once_with(
+ context, dc_ref, image_service, image_id, image_size_in_bytes,
+ ds_name, path.get_flat_extent_file_path())
+ self.assertFalse(copy_temp_virtual_disk.called)
+ self.assertEqual(path, ret)
+
+ @mock.patch.object(VMDK_DRIVER, '_copy_temp_virtual_disk')
+ @mock.patch.object(VMDK_DRIVER, '_get_temp_image_folder')
+ @mock.patch(
+ 'cinder.volume.drivers.vmware.volumeops.FlatExtentVirtualDiskPath')
+ @mock.patch.object(VMDK_DRIVER, '_copy_image')
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ def test_create_virtual_disk_from_preallocated_image_with_copy_error(
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
+ self._test_create_virtual_disk_from_preallocated_image_with_copy_error(
+ vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk)
+
+ def _test_create_virtual_disk_from_preallocated_image_with_copy_error(
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
+ context = mock.Mock()
+ image_service = mock.Mock()
+ image_id = mock.Mock()
+ image_size_in_bytes = 2 * units.Gi
+ dest_dc_ref = mock.sentinel.dest_dc_ref
+ dest_ds_name = "nfs"
+ dest_folder_path = "A/B/"
+ dest_disk_name = "disk-1"
+ adapter_type = "ide"
+
+ dc_ref = mock.sentinel.dc_ref
+ ds_name = "local-0"
+ folder_path = "cinder_temp"
+ get_temp_image_folder.return_value = (dc_ref, ds_name, folder_path)
+
+ path = mock.Mock()
+ dest_path = mock.Mock()
+ flat_extent_path.side_effect = [path, dest_path]
- create_descriptor.reset_mock()
- copy_image.reset_mock()
copy_image.side_effect = exceptions.VimException("error")
+
self.assertRaises(
exceptions.VimException,
self._driver._create_virtual_disk_from_preallocated_image,
- context, image_service, image_id, image_size_in_bytes, dc_ref,
- ds_name, folder_path, disk_name, adapter_type)
+ context, image_service, image_id, image_size_in_bytes, dest_dc_ref,
+ dest_ds_name, dest_folder_path, dest_disk_name, adapter_type)
+
+ create_descriptor = vops.create_flat_extent_virtual_disk_descriptor
+ create_descriptor.assert_called_once_with(
+ dc_ref, path, image_size_in_bytes / units.Ki, adapter_type,
+ vmdk.EAGER_ZEROED_THICK_VMDK_TYPE)
+
+ copy_image.assert_called_once_with(
+ context, dc_ref, image_service, image_id, image_size_in_bytes,
+ ds_name, path.get_flat_extent_file_path())
vops.delete_file.assert_called_once_with(
- src_path.get_descriptor_ds_file_path(), dc_ref)
+ path.get_descriptor_ds_file_path(), dc_ref)
+ self.assertFalse(copy_temp_virtual_disk.called)
@mock.patch(
'cinder.volume.drivers.vmware.volumeops.'
@@ -984,7 +1089,7 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
context, dc_ref, image_service, image_id, image_size_in_bytes,
ds_name, src_path.get_descriptor_file_path())
copy_temp_virtual_disk.assert_called_once_with(
- dc_ref, src_path, dest_path)
+ dc_ref, src_path, dc_ref, dest_path)
self.assertEqual(dest_path, ret)
@mock.patch.object(image_transfer, 'download_stream_optimized_image')
@@ -2384,14 +2489,44 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
generate_uuid,
extend_disk)
+ @mock.patch.object(VMDK_DRIVER, '_copy_temp_virtual_disk')
+ @mock.patch.object(VMDK_DRIVER, '_get_temp_image_folder')
@mock.patch(
'cinder.volume.drivers.vmware.volumeops.FlatExtentVirtualDiskPath')
@mock.patch.object(VMDK_DRIVER, '_copy_image')
@mock.patch.object(VMDK_DRIVER, 'volumeops')
def test_create_virtual_disk_from_preallocated_image(
- self, vops, copy_image, flat_extent_path):
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
self._test_create_virtual_disk_from_preallocated_image(
- vops, copy_image, flat_extent_path)
+ vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk)
+
+ @mock.patch.object(VMDK_DRIVER, '_copy_temp_virtual_disk')
+ @mock.patch.object(VMDK_DRIVER, '_get_temp_image_folder')
+ @mock.patch(
+ 'cinder.volume.drivers.vmware.volumeops.FlatExtentVirtualDiskPath')
+ @mock.patch.object(VMDK_DRIVER, '_copy_image')
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ def test_create_virtual_disk_from_preallocated_image_with_no_disk_copy(
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
+ self._test_create_virtual_disk_from_preallocated_image_with_no_copy(
+ vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk)
+
+ @mock.patch.object(VMDK_DRIVER, '_copy_temp_virtual_disk')
+ @mock.patch.object(VMDK_DRIVER, '_get_temp_image_folder')
+ @mock.patch(
+ 'cinder.volume.drivers.vmware.volumeops.FlatExtentVirtualDiskPath')
+ @mock.patch.object(VMDK_DRIVER, '_copy_image')
+ @mock.patch.object(VMDK_DRIVER, 'volumeops')
+ def test_create_virtual_disk_from_preallocated_image_with_copy_error(
+ self, vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk):
+ self._test_create_virtual_disk_from_preallocated_image_with_copy_error(
+ vops, copy_image, flat_extent_path, get_temp_image_folder,
+ copy_temp_virtual_disk)
@mock.patch(
'cinder.volume.drivers.vmware.volumeops.'
diff --git a/cinder/tests/test_vmware_volumeops.py b/cinder/tests/test_vmware_volumeops.py
index 237e52e21..50a1f0cbd 100644
--- a/cinder/tests/test_vmware_volumeops.py
+++ b/cinder/tests/test_vmware_volumeops.py
@@ -1174,6 +1174,63 @@ class VolumeOpsTestCase(test.TestCase):
datacenter=datacenter)
self.session.wait_for_task.assert_called_once_with(task)
+ def test_create_datastore_folder(self):
+ file_manager = mock.sentinel.file_manager
+ self.session.vim.service_content.fileManager = file_manager
+ invoke_api = self.session.invoke_api
+
+ ds_name = "nfs"
+ folder_path = "test/"
+ datacenter = mock.sentinel.datacenter
+
+ self.vops.create_datastore_folder(ds_name, folder_path, datacenter)
+ invoke_api.assert_called_once_with(self.session.vim,
+ 'MakeDirectory',
+ file_manager,
+ name="[nfs] test/",
+ datacenter=datacenter)
+
+ def test_create_datastore_folder_with_existing_folder(self):
+ file_manager = mock.sentinel.file_manager
+ self.session.vim.service_content.fileManager = file_manager
+ invoke_api = self.session.invoke_api
+ invoke_api.side_effect = exceptions.FileAlreadyExistsException
+
+ ds_name = "nfs"
+ folder_path = "test/"
+ datacenter = mock.sentinel.datacenter
+
+ self.vops.create_datastore_folder(ds_name, folder_path, datacenter)
+ invoke_api.assert_called_once_with(self.session.vim,
+ 'MakeDirectory',
+ file_manager,
+ name="[nfs] test/",
+ datacenter=datacenter)
+ invoke_api.side_effect = None
+
+ def test_create_datastore_folder_with_invoke_api_error(self):
+ file_manager = mock.sentinel.file_manager
+ self.session.vim.service_content.fileManager = file_manager
+ invoke_api = self.session.invoke_api
+ invoke_api.side_effect = exceptions.VimFaultException(
+ ["FileFault"], "error")
+
+ ds_name = "nfs"
+ folder_path = "test/"
+ datacenter = mock.sentinel.datacenter
+
+ self.assertRaises(exceptions.VimFaultException,
+ self.vops.create_datastore_folder,
+ ds_name,
+ folder_path,
+ datacenter)
+ invoke_api.assert_called_once_with(self.session.vim,
+ 'MakeDirectory',
+ file_manager,
+ name="[nfs] test/",
+ datacenter=datacenter)
+ invoke_api.side_effect = None
+
def test_get_path_name(self):
path = mock.Mock(spec=object)
path_name = mock.sentinel.vm_path_name
@@ -1298,19 +1355,44 @@ class VolumeOpsTestCase(test.TestCase):
task = mock.sentinel.task
invoke_api = self.session.invoke_api
invoke_api.return_value = task
+
disk_mgr = self.session.vim.service_content.virtualDiskManager
- dc_ref = self.session.dc_ref
- src_vmdk_file_path = self.session.src
- dest_vmdk_file_path = self.session.dest
- self.vops.copy_vmdk_file(dc_ref, src_vmdk_file_path,
+ src_dc_ref = mock.sentinel.src_dc_ref
+ src_vmdk_file_path = mock.sentinel.src_vmdk_file_path
+ dest_dc_ref = mock.sentinel.dest_dc_ref
+ dest_vmdk_file_path = mock.sentinel.dest_vmdk_file_path
+ self.vops.copy_vmdk_file(src_dc_ref, src_vmdk_file_path,
+ dest_vmdk_file_path, dest_dc_ref)
+
+ invoke_api.assert_called_once_with(self.session.vim,
+ 'CopyVirtualDisk_Task',
+ disk_mgr,
+ sourceName=src_vmdk_file_path,
+ sourceDatacenter=src_dc_ref,
+ destName=dest_vmdk_file_path,
+ destDatacenter=dest_dc_ref,
+ force=True)
+ self.session.wait_for_task.assert_called_once_with(task)
+
+ def test_copy_vmdk_file_with_default_dest_datacenter(self):
+ task = mock.sentinel.task
+ invoke_api = self.session.invoke_api
+ invoke_api.return_value = task
+
+ disk_mgr = self.session.vim.service_content.virtualDiskManager
+ src_dc_ref = mock.sentinel.src_dc_ref
+ src_vmdk_file_path = mock.sentinel.src_vmdk_file_path
+ dest_vmdk_file_path = mock.sentinel.dest_vmdk_file_path
+ self.vops.copy_vmdk_file(src_dc_ref, src_vmdk_file_path,
dest_vmdk_file_path)
+
invoke_api.assert_called_once_with(self.session.vim,
'CopyVirtualDisk_Task',
disk_mgr,
sourceName=src_vmdk_file_path,
- sourceDatacenter=dc_ref,
+ sourceDatacenter=src_dc_ref,
destName=dest_vmdk_file_path,
- destDatacenter=dc_ref,
+ destDatacenter=src_dc_ref,
force=True)
self.session.wait_for_task.assert_called_once_with(task)
diff --git a/cinder/volume/drivers/vmware/datastore.py b/cinder/volume/drivers/vmware/datastore.py
index 0f3a914fc..2e4e9b0ca 100644
--- a/cinder/volume/drivers/vmware/datastore.py
+++ b/cinder/volume/drivers/vmware/datastore.py
@@ -36,6 +36,12 @@ class DatastoreType(object):
VMFS = "vmfs"
VSAN = "vsan"
+ _ALL_TYPES = {NFS, VMFS, VSAN}
+
+ @staticmethod
+ def get_all_types():
+ return DatastoreType._ALL_TYPES
+
class DatastoreSelector(object):
"""Class for selecting datastores which satisfy input requirements."""
diff --git a/cinder/volume/drivers/vmware/vmdk.py b/cinder/volume/drivers/vmware/vmdk.py
index 60225d04b..8a4da232f 100644
--- a/cinder/volume/drivers/vmware/vmdk.py
+++ b/cinder/volume/drivers/vmware/vmdk.py
@@ -58,6 +58,8 @@ CREATE_PARAM_ADAPTER_TYPE = 'adapter_type'
CREATE_PARAM_DISK_LESS = 'disk_less'
CREATE_PARAM_BACKING_NAME = 'name'
+TMP_IMAGES_DATASTORE_FOLDER_PATH = "cinder_temp/"
+
vmdk_opts = [
cfg.StrOpt('vmware_host_ip',
default=None,
@@ -564,7 +566,22 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
def _relocate_backing(self, volume, backing, host):
pass
- def _select_ds_for_volume(self, volume, host=None):
+ def _select_datastore(self, req, host=None):
+ """Selects datastore satisfying the given requirements.
+
+ :return: (host, resource_pool, summary)
+ """
+
+ hosts = [host] if host else None
+ best_candidate = self.ds_sel.select_datastore(req, hosts=hosts)
+ if not best_candidate:
+ LOG.error(_LE("There is no valid datastore satisfying "
+ "requirements: %s."), req)
+ raise vmdk_exceptions.NoValidDatastoreException()
+
+ return best_candidate
+
+ def _select_ds_for_volume(self, volume, host=None, create_params=None):
"""Select datastore that can accommodate the given volume's backing.
Returns the selected datastore summary along with a compute host and
@@ -577,16 +594,7 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
req[hub.DatastoreSelector.PROFILE_NAME] = self._get_storage_profile(
volume)
- # Select datastore satisfying the requirements.
- hosts = [host] if host else None
- best_candidate = self.ds_sel.select_datastore(req, hosts=hosts)
- if not best_candidate:
- LOG.error(_LE("There is no valid datastore to create backing for "
- "volume: %s."),
- volume['name'])
- raise vmdk_exceptions.NoValidDatastoreException()
-
- (host_ref, resource_pool, summary) = best_candidate
+ (host_ref, resource_pool, summary) = self._select_datastore(req, host)
dc = self.volumeops.get_dc(resource_pool)
folder = self._get_volume_group_folder(dc)
@@ -906,13 +914,14 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
descriptor_ds_file_path,
exc_info=True)
- def _copy_temp_virtual_disk(self, dc_ref, src_path, dest_path):
+ def _copy_temp_virtual_disk(self, src_dc_ref, src_path, dest_dc_ref,
+ dest_path):
"""Clones a temporary virtual disk and deletes it finally."""
try:
self.volumeops.copy_vmdk_file(
- dc_ref, src_path.get_descriptor_ds_file_path(),
- dest_path.get_descriptor_ds_file_path())
+ src_dc_ref, src_path.get_descriptor_ds_file_path(),
+ dest_path.get_descriptor_ds_file_path(), dest_dc_ref)
except exceptions.VimException:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Error occurred while copying %(src)s to "
@@ -922,7 +931,29 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
finally:
# Delete temporary disk.
self._delete_temp_disk(src_path.get_descriptor_ds_file_path(),
- dc_ref)
+ src_dc_ref)
+
+ def _get_temp_image_folder(self, image_size_in_bytes):
+ """Get datastore folder for downloading temporary images."""
+ # Form requirements for datastore selection.
+ req = {}
+ req[hub.DatastoreSelector.SIZE_BYTES] = image_size_in_bytes
+ # vSAN datastores don't support virtual disk with
+ # flat extent; skip such datastores.
+ req[hub.DatastoreSelector.HARD_AFFINITY_DS_TYPE] = (
+ hub.DatastoreType.get_all_types() - {hub.DatastoreType.VSAN})
+
+ # Select datastore satisfying the requirements.
+ (host_ref, _resource_pool, summary) = self._select_datastore(req)
+
+ ds_name = summary.name
+ dc_ref = self.volumeops.get_dc(host_ref)
+
+ # Create temporary datastore folder.
+ folder_path = TMP_IMAGES_DATASTORE_FOLDER_PATH
+ self.volumeops.create_datastore_folder(ds_name, folder_path, dc_ref)
+
+ return (dc_ref, ds_name, folder_path)
def _create_virtual_disk_from_sparse_image(
self, context, image_service, image_id, image_size_in_bytes,
@@ -947,19 +978,42 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
dest_path = volumeops.FlatExtentVirtualDiskPath(ds_name,
folder_path,
disk_name)
- self._copy_temp_virtual_disk(dc_ref, src_path, dest_path)
+ self._copy_temp_virtual_disk(dc_ref, src_path, dc_ref, dest_path)
LOG.debug("Created virtual disk: %s from sparse vmdk image.",
dest_path.get_descriptor_ds_file_path())
return dest_path
def _create_virtual_disk_from_preallocated_image(
self, context, image_service, image_id, image_size_in_bytes,
- dc_ref, ds_name, folder_path, disk_name, adapter_type):
+ dest_dc_ref, dest_ds_name, dest_folder_path, dest_disk_name,
+ adapter_type):
"""Creates virtual disk from an image which is a flat extent."""
- path = volumeops.FlatExtentVirtualDiskPath(ds_name,
- folder_path,
- disk_name)
+ # Upload the image and use it as a flat extent to create a virtual
+ # disk. First, find the datastore folder to download the image.
+ (dc_ref, ds_name,
+ folder_path) = self._get_temp_image_folder(image_size_in_bytes)
+
+ # pylint: disable=E1101
+ if ds_name == dest_ds_name and dc_ref.value == dest_dc_ref.value:
+ # Temporary image folder and destination path are on the same
+ # datastore. We can directly download the image to the destination
+ # folder to save one virtual disk copy.
+ path = volumeops.FlatExtentVirtualDiskPath(dest_ds_name,
+ dest_folder_path,
+ dest_disk_name)
+ dest_path = path
+ else:
+ # Use the image to create a temporary virtual disk which is then
+ # copied to the destination folder.
+ disk_name = uuidutils.generate_uuid()
+ path = volumeops.FlatExtentVirtualDiskPath(ds_name,
+ folder_path,
+ disk_name)
+ dest_path = volumeops.FlatExtentVirtualDiskPath(dest_ds_name,
+ dest_folder_path,
+ dest_disk_name)
+
LOG.debug("Creating virtual disk: %(path)s from (flat extent) image: "
"%(image_id)s.",
{'path': path.get_descriptor_ds_file_path(),
@@ -992,9 +1046,13 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
path.get_descriptor_ds_file_path(),
exc_info=True)
+ if dest_path != path:
+ # Copy temporary disk to given destination.
+ self._copy_temp_virtual_disk(dc_ref, path, dest_dc_ref, dest_path)
+
LOG.debug("Created virtual disk: %s from flat extent image.",
- path.get_descriptor_ds_file_path())
- return path
+ dest_path.get_descriptor_ds_file_path())
+ return dest_path
def _check_disk_conversion(self, image_disk_type, extra_spec_disk_type):
"""Check if disk type conversion is needed."""
diff --git a/cinder/volume/drivers/vmware/volumeops.py b/cinder/volume/drivers/vmware/volumeops.py
index 44d6e7685..e401f7126 100644
--- a/cinder/volume/drivers/vmware/volumeops.py
+++ b/cinder/volume/drivers/vmware/volumeops.py
@@ -1183,6 +1183,28 @@ class VMwareVolumeOps(object):
self._session.wait_for_task(task)
LOG.info(_LI("Successfully deleted file: %s."), file_path)
+ def create_datastore_folder(self, ds_name, folder_path, datacenter):
+ """Creates a datastore folder.
+
+ This method returns silently if the folder already exists.
+
+ :param ds_name: datastore name
+ :param folder_path: path of folder to create
+ :param datacenter: datacenter of target datastore
+ """
+ fileManager = self._session.vim.service_content.fileManager
+ ds_folder_path = "[%s] %s" % (ds_name, folder_path)
+ LOG.debug("Creating datastore folder: %s.", ds_folder_path)
+ try:
+ self._session.invoke_api(self._session.vim,
+ 'MakeDirectory',
+ fileManager,
+ name=ds_folder_path,
+ datacenter=datacenter)
+ LOG.info(_LI("Created datastore folder: %s."), folder_path)
+ except exceptions.FileAlreadyExistsException:
+ LOG.debug("Datastore folder: %s already exists.", folder_path)
+
def get_path_name(self, backing):
"""Get path name of the backing.
@@ -1308,26 +1330,31 @@ class VMwareVolumeOps(object):
LOG.debug("Created descriptor: %s.",
path.get_descriptor_ds_file_path())
- def copy_vmdk_file(self, dc_ref, src_vmdk_file_path, dest_vmdk_file_path):
+ def copy_vmdk_file(self, src_dc_ref, src_vmdk_file_path,
+ dest_vmdk_file_path, dest_dc_ref=None):
"""Copy contents of the src vmdk file to dest vmdk file.
- During the copy also coalesce snapshots of src if present.
- dest_vmdk_file_path will be created if not already present.
-
- :param dc_ref: Reference to datacenter containing src and dest
+ :param src_dc_ref: Reference to datacenter containing src datastore
:param src_vmdk_file_path: Source vmdk file path
:param dest_vmdk_file_path: Destination vmdk file path
+ :param dest_dc_ref: Reference to datacenter of dest datastore.
+ If unspecified, source datacenter is used.
"""
- LOG.debug('Copying disk data before snapshot of the VM')
+ LOG.debug('Copying disk: %(src)s to %(dest)s.',
+ {'src': src_vmdk_file_path,
+ 'dest': dest_vmdk_file_path})
+
+ dest_dc_ref = dest_dc_ref or src_dc_ref
diskMgr = self._session.vim.service_content.virtualDiskManager
task = self._session.invoke_api(self._session.vim,
'CopyVirtualDisk_Task',
diskMgr,
sourceName=src_vmdk_file_path,
- sourceDatacenter=dc_ref,
+ sourceDatacenter=src_dc_ref,
destName=dest_vmdk_file_path,
- destDatacenter=dc_ref,
+ destDatacenter=dest_dc_ref,
force=True)
+
LOG.debug("Initiated copying disk data via task: %s.", task)
self._session.wait_for_task(task)
LOG.info(_LI("Successfully copied disk at: %(src)s to: %(dest)s."),