VMware: Add volume ID in vCenter's volume config

HP data protector's backup of vCenter inventory is failing
for 'in-use' Cinder volumes because the vmdk is attached
to two VMs (Nova instance and the backing VM corresponding
to Cinder volume). The solution is to skip the backing VM
during data protector's backup.

This patch adds key 'cinder.volume.id' with value set to
volume UUID in volume's vCenter config file so that other
vCenter solutions can uniquely identify Cinder volumes.

Closes-Bug: #1484012
Change-Id: I08a5f1a39def14f164ab3ca08a480310ce0b79ca
This commit is contained in:
Vipin Balachandran
2015-06-22 19:56:09 +05:30
parent e1e33286ce
commit cb98bb48f1
4 changed files with 209 additions and 74 deletions

View File

@@ -1056,7 +1056,7 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
fake_vm_create_spec = mock.sentinel.spec
fake_disk_type = 'thin'
vol_name = 'fake_volume name'
vol_id = '12345'
vol_id = 'd11a82de-ddaa-448d-b50a-a255a7e61a1e'
fake_volume = {'name': vol_name,
'id': vol_id,
'size': fake_volume_size,
@@ -1095,12 +1095,14 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
image_service.show.assert_called_with(fake_context, fake_image_id)
_select_ds_for_volume.assert_called_with(fake_volume)
get_profile_id.assert_called_once_with(fake_volume)
extra_config = {vmdk.EXTRA_CONFIG_VOLUME_ID_KEY: vol_id}
volumeops.get_create_spec.assert_called_with(fake_volume['name'],
0,
fake_disk_type,
fake_summary.name,
profile_id,
adapter_type)
profileId=profile_id,
adapter_type=adapter_type,
extra_config=extra_config)
self.assertTrue(download_image.called)
download_image.assert_called_with(fake_context, timeout,
image_service,
@@ -1726,15 +1728,19 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
context = mock.sentinel.context
name = 'vm-1'
volume = {'name': 'vol-1', 'id': 1, 'size': 1}
volume = {'name': 'vol-1',
'id': 'd11a82de-ddaa-448d-b50a-a255a7e61a1e',
'size': 1}
tmp_file_path = mock.sentinel.tmp_file_path
file_size_bytes = units.Gi
ret = self._driver._create_backing_from_stream_optimized_file(
context, name, volume, tmp_file_path, file_size_bytes)
self.assertEqual(vm_ref, ret)
extra_config = {vmdk.EXTRA_CONFIG_VOLUME_ID_KEY: volume['id']}
vops.get_create_spec.assert_called_once_with(
name, 0, disk_type, summary.name, profile_id)
name, 0, disk_type, summary.name, profileId=profile_id,
extra_config=extra_config)
file_open.assert_called_once_with(tmp_file_path, "rb")
download_data.assert_called_once_with(
context, self.IMG_TX_TIMEOUT, tmp_file, session=session,
@@ -2054,6 +2060,7 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
"""Test _clone_backing with clone type - linked."""
fake_size = 3
fake_volume = {'volume_type_id': None, 'name': 'fake_name',
'id': '51e47214-8e3c-475d-b44b-aea6cd3eef53',
'size': fake_size}
fake_snapshot = {'volume_name': 'volume_name',
'name': 'snapshot_name',
@@ -2063,13 +2070,15 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
self._driver._clone_backing(fake_volume, fake_backing, fake_snapshot,
volumeops.LINKED_CLONE_TYPE,
fake_snapshot['volume_size'])
extra_config = {vmdk.EXTRA_CONFIG_VOLUME_ID_KEY: fake_volume['id']}
volume_ops.clone_backing.assert_called_with(fake_volume['name'],
fake_backing,
fake_snapshot,
fake_type,
None,
host=None,
resource_pool=None)
resource_pool=None,
extra_config=extra_config)
# If the volume size is greater than the original snapshot size,
# _extend_vmdk_virtual_disk will be called.
_extend_vmdk_virtual_disk.assert_called_with(fake_volume['name'],
@@ -2100,6 +2109,7 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
fake_summary.datastore = fake_datastore
fake_size = 3
fake_volume = {'volume_type_id': None, 'name': 'fake_name',
'id': '51e47214-8e3c-475d-b44b-aea6cd3eef53',
'size': fake_size}
fake_snapshot = {'volume_name': 'volume_name', 'name': 'snapshot_name',
'volume_size': 2}
@@ -2110,6 +2120,7 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
volumeops.FULL_CLONE_TYPE,
fake_snapshot['volume_size'])
_select_ds_for_volume.assert_called_with(fake_volume)
extra_config = {vmdk.EXTRA_CONFIG_VOLUME_ID_KEY: fake_volume['id']}
volume_ops.clone_backing.assert_called_with(fake_volume['name'],
fake_backing,
fake_snapshot,
@@ -2117,7 +2128,8 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
fake_datastore,
host=fake_host,
resource_pool=
fake_resource_pool)
fake_resource_pool,
extra_config=extra_config)
# If the volume size is greater than the original snapshot size,
# _extend_vmdk_virtual_disk will be called.
_extend_vmdk_virtual_disk.assert_called_with(fake_volume['name'],
@@ -2552,16 +2564,20 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
select_ds_for_volume.return_value = (host, resource_pool, folder,
summary)
volume = {'name': 'vol-1', 'volume_type_id': None, 'size': 1}
volume = {'name': 'vol-1', 'volume_type_id': None, 'size': 1,
'id': 'd11a82de-ddaa-448d-b50a-a255a7e61a1e'}
create_params = {vmdk.CREATE_PARAM_DISK_LESS: True}
self._driver._create_backing(volume, host, create_params)
vops.create_backing_disk_less.assert_called_once_with('vol-1',
folder,
resource_pool,
host,
summary.name,
None)
extra_config = {vmdk.EXTRA_CONFIG_VOLUME_ID_KEY: volume['id']}
vops.create_backing_disk_less.assert_called_once_with(
'vol-1',
folder,
resource_pool,
host,
summary.name,
profileId=None,
extra_config=extra_config)
create_params = {vmdk.CREATE_PARAM_ADAPTER_TYPE: 'ide'}
self._driver._create_backing(volume, host, create_params)
@@ -2573,8 +2589,9 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
resource_pool,
host,
summary.name,
None,
'ide')
profileId=None,
adapter_type='ide',
extra_config=extra_config)
vops.create_backing.reset_mock()
backing_name = "temp-vol"
@@ -2588,8 +2605,9 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
resource_pool,
host,
summary.name,
None,
'lsiLogic')
profileId=None,
adapter_type='lsiLogic',
extra_config=extra_config)
@mock.patch('cinder.openstack.common.fileutils.ensure_tree')
@mock.patch('cinder.openstack.common.fileutils.delete_if_exists')

