VMware: Optional create backing parameters
The current create backing methods do not support specifying an adapter type for the backing VM. These methods always create a backing VM with a single disk and LSI logic adapter. This change adds optional parameters to create backing methods so that a backing VM can be created without a disk or with a specific adapter type. Partial-Bug: #1284284 Partial-Bug: #1287185 Partial-Bug: #1287176 Change-Id: Ifff64eb2be4af1c4218e810366e25dbecdc5847f
This commit is contained in:
@@ -353,9 +353,9 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
|
||||
volume = FakeObject()
|
||||
volume['name'] = 'vol_name'
|
||||
backing = FakeMor('VirtualMachine', 'my_back')
|
||||
mux = self._driver._create_backing(volume, host1.obj)
|
||||
mux = self._driver._create_backing(volume, host1.obj, {})
|
||||
mux.AndRaise(error_util.VimException('Maintenance mode'))
|
||||
mux = self._driver._create_backing(volume, host2.obj)
|
||||
mux = self._driver._create_backing(volume, host2.obj, {})
|
||||
mux.AndReturn(backing)
|
||||
m.StubOutWithMock(self._volumeops, 'cancel_retrieval')
|
||||
self._volumeops.cancel_retrieval(retrieve_result)
|
||||
@@ -537,6 +537,7 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
|
||||
mox.IgnoreArg(), folder,
|
||||
resource_pool, host,
|
||||
mox.IgnoreArg(),
|
||||
mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(backing)
|
||||
|
||||
m.ReplayAll()
|
||||
@@ -1074,17 +1075,17 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
|
||||
timeout = self._config.vmware_image_transfer_timeout_secs
|
||||
|
||||
image_service.show.return_value = fake_image_meta
|
||||
volumeops._get_create_spec.return_value = fake_vm_create_spec
|
||||
volumeops.get_create_spec.return_value = fake_vm_create_spec
|
||||
volumeops.get_backing.return_value = fake_backing
|
||||
|
||||
# If _select_ds_for_volume raises an exception, _get_create_spec
|
||||
# If _select_ds_for_volume raises an exception, get_create_spec
|
||||
# will not be called.
|
||||
_select_ds_for_volume.side_effect = error_util.VimException('Error')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self._driver.copy_image_to_volume,
|
||||
fake_context, fake_volume,
|
||||
image_service, fake_image_id)
|
||||
self.assertFalse(volumeops._get_create_spec.called)
|
||||
self.assertFalse(volumeops.get_create_spec.called)
|
||||
|
||||
# If the volume size is greater then than the image size,
|
||||
# _extend_vmdk_virtual_disk will be called.
|
||||
@@ -1095,10 +1096,10 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
|
||||
image_service, fake_image_id)
|
||||
image_service.show.assert_called_with(fake_context, fake_image_id)
|
||||
_select_ds_for_volume.assert_called_with(fake_volume)
|
||||
volumeops._get_create_spec.assert_called_with(fake_volume['name'],
|
||||
0,
|
||||
fake_disk_type,
|
||||
fake_summary.name)
|
||||
volumeops.get_create_spec.assert_called_with(fake_volume['name'],
|
||||
0,
|
||||
fake_disk_type,
|
||||
fake_summary.name)
|
||||
self.assertTrue(fetch_optimized_image.called)
|
||||
fetch_optimized_image.assert_called_with(fake_context, timeout,
|
||||
image_service,
|
||||
@@ -1906,3 +1907,37 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
|
||||
"""Test extend_volume."""
|
||||
self._test_extend_volume(volume_ops, _extend_virtual_disk,
|
||||
_select_ds_for_volume)
|
||||
|
||||
@mock.patch.object(VMDK_DRIVER, '_get_folder_ds_summary')
|
||||
@mock.patch.object(VMDK_DRIVER, 'volumeops')
|
||||
def test_create_backing_with_params(self, vops, get_folder_ds_summary):
|
||||
resource_pool = mock.sentinel.resource_pool
|
||||
vops.get_dss_rp.return_value = (mock.Mock(), resource_pool)
|
||||
folder = mock.sentinel.folder
|
||||
summary = mock.sentinel.summary
|
||||
get_folder_ds_summary.return_value = (folder, summary)
|
||||
|
||||
volume = {'name': 'vol-1', 'volume_type_id': None, 'size': 1}
|
||||
host = mock.Mock()
|
||||
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)
|
||||
|
||||
create_params = {vmdk.CREATE_PARAM_ADAPTER_TYPE: 'ide'}
|
||||
self._driver._create_backing(volume, host, create_params)
|
||||
|
||||
vops.create_backing.assert_called_once_with('vol-1',
|
||||
units.Mi,
|
||||
vmdk.THIN_VMDK_TYPE,
|
||||
folder,
|
||||
resource_pool,
|
||||
host,
|
||||
summary.name,
|
||||
None,
|
||||
'ide')
|
||||
|
||||
@@ -402,29 +402,60 @@ class VolumeOpsTestCase(test.TestCase):
|
||||
self.assertEqual(expected_invoke_api,
|
||||
self.session.invoke_api.mock_calls)
|
||||
|
||||
def test_get_create_spec(self):
|
||||
def test_create_specs_for_ide_disk_add(self):
|
||||
factory = self.session.vim.client.factory
|
||||
factory.create.return_value = mock.Mock(spec=object)
|
||||
name = mock.sentinel.name
|
||||
|
||||
size_kb = 0.5
|
||||
disk_type = 'thin'
|
||||
ds_name = mock.sentinel.ds_name
|
||||
ret = self.vops._get_create_spec(name, size_kb, disk_type, ds_name)
|
||||
self.assertEqual(name, ret.name)
|
||||
self.assertEqual('[%s]' % ds_name, ret.files.vmPathName)
|
||||
self.assertEqual(1, ret.deviceChange[1].device.capacityInKB)
|
||||
self.assertEqual("vmx-08", ret.version)
|
||||
expected = [mock.call.create('ns0:VirtualLsiLogicController'),
|
||||
adapter_type = 'ide'
|
||||
ret = self.vops._create_specs_for_disk_add(size_kb, disk_type,
|
||||
adapter_type)
|
||||
self.assertFalse(hasattr(ret[0].device, 'sharedBus'))
|
||||
self.assertEqual(1, ret[1].device.capacityInKB)
|
||||
expected = [mock.call.create('ns0:VirtualIDEController'),
|
||||
mock.call.create('ns0:VirtualDeviceConfigSpec'),
|
||||
mock.call.create('ns0:VirtualDisk'),
|
||||
mock.call.create('ns0:VirtualDiskFlatVer2BackingInfo'),
|
||||
mock.call.create('ns0:VirtualDeviceConfigSpec')]
|
||||
factory.create.assert_has_calls(expected, any_order=True)
|
||||
|
||||
def test_create_specs_for_scsi_disk_add(self):
|
||||
factory = self.session.vim.client.factory
|
||||
factory.create.return_value = mock.Mock(spec=object)
|
||||
|
||||
size_kb = 2
|
||||
disk_type = 'thin'
|
||||
adapter_type = 'lsiLogicsas'
|
||||
ret = self.vops._create_specs_for_disk_add(size_kb, disk_type,
|
||||
adapter_type)
|
||||
self.assertEqual('noSharing', ret[0].device.sharedBus)
|
||||
self.assertEqual(size_kb, ret[1].device.capacityInKB)
|
||||
expected = [mock.call.create('ns0:VirtualLsiLogicSASController'),
|
||||
mock.call.create('ns0:VirtualDeviceConfigSpec'),
|
||||
mock.call.create('ns0:VirtualMachineFileInfo'),
|
||||
mock.call.create('ns0:VirtualMachineConfigSpec')]
|
||||
mock.call.create('ns0:VirtualDisk'),
|
||||
mock.call.create('ns0:VirtualDiskFlatVer2BackingInfo'),
|
||||
mock.call.create('ns0:VirtualDeviceConfigSpec')]
|
||||
factory.create.assert_has_calls(expected, any_order=True)
|
||||
|
||||
def test_get_create_spec_disk_less(self):
|
||||
factory = self.session.vim.client.factory
|
||||
factory.create.return_value = mock.Mock(spec=object)
|
||||
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)
|
||||
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)
|
||||
expected = [mock.call.create('ns0:VirtualMachineFileInfo'),
|
||||
mock.call.create('ns0:VirtualMachineConfigSpec'),
|
||||
mock.call.create('ns0:VirtualMachineDefinedProfileSpec')]
|
||||
factory.create.assert_has_calls(expected, any_order=True)
|
||||
|
||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||
'_get_create_spec')
|
||||
'get_create_spec')
|
||||
def test_create_backing(self, get_create_spec):
|
||||
create_spec = mock.sentinel.create_spec
|
||||
get_create_spec.return_value = create_spec
|
||||
@@ -436,15 +467,49 @@ class VolumeOpsTestCase(test.TestCase):
|
||||
name = 'backing_name'
|
||||
size_kb = mock.sentinel.size_kb
|
||||
disk_type = mock.sentinel.disk_type
|
||||
adapter_type = mock.sentinel.adapter_type
|
||||
folder = mock.sentinel.folder
|
||||
resource_pool = mock.sentinel.resource_pool
|
||||
host = mock.sentinel.host
|
||||
ds_name = mock.sentinel.ds_name
|
||||
profile_id = mock.sentinel.profile_id
|
||||
ret = self.vops.create_backing(name, size_kb, disk_type, folder,
|
||||
resource_pool, host, ds_name)
|
||||
resource_pool, host, ds_name,
|
||||
profile_id, adapter_type)
|
||||
self.assertEqual(mock.sentinel.result, ret)
|
||||
get_create_spec.assert_called_once_with(name, size_kb, disk_type,
|
||||
ds_name, None)
|
||||
ds_name, profile_id,
|
||||
adapter_type)
|
||||
self.session.invoke_api.assert_called_once_with(self.session.vim,
|
||||
'CreateVM_Task',
|
||||
folder,
|
||||
config=create_spec,
|
||||
pool=resource_pool,
|
||||
host=host)
|
||||
self.session.wait_for_task.assert_called_once_with(task)
|
||||
|
||||
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
|
||||
'_get_create_spec_disk_less')
|
||||
def test_create_backing_disk_less(self, get_create_spec_disk_less):
|
||||
create_spec = mock.sentinel.create_spec
|
||||
get_create_spec_disk_less.return_value = create_spec
|
||||
task = mock.sentinel.task
|
||||
self.session.invoke_api.return_value = task
|
||||
task_info = mock.Mock(spec=object)
|
||||
task_info.result = mock.sentinel.result
|
||||
self.session.wait_for_task.return_value = task_info
|
||||
name = 'backing_name'
|
||||
folder = mock.sentinel.folder
|
||||
resource_pool = mock.sentinel.resource_pool
|
||||
host = mock.sentinel.host
|
||||
ds_name = mock.sentinel.ds_name
|
||||
profile_id = mock.sentinel.profile_id
|
||||
ret = self.vops.create_backing_disk_less(name, folder, resource_pool,
|
||||
host, ds_name, profile_id)
|
||||
|
||||
self.assertEqual(mock.sentinel.result, ret)
|
||||
get_create_spec_disk_less.assert_called_once_with(name, ds_name,
|
||||
profile_id)
|
||||
self.session.invoke_api.assert_called_once_with(self.session.vim,
|
||||
'CreateVM_Task',
|
||||
folder,
|
||||
@@ -814,3 +879,34 @@ class VolumeOpsTestCase(test.TestCase):
|
||||
newCapacityKb=fake_size_in_kb,
|
||||
eagerZero=False)
|
||||
self.session.wait_for_task.assert_called_once_with(task)
|
||||
|
||||
|
||||
class ControllerTypeTest(test.TestCase):
|
||||
"""Unit tests for ControllerType."""
|
||||
|
||||
def test_get_controller_type(self):
|
||||
self.assertEqual(volumeops.ControllerType.LSI_LOGIC,
|
||||
volumeops.ControllerType.get_controller_type(
|
||||
'lsiLogic'))
|
||||
self.assertEqual(volumeops.ControllerType.BUS_LOGIC,
|
||||
volumeops.ControllerType.get_controller_type(
|
||||
'busLogic'))
|
||||
self.assertEqual(volumeops.ControllerType.LSI_LOGIC_SAS,
|
||||
volumeops.ControllerType.get_controller_type(
|
||||
'lsiLogicsas'))
|
||||
self.assertEqual(volumeops.ControllerType.IDE,
|
||||
volumeops.ControllerType.get_controller_type(
|
||||
'ide'))
|
||||
self.assertRaises(error_util.InvalidAdapterTypeException,
|
||||
volumeops.ControllerType.get_controller_type,
|
||||
'invalid_type')
|
||||
|
||||
def test_is_scsi_controller(self):
|
||||
self.assertTrue(volumeops.ControllerType.is_scsi_controller(
|
||||
volumeops.ControllerType.LSI_LOGIC))
|
||||
self.assertTrue(volumeops.ControllerType.is_scsi_controller(
|
||||
volumeops.ControllerType.BUS_LOGIC))
|
||||
self.assertTrue(volumeops.ControllerType.is_scsi_controller(
|
||||
volumeops.ControllerType.LSI_LOGIC_SAS))
|
||||
self.assertFalse(volumeops.ControllerType.is_scsi_controller(
|
||||
volumeops.ControllerType.IDE))
|
||||
|
||||
@@ -67,3 +67,8 @@ class VMwaredriverConfigurationException(VMwareDriverException):
|
||||
"""Base class for all configuration exceptions.
|
||||
"""
|
||||
message = _("VMware VMDK driver configuration error.")
|
||||
|
||||
|
||||
class InvalidAdapterTypeException(VMwareDriverException):
|
||||
"""Thrown when the disk adapter type is invalid."""
|
||||
message = _("Invalid disk adapter type: %(invalid_type)s.")
|
||||
|
||||
@@ -46,6 +46,9 @@ THIN_VMDK_TYPE = 'thin'
|
||||
THICK_VMDK_TYPE = 'thick'
|
||||
EAGER_ZEROED_THICK_VMDK_TYPE = 'eagerZeroedThick'
|
||||
|
||||
CREATE_PARAM_ADAPTER_TYPE = 'adapter_type'
|
||||
CREATE_PARAM_DISK_LESS = 'disk_less'
|
||||
|
||||
vmdk_opts = [
|
||||
cfg.StrOpt('vmware_host_ip',
|
||||
default=None,
|
||||
@@ -426,11 +429,13 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
|
||||
EAGER_ZEROED_THICK_VMDK_TYPE),
|
||||
THIN_VMDK_TYPE)
|
||||
|
||||
def _create_backing(self, volume, host):
|
||||
def _create_backing(self, volume, host, create_params={}):
|
||||
"""Create volume backing under the given host.
|
||||
|
||||
:param volume: Volume object
|
||||
:param host: Reference of the host
|
||||
:param create_params: Dictionary specifying optional parameters for
|
||||
backing VM creation
|
||||
:return: Reference to the created backing
|
||||
"""
|
||||
# Get datastores and resource pool of the host
|
||||
@@ -439,21 +444,41 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
|
||||
(folder, summary) = self._get_folder_ds_summary(volume,
|
||||
resource_pool,
|
||||
datastores)
|
||||
disk_type = VMwareEsxVmdkDriver._get_disk_type(volume)
|
||||
size_kb = volume['size'] * units.Mi
|
||||
|
||||
# check if a storage profile needs to be associated with the backing VM
|
||||
storage_profile = self._get_storage_profile(volume)
|
||||
profileId = None
|
||||
if self._storage_policy_enabled and storage_profile:
|
||||
profile = self.volumeops.retrieve_profile_id(storage_profile)
|
||||
if profile:
|
||||
profileId = profile.uniqueId
|
||||
|
||||
# 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(volume['name'],
|
||||
folder,
|
||||
resource_pool,
|
||||
host,
|
||||
summary.name,
|
||||
profileId)
|
||||
|
||||
# create a backing with single disk
|
||||
disk_type = VMwareEsxVmdkDriver._get_disk_type(volume)
|
||||
size_kb = volume['size'] * units.Mi
|
||||
adapter_type = create_params.get(CREATE_PARAM_ADAPTER_TYPE,
|
||||
'lsiLogic')
|
||||
return self.volumeops.create_backing(volume['name'],
|
||||
size_kb,
|
||||
disk_type, folder,
|
||||
disk_type,
|
||||
folder,
|
||||
resource_pool,
|
||||
host,
|
||||
summary.name,
|
||||
profileId)
|
||||
profileId,
|
||||
adapter_type)
|
||||
|
||||
def _relocate_backing(self, volume, backing, host):
|
||||
pass
|
||||
@@ -495,13 +520,15 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
|
||||
LOG.error(msg)
|
||||
raise error_util.VimException(msg)
|
||||
|
||||
def _create_backing_in_inventory(self, volume):
|
||||
def _create_backing_in_inventory(self, volume, create_params={}):
|
||||
"""Creates backing under any suitable host.
|
||||
|
||||
The method tries to pick datastore that can fit the volume under
|
||||
any host in the inventory.
|
||||
|
||||
:param volume: Volume object
|
||||
:param create_params: Dictionary specifying optional parameters for
|
||||
backing VM creation
|
||||
:return: Reference to the created backing
|
||||
"""
|
||||
|
||||
@@ -513,7 +540,9 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
|
||||
backing = None
|
||||
for host in hosts:
|
||||
try:
|
||||
backing = self._create_backing(volume, host.obj)
|
||||
backing = self._create_backing(volume,
|
||||
host.obj,
|
||||
create_params)
|
||||
if backing:
|
||||
break
|
||||
except error_util.VimException as excep:
|
||||
@@ -879,10 +908,10 @@ 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)
|
||||
vm_create_spec = self.volumeops.get_create_spec(volume['name'],
|
||||
dummy_disk_size,
|
||||
disk_type,
|
||||
summary.name)
|
||||
# convert vm_create_spec to vm_import_spec
|
||||
cf = self.session.vim.client.factory
|
||||
vm_import_spec = cf.create('ns0:VirtualMachineImportSpec')
|
||||
|
||||
@@ -57,6 +57,43 @@ def split_datastore_path(datastore_path):
|
||||
return (datastore_name.strip(), folder_path.strip(), file_name.strip())
|
||||
|
||||
|
||||
class ControllerType:
|
||||
"""Encapsulate various controller types."""
|
||||
|
||||
LSI_LOGIC = 'VirtualLsiLogicController'
|
||||
BUS_LOGIC = 'VirtualBusLogicController'
|
||||
LSI_LOGIC_SAS = 'VirtualLsiLogicSASController'
|
||||
IDE = 'VirtualIDEController'
|
||||
|
||||
CONTROLLER_TYPE_DICT = {'lsiLogic': LSI_LOGIC,
|
||||
'busLogic': BUS_LOGIC,
|
||||
'lsiLogicsas': LSI_LOGIC_SAS,
|
||||
'ide': IDE}
|
||||
|
||||
@staticmethod
|
||||
def get_controller_type(adapter_type):
|
||||
"""Get the disk controller type based on the given adapter type.
|
||||
|
||||
:param adapter_type: disk adapter type
|
||||
:return: controller type corresponding to the given adapter type
|
||||
:raises: InvalidAdapterTypeException
|
||||
"""
|
||||
if adapter_type in ControllerType.CONTROLLER_TYPE_DICT:
|
||||
return ControllerType.CONTROLLER_TYPE_DICT[adapter_type]
|
||||
raise error_util.InvalidAdapterTypeException(invalid_type=adapter_type)
|
||||
|
||||
@staticmethod
|
||||
def is_scsi_controller(controller_type):
|
||||
"""Check if the given controller is a SCSI controller.
|
||||
|
||||
:param controller_type: controller type
|
||||
:return: True if the controller is a SCSI controller
|
||||
"""
|
||||
return controller_type in [ControllerType.LSI_LOGIC,
|
||||
ControllerType.BUS_LOGIC,
|
||||
ControllerType.LSI_LOGIC_SAS]
|
||||
|
||||
|
||||
class VMwareVolumeOps(object):
|
||||
"""Manages volume operations."""
|
||||
|
||||
@@ -348,22 +385,21 @@ class VMwareVolumeOps(object):
|
||||
"%(size)s GB."),
|
||||
{'name': name, 'size': requested_size_in_gb})
|
||||
|
||||
def _get_create_spec(self, name, size_kb, disk_type, ds_name,
|
||||
profileId=None):
|
||||
"""Return spec for creating volume backing.
|
||||
def _create_specs_for_disk_add(self, size_kb, disk_type, adapter_type):
|
||||
"""Create controller and disk specs for adding a new disk.
|
||||
|
||||
:param name: Name of the backing
|
||||
:param size_kb: Size in KB of the backing
|
||||
:param disk_type: VMDK type for the disk
|
||||
:param ds_name: Datastore name where the disk is to be provisioned
|
||||
:param profileId: storage profile ID for the backing
|
||||
:return: Spec for creation
|
||||
:param size_kb: disk size in KB
|
||||
:param disk_type: disk provisioning type
|
||||
:param adapter_type: disk adapter type
|
||||
:return: list containing controller and disk specs
|
||||
"""
|
||||
cf = self._session.vim.client.factory
|
||||
controller_device = cf.create('ns0:VirtualLsiLogicController')
|
||||
controller_type = ControllerType.get_controller_type(adapter_type)
|
||||
controller_device = cf.create('ns0:%s' % controller_type)
|
||||
controller_device.key = -100
|
||||
controller_device.busNumber = 0
|
||||
controller_device.sharedBus = 'noSharing'
|
||||
if ControllerType.is_scsi_controller(controller_type):
|
||||
controller_device.sharedBus = 'noSharing'
|
||||
controller_spec = cf.create('ns0:VirtualDeviceConfigSpec')
|
||||
controller_spec.operation = 'add'
|
||||
controller_spec.device = controller_device
|
||||
@@ -387,6 +423,17 @@ class VMwareVolumeOps(object):
|
||||
disk_spec.fileOperation = 'create'
|
||||
disk_spec.device = disk_device
|
||||
|
||||
return [controller_spec, disk_spec]
|
||||
|
||||
def _get_create_spec_disk_less(self, name, ds_name, profileId=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
|
||||
:return: Spec for creation
|
||||
"""
|
||||
cf = self._session.vim.client.factory
|
||||
vm_file_info = cf.create('ns0:VirtualMachineFileInfo')
|
||||
vm_file_info.vmPathName = '[%s]' % ds_name
|
||||
|
||||
@@ -395,7 +442,6 @@ class VMwareVolumeOps(object):
|
||||
create_spec.guestId = 'otherGuest'
|
||||
create_spec.numCPUs = 1
|
||||
create_spec.memoryMB = 128
|
||||
create_spec.deviceChange = [controller_spec, disk_spec]
|
||||
create_spec.files = vm_file_info
|
||||
# set the Hardware version to the lowest version supported by ESXi5.0
|
||||
# and compatible with vCenter Server 5.0
|
||||
@@ -408,11 +454,38 @@ class VMwareVolumeOps(object):
|
||||
vmProfile.profileId = profileId
|
||||
create_spec.vmProfile = [vmProfile]
|
||||
|
||||
LOG.debug("Spec for creating the backing: %s." % create_spec)
|
||||
return create_spec
|
||||
|
||||
def get_create_spec(self, name, size_kb, disk_type, ds_name,
|
||||
profileId=None, adapter_type='lsiLogic'):
|
||||
"""Return spec for creating backing with a single disk.
|
||||
|
||||
:param name: name of the backing
|
||||
:param size_kb: disk size in KB
|
||||
:param disk_type: disk provisioning type
|
||||
: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
|
||||
:return: spec for creation
|
||||
"""
|
||||
create_spec = self._get_create_spec_disk_less(name, ds_name, profileId)
|
||||
create_spec.deviceChange = self._create_specs_for_disk_add(
|
||||
size_kb, disk_type, adapter_type)
|
||||
return create_spec
|
||||
|
||||
def _create_backing_int(self, folder, resource_pool, host, create_spec):
|
||||
"""Helper for create backing methods."""
|
||||
LOG.debug("Creating volume backing with spec: %s.", create_spec)
|
||||
task = self._session.invoke_api(self._session.vim, 'CreateVM_Task',
|
||||
folder, config=create_spec,
|
||||
pool=resource_pool, host=host)
|
||||
task_info = self._session.wait_for_task(task)
|
||||
backing = task_info.result
|
||||
LOG.info(_("Successfully created volume backing: %s."), backing)
|
||||
return backing
|
||||
|
||||
def create_backing(self, name, size_kb, disk_type, folder, resource_pool,
|
||||
host, ds_name, profileId=None):
|
||||
host, ds_name, profileId=None, adapter_type='lsiLogic'):
|
||||
"""Create backing for the volume.
|
||||
|
||||
Creates a VM with one VMDK based on the given inputs.
|
||||
@@ -425,26 +498,51 @@ class VMwareVolumeOps(object):
|
||||
: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 adapter_type: Disk adapter type
|
||||
:return: Reference to the created backing entity
|
||||
"""
|
||||
LOG.debug("Creating volume backing name: %(name)s "
|
||||
"disk_type: %(disk_type)s size_kb: %(size_kb)s at "
|
||||
"folder: %(folder)s resourse pool: %(resource_pool)s "
|
||||
"datastore name: %(ds_name)s profileId: %(profile)s." %
|
||||
LOG.debug("Creating volume backing with name: %(name)s "
|
||||
"disk_type: %(disk_type)s size_kb: %(size_kb)s "
|
||||
"adapter_type: %(adapter_type)s profileId: %(profile)s at "
|
||||
"folder: %(folder)s resource_pool: %(resource_pool)s "
|
||||
"host: %(host)s datastore_name: %(ds_name)s.",
|
||||
{'name': name, 'disk_type': disk_type, 'size_kb': size_kb,
|
||||
'folder': folder, 'resource_pool': resource_pool,
|
||||
'ds_name': ds_name, 'profile': profileId})
|
||||
'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)
|
||||
task = self._session.invoke_api(self._session.vim, 'CreateVM_Task',
|
||||
folder, config=create_spec,
|
||||
pool=resource_pool, host=host)
|
||||
LOG.debug("Initiated creation of volume backing: %s." % name)
|
||||
task_info = self._session.wait_for_task(task)
|
||||
backing = task_info.result
|
||||
LOG.info(_("Successfully created volume backing: %s.") % backing)
|
||||
return backing
|
||||
create_spec = self.get_create_spec(name, size_kb, disk_type, ds_name,
|
||||
profileId, adapter_type)
|
||||
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):
|
||||
"""Create disk-less volume backing.
|
||||
|
||||
This type of backing is useful for creating volume from image. The
|
||||
downloaded image from the image service can be copied to a virtual
|
||||
disk of desired provisioning type and added to the backing VM.
|
||||
|
||||
:param name: Name of the backing
|
||||
:param folder: Folder where the backing is created
|
||||
:param resource_pool: Resource pool reference
|
||||
: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
|
||||
:return: Reference to the created backing entity
|
||||
"""
|
||||
LOG.debug("Creating disk-less volume backing with name: %(name)s "
|
||||
"profileId: %(profile)s at folder: %(folder)s "
|
||||
"resource pool: %(resource_pool)s host: %(host)s "
|
||||
"datastore_name: %(ds_name)s.",
|
||||
{'name': name, 'profile': profileId, 'folder': folder,
|
||||
'resource_pool': resource_pool, 'host': host,
|
||||
'ds_name': ds_name})
|
||||
|
||||
create_spec = self._get_create_spec_disk_less(name, ds_name, profileId)
|
||||
return self._create_backing_int(folder, resource_pool, host,
|
||||
create_spec)
|
||||
|
||||
def get_datastore(self, backing):
|
||||
"""Get datastore where the backing resides.
|
||||
|
||||
Reference in New Issue
Block a user