Merge "VMware: ephemeral disk support"
This commit is contained in:
commit
e6983a1ff5
|
@ -385,12 +385,15 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||
'flavorid': '1', 'vcpu_weight': None, 'id': 2}
|
||||
|
||||
def _create_instance(self, node=None, set_image_ref=True,
|
||||
uuid=None, instance_type='m1.large'):
|
||||
uuid=None, instance_type='m1.large',
|
||||
ephemeral=None):
|
||||
if not node:
|
||||
node = self.node_name
|
||||
if not uuid:
|
||||
uuid = uuidutils.generate_uuid()
|
||||
self.type_data = self._get_instance_type_by_name(instance_type)
|
||||
if ephemeral is not None:
|
||||
self.type_data['ephemeral_gb'] = ephemeral
|
||||
values = {'name': 'fake_name',
|
||||
'id': 1,
|
||||
'uuid': uuid,
|
||||
|
@ -416,17 +419,19 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||
self.context, **values)
|
||||
|
||||
def _create_vm(self, node=None, num_instances=1, uuid=None,
|
||||
instance_type='m1.large', powered_on=True):
|
||||
instance_type='m1.large', powered_on=True,
|
||||
ephemeral=None, bdi=None):
|
||||
"""Create and spawn the VM."""
|
||||
if not node:
|
||||
node = self.node_name
|
||||
self._create_instance(node=node, uuid=uuid,
|
||||
instance_type=instance_type)
|
||||
instance_type=instance_type,
|
||||
ephemeral=ephemeral)
|
||||
self.assertIsNone(vm_util.vm_ref_cache_get(self.uuid))
|
||||
self.conn.spawn(self.context, self.instance, self.image,
|
||||
injected_files=[], admin_password=None,
|
||||
network_info=self.network_info,
|
||||
block_device_info=None)
|
||||
block_device_info=bdi)
|
||||
self._check_vm_record(num_instances=num_instances,
|
||||
powered_on=powered_on)
|
||||
self.assertIsNotNone(vm_util.vm_ref_cache_get(self.uuid))
|
||||
|
@ -644,6 +649,35 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||
self._create_vm()
|
||||
self.assertEqual(self.iso_index, 2)
|
||||
|
||||
def test_ephemeral_disk_attach(self):
|
||||
self._create_vm(ephemeral=50)
|
||||
path = ds_util.DatastorePath(self.ds, self.uuid,
|
||||
'ephemeral_0.vmdk')
|
||||
self.assertTrue(vmwareapi_fake.get_file(str(path)))
|
||||
|
||||
def test_ephemeral_disk_attach_from_bdi(self):
|
||||
ephemerals = [{'device_type': 'disk',
|
||||
'disk_bus': 'lsiLogic',
|
||||
'size': 25},
|
||||
{'device_type': 'disk',
|
||||
'disk_bus': 'lsiLogic',
|
||||
'size': 25}]
|
||||
bdi = {'ephemerals': ephemerals}
|
||||
self._create_vm(bdi=bdi, ephemeral=50)
|
||||
path = ds_util.DatastorePath(self.ds, self.uuid,
|
||||
'ephemeral_0.vmdk')
|
||||
self.assertTrue(vmwareapi_fake.get_file(str(path)))
|
||||
path = ds_util.DatastorePath(self.ds, self.uuid,
|
||||
'ephemeral_1.vmdk')
|
||||
self.assertTrue(vmwareapi_fake.get_file(str(path)))
|
||||
|
||||
def test_ephemeral_disk_attach_from_bdii_with_no_ephs(self):
|
||||
bdi = {'ephemerals': []}
|
||||
self._create_vm(bdi=bdi, ephemeral=50)
|
||||
path = ds_util.DatastorePath(self.ds, self.uuid,
|
||||
'ephemeral_0.vmdk')
|
||||
self.assertTrue(vmwareapi_fake.get_file(str(path)))
|
||||
|
||||
def test_cdrom_attach_with_config_drive(self):
|
||||
self.flags(force_config_drive=True)
|
||||
|
||||
|
|
|
@ -1089,6 +1089,10 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
|
|||
'fake_policy')
|
||||
self.assertIsNone(profile_spec)
|
||||
|
||||
def test_get_ephemeral_name(self):
|
||||
filename = vm_util.get_ephemeral_name(0)
|
||||
self.assertEqual('ephemeral_0.vmdk', filename)
|
||||
|
||||
|
||||
@mock.patch.object(driver.VMwareAPISession, 'vim', stubs.fake_vim_prop)
|
||||
class VMwareVMUtilGetHostRefTestCase(test.NoDBTestCase):
|
||||
|
|
|
@ -739,7 +739,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
|||
def test_use_iso_image_without_root_disk(self):
|
||||
self._test_use_iso_image(with_root_disk=False)
|
||||
|
||||
def _verify_spawn_method_calls(self, mock_call_method):
|
||||
def _verify_spawn_method_calls(self, mock_call_method, extras=None):
|
||||
# TODO(vui): More explicit assertions of spawn() behavior
|
||||
# are waiting on additional refactoring pertaining to image
|
||||
# handling/manipulation. Till then, we continue to assert on the
|
||||
|
@ -753,6 +753,8 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
|||
'SearchDatastore_Task',
|
||||
'ExtendVirtualDisk_Task',
|
||||
]
|
||||
if extras:
|
||||
expected_methods.extend(extras)
|
||||
|
||||
recorded_methods = [c[1][1] for c in mock_call_method.mock_calls]
|
||||
self.assertEqual(expected_methods, recorded_methods)
|
||||
|
@ -875,7 +877,8 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
|||
else:
|
||||
self.assertFalse(mock_power_on_instance.called)
|
||||
|
||||
if block_device_info:
|
||||
if (block_device_info and
|
||||
'block_device_mapping' in block_device_info):
|
||||
root_disk = block_device_info['block_device_mapping'][0]
|
||||
mock_attach = self._vmops._volumeops.attach_root_volume
|
||||
mock_attach.assert_called_once_with(
|
||||
|
@ -899,7 +902,10 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
|||
upload_file_name,
|
||||
cookies='Fake-CookieJar')
|
||||
self.assertTrue(len(_wait_for_task.mock_calls) > 0)
|
||||
self._verify_spawn_method_calls(_call_method)
|
||||
extras = None
|
||||
if block_device_info and 'ephemerals' in block_device_info:
|
||||
extras = ['CreateVirtualDisk_Task']
|
||||
self._verify_spawn_method_calls(_call_method, extras)
|
||||
|
||||
dc_ref = 'fake_dc_ref'
|
||||
source_file = unicode('[fake_ds] vmware_base/%s/%s.vmdk' %
|
||||
|
@ -992,6 +998,82 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
|
|||
self._test_spawn(block_device_info=block_device_info,
|
||||
config_drive=True)
|
||||
|
||||
def test_spawn_with_block_device_info_ephemerals(self):
|
||||
ephemerals = [{'device_type': 'disk',
|
||||
'disk_bus': 'virtio',
|
||||
'device_name': '/dev/vdb',
|
||||
'size': 1}]
|
||||
block_device_info = {'ephemerals': ephemerals}
|
||||
self._test_spawn(block_device_info=block_device_info)
|
||||
|
||||
def _get_fake_vi(self):
|
||||
image_info = images.VMwareImage(
|
||||
image_id=self._image_id,
|
||||
file_size=7,
|
||||
linked_clone=False)
|
||||
vi = vmops.VirtualMachineInstanceConfigInfo(
|
||||
self._instance, 'fake_uuid', image_info,
|
||||
self._ds, self._dc_info, mock.Mock())
|
||||
return vi
|
||||
|
||||
@mock.patch.object(vm_util, 'create_virtual_disk')
|
||||
def test_create_and_attach_ephemeral_disk(self, mock_create):
|
||||
vi = self._get_fake_vi()
|
||||
self._vmops._volumeops = mock.Mock()
|
||||
mock_attach_disk_to_vm = self._vmops._volumeops.attach_disk_to_vm
|
||||
|
||||
self._vmops._create_and_attach_ephemeral_disk(self._instance,
|
||||
'fake-vm-ref',
|
||||
vi, 1,
|
||||
'fake-adapter-type',
|
||||
'fake-filename')
|
||||
path = str(ds_util.DatastorePath(vi.datastore.name, 'fake_uuid',
|
||||
'fake-filename'))
|
||||
mock_create.assert_called_once_with(
|
||||
self._session, self._dc_info.ref, 'fake-adapter-type',
|
||||
'thin', path, 1)
|
||||
mock_attach_disk_to_vm.assert_called_once_with(
|
||||
'fake-vm-ref', self._instance, 'fake-adapter-type',
|
||||
'thin', path, 1, False)
|
||||
|
||||
def test_create_ephemeral_with_bdi(self):
|
||||
ephemerals = [{'device_type': 'disk',
|
||||
'disk_bus': 'virtio',
|
||||
'device_name': '/dev/vdb',
|
||||
'size': 1}]
|
||||
block_device_info = {'ephemerals': ephemerals}
|
||||
vi = self._get_fake_vi()
|
||||
with mock.patch.object(
|
||||
self._vmops, '_create_and_attach_ephemeral_disk') as mock_caa:
|
||||
self._vmops._create_ephemeral(block_device_info,
|
||||
self._instance,
|
||||
'fake-vm-ref',
|
||||
vi)
|
||||
mock_caa.assert_called_once_with(self._instance, 'fake-vm-ref',
|
||||
vi, 1 * units.Mi, 'virtio',
|
||||
'ephemeral_0.vmdk')
|
||||
|
||||
def _test_create_ephemeral_from_instance(self, bdi):
|
||||
vi = self._get_fake_vi()
|
||||
with mock.patch.object(
|
||||
self._vmops, '_create_and_attach_ephemeral_disk') as mock_caa:
|
||||
self._vmops._create_ephemeral(bdi,
|
||||
self._instance,
|
||||
'fake-vm-ref',
|
||||
vi)
|
||||
mock_caa.assert_called_once_with(self._instance, 'fake-vm-ref',
|
||||
vi, 1 * units.Mi, 'lsiLogic',
|
||||
'ephemeral_0.vmdk')
|
||||
|
||||
def test_create_ephemeral_with_bdi_but_no_ephemerals(self):
|
||||
block_device_info = {'ephemerals': []}
|
||||
self._instance.ephemeral_gb = 1
|
||||
self._test_create_ephemeral_from_instance(block_device_info)
|
||||
|
||||
def test_create_ephemeral_with_no_bdi(self):
|
||||
self._instance.ephemeral_gb = 1
|
||||
self._test_create_ephemeral_from_instance(None)
|
||||
|
||||
def test_build_virtual_machine(self):
|
||||
image_id = nova.tests.unit.image.fake.get_valid_image_id()
|
||||
image = images.VMwareImage(image_id=image_id)
|
||||
|
|
|
@ -22,6 +22,7 @@ DISK_FORMAT_ISO = 'iso'
|
|||
DISK_FORMAT_VMDK = 'vmdk'
|
||||
DISK_FORMATS_ALL = [DISK_FORMAT_ISO, DISK_FORMAT_VMDK]
|
||||
|
||||
DISK_TYPE_THIN = 'thin'
|
||||
DISK_TYPE_SPARSE = 'sparse'
|
||||
DISK_TYPE_THIN = 'thin'
|
||||
DISK_TYPE_PREALLOCATED = 'preallocated'
|
||||
|
|
|
@ -1481,3 +1481,7 @@ def power_off_instance(session, instance, vm_ref=None):
|
|||
LOG.debug("Powered off the VM", instance=instance)
|
||||
except vexc.InvalidPowerStateException:
|
||||
LOG.debug("VM already powered off", instance=instance)
|
||||
|
||||
|
||||
def get_ephemeral_name(id):
|
||||
return 'ephemeral_%d.vmdk' % id
|
||||
|
|
|
@ -477,6 +477,43 @@ class VMwareVMOps(object):
|
|||
LOG.debug("Cleaning up location %s", str(tmp_dir_loc))
|
||||
self._delete_datastore_file(str(tmp_dir_loc), vi.dc_info.ref)
|
||||
|
||||
def _create_and_attach_ephemeral_disk(self, instance, vm_ref, vi, size,
|
||||
adapter_type, filename):
|
||||
path = str(ds_util.DatastorePath(vi.datastore.name, instance.uuid,
|
||||
filename))
|
||||
disk_type = constants.DISK_TYPE_THIN
|
||||
vm_util.create_virtual_disk(
|
||||
self._session, vi.dc_info.ref,
|
||||
adapter_type,
|
||||
disk_type,
|
||||
path,
|
||||
size)
|
||||
|
||||
self._volumeops.attach_disk_to_vm(
|
||||
vm_ref, vi.instance,
|
||||
adapter_type, disk_type,
|
||||
path, size, False)
|
||||
|
||||
def _create_ephemeral(self, bdi, instance, vm_ref, vi):
|
||||
ephemerals = None
|
||||
if bdi is not None:
|
||||
ephemerals = driver.block_device_info_get_ephemerals(bdi)
|
||||
for idx, eph in enumerate(ephemerals):
|
||||
size = eph['size'] * units.Mi
|
||||
adapter_type = eph.get('disk_bus', vi.ii.adapter_type)
|
||||
filename = vm_util.get_ephemeral_name(idx)
|
||||
self._create_and_attach_ephemeral_disk(instance, vm_ref, vi,
|
||||
size, adapter_type,
|
||||
filename)
|
||||
# There may be block devices defined but no ephemerals. In this case
|
||||
# we need to allocate a ephemeral disk if required
|
||||
if not ephemerals and instance.ephemeral_gb:
|
||||
size = instance.ephemeral_gb * units.Mi
|
||||
filename = vm_util.get_ephemeral_name(0)
|
||||
self._create_and_attach_ephemeral_disk(instance, vm_ref, vi,
|
||||
size, vi.ii.adapter_type,
|
||||
filename)
|
||||
|
||||
def spawn(self, context, instance, image_meta, injected_files,
|
||||
admin_password, network_info, block_device_info=None,
|
||||
instance_name=None, power_on=True):
|
||||
|
@ -552,6 +589,9 @@ class VMwareVMOps(object):
|
|||
else:
|
||||
self._use_disk_image_as_full_clone(vm_ref, vi)
|
||||
|
||||
# Create ephemeral disks
|
||||
self._create_ephemeral(block_device_info, instance, vm_ref, vi)
|
||||
|
||||
if configdrive.required_by(instance):
|
||||
self._configure_config_drive(
|
||||
instance, vm_ref, vi.dc_info, vi.datastore,
|
||||
|
|
Loading…
Reference in New Issue