View File

@@ -661,18 +661,48 @@ class VolumeOpsTestCase(test.TestCase):
name = mock.sentinel.name
ds_name = mock.sentinel.ds_name
profile_id = mock.sentinel.profile_id
ret = self.vops._get_create_spec_disk_less(name, ds_name, profile_id)
option_key = mock.sentinel.key
option_value = mock.sentinel.value
extra_config = {option_key: option_value}
ret = self.vops._get_create_spec_disk_less(name, ds_name, profile_id,
extra_config)
factory.create.side_effect = None
self.assertEqual(name, ret.name)
self.assertEqual('[%s]' % ds_name, ret.files.vmPathName)
self.assertEqual("vmx-08", ret.version)
self.assertEqual(profile_id, ret.vmProfile[0].profileId)
self.assertEqual(1, len(ret.extraConfig))
self.assertEqual(option_key, ret.extraConfig[0].key)
self.assertEqual(option_value, ret.extraConfig[0].value)
expected = [mock.call.create('ns0:VirtualMachineFileInfo'),
mock.call.create('ns0:VirtualMachineConfigSpec'),
mock.call.create('ns0:VirtualMachineDefinedProfileSpec')]
mock.call.create('ns0:VirtualMachineDefinedProfileSpec'),
mock.call.create('ns0:OptionValue')]
factory.create.assert_has_calls(expected, any_order=True)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'_get_create_spec_disk_less')
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'_create_specs_for_disk_add')
def test_get_create_spec(self, create_specs_for_disk_add,
get_create_spec_disk_less):
name = 'vol-1'
size_kb = 1024
disk_type = 'thin'
ds_name = 'nfs-1'
profileId = mock.sentinel.profile_id
adapter_type = 'busLogic'
extra_config = mock.sentinel.extra_config
self.vops.get_create_spec(name, size_kb, disk_type, ds_name,
profileId, adapter_type, extra_config)
get_create_spec_disk_less.assert_called_once_with(
name, ds_name, profileId=profileId, extra_config=extra_config)
create_specs_for_disk_add.assert_called_once_with(
size_kb, disk_type, adapter_type)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'get_create_spec')
def test_create_backing(self, get_create_spec):
@@ -692,13 +722,14 @@ class VolumeOpsTestCase(test.TestCase):
host = mock.sentinel.host
ds_name = mock.sentinel.ds_name
profile_id = mock.sentinel.profile_id
extra_config = mock.sentinel.extra_config
ret = self.vops.create_backing(name, size_kb, disk_type, folder,
resource_pool, host, ds_name,
profile_id, adapter_type)
profile_id, adapter_type, extra_config)
self.assertEqual(mock.sentinel.result, ret)
get_create_spec.assert_called_once_with(name, size_kb, disk_type,
ds_name, profile_id,
adapter_type)
get_create_spec.assert_called_once_with(
name, size_kb, disk_type, ds_name, profileId=profile_id,
adapter_type=adapter_type, extra_config=extra_config)
self.session.invoke_api.assert_called_once_with(self.session.vim,
'CreateVM_Task',
folder,
@@ -723,12 +754,14 @@ class VolumeOpsTestCase(test.TestCase):
host = mock.sentinel.host
ds_name = mock.sentinel.ds_name
profile_id = mock.sentinel.profile_id
extra_config = mock.sentinel.extra_config
ret = self.vops.create_backing_disk_less(name, folder, resource_pool,
host, ds_name, profile_id)
host, ds_name, profile_id,
extra_config)
self.assertEqual(mock.sentinel.result, ret)
get_create_spec_disk_less.assert_called_once_with(name, ds_name,
profile_id)
get_create_spec_disk_less.assert_called_once_with(
name, ds_name, profileId=profile_id, extra_config=extra_config)
self.session.invoke_api.assert_called_once_with(self.session.vim,
'CreateVM_Task',
folder,
@@ -988,6 +1021,11 @@ class VolumeOpsTestCase(test.TestCase):
self.assertEqual(folder, ret)
get_parent.assert_called_once_with(backing, 'Folder')
def _verify_extra_config(self, option_values, key, value):
self.assertEqual(1, len(option_values))
self.assertEqual(key, option_values[0].key)
self.assertEqual(value, option_values[0].value)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'_get_relocate_spec')
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
@@ -998,28 +1036,38 @@ class VolumeOpsTestCase(test.TestCase):
relocate_spec = mock.sentinel.relocate_spec
get_relocate_spec.return_value = relocate_spec
# Test with empty disk type.
datastore = mock.sentinel.datastore
disk_move_type = mock.sentinel.disk_move_type
snapshot = mock.sentinel.snapshot
disk_type = None
backing = mock.sentinel.backing
host = mock.sentinel.host
rp = mock.sentinel.rp
key = mock.sentinel.key
value = mock.sentinel.value
extra_config = {key: value}
ret = self.vops._get_clone_spec(datastore, disk_move_type, snapshot,
backing, disk_type)
backing, disk_type, host, rp,
extra_config)
self.assertEqual(relocate_spec, ret.location)
self.assertFalse(ret.powerOn)
self.assertFalse(ret.template)
self.assertEqual(snapshot, ret.snapshot)
get_relocate_spec.assert_called_once_with(datastore, None, None,
get_relocate_spec.assert_called_once_with(datastore, rp, host,
disk_move_type, disk_type,
None)
self._verify_extra_config(ret.config.extraConfig, key, value)
# Test with non-empty disk type.
disk_device = mock.sentinel.disk_device
get_disk_device.return_value = disk_device
disk_type = 'thin'
ret = self.vops._get_clone_spec(datastore, disk_move_type, snapshot,
backing, disk_type)
backing, disk_type, host, rp,
extra_config)
factory.create.side_effect = None
self.assertEqual(relocate_spec, ret.location)
@@ -1027,9 +1075,10 @@ class VolumeOpsTestCase(test.TestCase):
self.assertFalse(ret.template)
self.assertEqual(snapshot, ret.snapshot)
get_disk_device.assert_called_once_with(backing)
get_relocate_spec.assert_called_with(datastore, None, None,
get_relocate_spec.assert_called_with(datastore, rp, host,
disk_move_type, disk_type,
disk_device)
self._verify_extra_config(ret.config.extraConfig, key, value)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'_get_clone_spec')
@@ -1056,8 +1105,9 @@ class VolumeOpsTestCase(test.TestCase):
# verify calls
self.assertEqual(mock.sentinel.new_backing, ret)
disk_move_type = 'moveAllDiskBackingsAndDisallowSharing'
get_clone_spec.assert_called_with(datastore, disk_move_type, snapshot,
backing, None, None, None)
get_clone_spec.assert_called_with(
datastore, disk_move_type, snapshot, backing, None, host=None,
resource_pool=None, extra_config=None)
expected = [mock.call(vim_util, 'get_object_property',
self.session.vim, backing, 'parent'),
mock.call(self.session.vim, 'CloneVM_Task', backing,
@@ -1072,27 +1122,32 @@ class VolumeOpsTestCase(test.TestCase):
# verify calls
self.assertEqual(mock.sentinel.new_backing, ret)
disk_move_type = 'createNewChildDiskBacking'
get_clone_spec.assert_called_with(datastore, disk_move_type, snapshot,
backing, None, None, None)
get_clone_spec.assert_called_with(
datastore, disk_move_type, snapshot, backing, None, host=None,
resource_pool=None, extra_config=None)
expected = [mock.call(vim_util, 'get_object_property',
self.session.vim, backing, 'parent'),
mock.call(self.session.vim, 'CloneVM_Task', backing,
folder=folder, name=name, spec=clone_spec)]
self.assertEqual(expected, self.session.invoke_api.mock_calls)
# Test disk type conversion and target host.
# Test with optional params (disk_type, host, resource_pool and
# extra_config).
clone_type = None
disk_type = 'thin'
host = mock.sentinel.host
rp = mock.sentinel.rp
extra_config = mock.sentinel.extra_config
self.session.invoke_api.reset_mock()
ret = self.vops.clone_backing(name, backing, snapshot, clone_type,
datastore, disk_type, host, rp)
datastore, disk_type, host, rp,
extra_config)
self.assertEqual(mock.sentinel.new_backing, ret)
disk_move_type = 'moveAllDiskBackingsAndDisallowSharing'
get_clone_spec.assert_called_with(datastore, disk_move_type, snapshot,
backing, disk_type, host, rp)
get_clone_spec.assert_called_with(
datastore, disk_move_type, snapshot, backing, disk_type, host=host,
resource_pool=rp, extra_config=extra_config)
expected = [mock.call(vim_util, 'get_object_property',
self.session.vim, backing, 'parent'),
mock.call(self.session.vim, 'CloneVM_Task', backing,

View File

@@ -60,6 +60,8 @@ CREATE_PARAM_BACKING_NAME = 'name'
TMP_IMAGES_DATASTORE_FOLDER_PATH = "cinder_temp/"
EXTRA_CONFIG_VOLUME_ID_KEY = "cinder.volume.id"
vmdk_opts = [
cfg.StrOpt('vmware_host_ip',
default=None,
@@ -414,6 +416,9 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
profile_id = profile.uniqueId
return profile_id
def _get_extra_config(self, volume):
return {EXTRA_CONFIG_VOLUME_ID_KEY: volume['id']}
def _create_backing(self, volume, host=None, create_params=None):
"""Create volume backing under the given host.
@@ -436,17 +441,21 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
backing_name = create_params.get(CREATE_PARAM_BACKING_NAME,
volume['name'])
extra_config = self._get_extra_config(volume)
# default is a backing with single disk
disk_less = create_params.get(CREATE_PARAM_DISK_LESS, False)
if disk_less:
# create a disk-less backing-- disk can be added later; for e.g.,
# by copying an image
return self.volumeops.create_backing_disk_less(backing_name,
folder,
resource_pool,
host_ref,
summary.name,
profile_id)
return self.volumeops.create_backing_disk_less(
backing_name,
folder,
resource_pool,
host_ref,
summary.name,
profileId=profile_id,
extra_config=extra_config)
# create a backing with single disk
disk_type = VMwareEsxVmdkDriver._get_disk_type(volume)
@@ -460,8 +469,9 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
resource_pool,
host_ref,
summary.name,
profile_id,
adapter_type)
profileId=profile_id,
adapter_type=adapter_type,
extra_config=extra_config)
def _relocate_backing(self, volume, backing, host):
pass
@@ -1113,12 +1123,15 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
# The size of stream optimized glance image is often suspect,
# so better let VC figure out the disk capacity during import.
dummy_disk_size = 0
vm_create_spec = self.volumeops.get_create_spec(volume['name'],
dummy_disk_size,
disk_type,
summary.name,
profile_id,
adapter_type)
extra_config = self._get_extra_config(volume)
vm_create_spec = self.volumeops.get_create_spec(
volume['name'],
dummy_disk_size,
disk_type,
summary.name,
profileId=profile_id,
adapter_type=adapter_type,
extra_config=extra_config)
# convert vm_create_spec to vm_import_spec
cf = self.session.vim.client.factory
vm_import_spec = cf.create('ns0:VirtualMachineImportSpec')
@@ -1619,11 +1632,13 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
profile_id = self._get_storage_profile_id(volume)
disk_type = VMwareEsxVmdkDriver._get_disk_type(volume)
vm_create_spec = self.volumeops.get_create_spec(name,
0,
disk_type,
summary.name,
profile_id)
extra_config = self._get_extra_config(volume)
# We cannot determine the size of a virtual disk created from
# streamOptimized disk image. Set size to 0 and let vCenter
# figure out the size after virtual disk creation.
vm_create_spec = self.volumeops.get_create_spec(
name, 0, disk_type, summary.name, profileId=profile_id,
extra_config=extra_config)
vm_import_spec.configSpec = vm_create_spec
timeout = self.configuration.vmware_image_transfer_timeout_secs
@@ -1954,9 +1969,11 @@ class VMwareVcVmdkDriver(VMwareEsxVmdkDriver):
# Pick a datastore where to create the full clone under any host
(host, rp, _folder, summary) = self._select_ds_for_volume(volume)
datastore = summary.datastore
extra_config = self._get_extra_config(volume)
clone = self.volumeops.clone_backing(volume['name'], backing,
snapshot, clone_type, datastore,
host=host, resource_pool=rp)
host=host, resource_pool=rp,
extra_config=extra_config)
# If the volume size specified by the user is greater than
# the size of the source volume, the newly created volume will
# allocate the capacity to the size of the source volume in the backend

View File

@@ -23,6 +23,7 @@ from oslo_utils import units
from oslo_vmware import exceptions
from oslo_vmware import pbm
from oslo_vmware import vim_util
import six
from six.moves import urllib
from cinder.i18n import _, _LE, _LI
@@ -682,12 +683,28 @@ class VMwareVolumeOps(object):
specs.append(controller_spec)
return specs
def _get_create_spec_disk_less(self, name, ds_name, profileId=None):
def _get_extra_config_option_values(self, extra_config):
cf = self._session.vim.client.factory
option_values = []
for key, value in six.iteritems(extra_config):
opt = cf.create('ns0:OptionValue')
opt.key = key
opt.value = value
option_values.append(opt)
return option_values
def _get_create_spec_disk_less(self, name, ds_name, profileId=None,
extra_config=None):
"""Return spec for creating disk-less backing.
:param name: Name of the backing
:param ds_name: Datastore name where the disk is to be provisioned
:param profileId: storage profile ID for the backing
:param profileId: Storage profile ID for the backing
:param extra_config: Key-value pairs to be written to backing's
extra-config
:return: Spec for creation
"""
cf = self._session.vim.client.factory
@@ -711,10 +728,15 @@ class VMwareVolumeOps(object):
vmProfile.profileId = profileId
create_spec.vmProfile = [vmProfile]
if extra_config:
create_spec.extraConfig = self._get_extra_config_option_values(
extra_config)
return create_spec
def get_create_spec(self, name, size_kb, disk_type, ds_name,
profileId=None, adapter_type='lsiLogic'):
profileId=None, adapter_type='lsiLogic',
extra_config=None):
"""Return spec for creating backing with a single disk.
:param name: name of the backing
@@ -723,9 +745,12 @@ class VMwareVolumeOps(object):
:param ds_name: datastore name where the disk is to be provisioned
:param profileId: storage profile ID for the backing
:param adapter_type: disk adapter type
:param extra_config: key-value pairs to be written to backing's
extra-config
:return: spec for creation
"""
create_spec = self._get_create_spec_disk_less(name, ds_name, profileId)
create_spec = self._get_create_spec_disk_less(
name, ds_name, profileId=profileId, extra_config=extra_config)
create_spec.deviceChange = self._create_specs_for_disk_add(
size_kb, disk_type, adapter_type)
return create_spec
@@ -742,7 +767,8 @@ class VMwareVolumeOps(object):
return backing
def create_backing(self, name, size_kb, disk_type, folder, resource_pool,
host, ds_name, profileId=None, adapter_type='lsiLogic'):
host, ds_name, profileId=None, adapter_type='lsiLogic',
extra_config=None):
"""Create backing for the volume.
Creates a VM with one VMDK based on the given inputs.
@@ -754,8 +780,10 @@ class VMwareVolumeOps(object):
:param resource_pool: Resource pool reference
:param host: Host reference
:param ds_name: Datastore name where the disk is to be provisioned
:param profileId: storage profile ID to be associated with backing
:param profileId: Storage profile ID to be associated with backing
:param adapter_type: Disk adapter type
:param extra_config: Key-value pairs to be written to backing's
extra-config
:return: Reference to the created backing entity
"""
LOG.debug("Creating volume backing with name: %(name)s "
@@ -768,13 +796,15 @@ class VMwareVolumeOps(object):
'ds_name': ds_name, 'profile': profileId, 'host': host,
'adapter_type': adapter_type})
create_spec = self.get_create_spec(name, size_kb, disk_type, ds_name,
profileId, adapter_type)
create_spec = self.get_create_spec(
name, size_kb, disk_type, ds_name, profileId=profileId,
adapter_type=adapter_type, extra_config=extra_config)
return self._create_backing_int(folder, resource_pool, host,
create_spec)
def create_backing_disk_less(self, name, folder, resource_pool,
host, ds_name, profileId=None):
host, ds_name, profileId=None,
extra_config=None):
"""Create disk-less volume backing.
This type of backing is useful for creating volume from image. The
@@ -787,6 +817,8 @@ class VMwareVolumeOps(object):
:param host: Host reference
:param ds_name: Name of the datastore used for VM storage
:param profileId: Storage profile ID to be associated with backing
:param extra_config: Key-value pairs to be written to backing's
extra-config
:return: Reference to the created backing entity
"""
LOG.debug("Creating disk-less volume backing with name: %(name)s "
@@ -797,7 +829,8 @@ class VMwareVolumeOps(object):
'resource_pool': resource_pool, 'host': host,
'ds_name': ds_name})
create_spec = self._get_create_spec_disk_less(name, ds_name, profileId)
create_spec = self._get_create_spec_disk_less(
name, ds_name, profileId=profileId, extra_config=extra_config)
return self._create_backing_int(folder, resource_pool, host,
create_spec)
@@ -1023,7 +1056,8 @@ class VMwareVolumeOps(object):
return self._get_parent(backing, 'Folder')
def _get_clone_spec(self, datastore, disk_move_type, snapshot, backing,
disk_type, host=None, resource_pool=None):
disk_type, host=None, resource_pool=None,
extra_config=None):
"""Get the clone spec.
:param datastore: Reference to datastore
@@ -1033,6 +1067,8 @@ class VMwareVolumeOps(object):
:param disk_type: Disk type of clone
:param host: Target host
:param resource_pool: Target resource pool
:param extra_config: Key-value pairs to be written to backing's
extra-config
:return: Clone spec
"""
if disk_type is not None:
@@ -1050,11 +1086,18 @@ class VMwareVolumeOps(object):
clone_spec.template = False
clone_spec.snapshot = snapshot
if extra_config:
config_spec = cf.create('ns0:VirtualMachineConfigSpec')
config_spec.extraConfig = self._get_extra_config_option_values(
extra_config)
clone_spec.config = config_spec
LOG.debug("Spec for cloning the backing: %s.", clone_spec)
return clone_spec
def clone_backing(self, name, backing, snapshot, clone_type, datastore,
disk_type=None, host=None, resource_pool=None):
disk_type=None, host=None, resource_pool=None,
extra_config=None):
"""Clone backing.
If the clone_type is 'full', then a full clone of the source volume
@@ -1069,6 +1112,8 @@ class VMwareVolumeOps(object):
:param disk_type: Disk type of the clone
:param host: Target host
:param resource_pool: Target resource pool
:param extra_config: Key-value pairs to be written to backing's
extra-config
"""
LOG.debug("Creating a clone of backing: %(back)s, named: %(name)s, "
"clone type: %(type)s from snapshot: %(snap)s on "
@@ -1082,9 +1127,9 @@ class VMwareVolumeOps(object):
disk_move_type = 'createNewChildDiskBacking'
else:
disk_move_type = 'moveAllDiskBackingsAndDisallowSharing'
clone_spec = self._get_clone_spec(datastore, disk_move_type, snapshot,
backing, disk_type, host,
resource_pool)
clone_spec = self._get_clone_spec(
datastore, disk_move_type, snapshot, backing, disk_type, host=host,
resource_pool=resource_pool, extra_config=extra_config)
task = self._session.invoke_api(self._session.vim, 'CloneVM_Task',
backing, folder=folder, name=name,
spec=clone_spec)