VMware: add resource limits for disk

The flavor extra specs for quotas has been extended to support
 quota:disk_io_limit - The utilization of a virtual machine will not exceed
                       this limit. The unit is number of I/O per second.
 quota:disk_io_reservation -  Reservation control is used to provide guaranteed
                              allocation in terms of IOPS
 quota:disk_io_shares_level - the allocation level. This can be 'custom', 'high'
                              'normal' or 'low'.
 quota:disk_io_shares_share - in the event that 'custom' is used, this is the
                              number of shares.
This enables the VMware driver to enable disk allocations
for the running instance.

Please see http://goo.gl/6sHwIA for a detailed explanation of the above.

DocImpact

The is part of the blueprint vmware-limits

Change-Id: I6797ad3442895cd73f240590286b4ae13986291f
This commit is contained in:
Gary Kotton 2015-04-30 05:20:13 -07:00
parent 2b992673b5
commit 42524209e2
4 changed files with 37 additions and 16 deletions

View File

@ -1092,6 +1092,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_extend_virtual_disk,
mock_sized_image_exists,
flavor_fits_image=False):
extra_specs = vm_util.ExtraSpecs()
file_size = 10 * units.Gi if flavor_fits_image else 5 * units.Gi
image_info = images.VMwareImage(
image_id=self._image_id,
@ -1103,7 +1104,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_imagecache.get_image_cache_folder.return_value = cache_root_folder
vi = vmops.VirtualMachineInstanceConfigInfo(
self._instance, image_info,
self._ds, self._dc_info, mock_imagecache)
self._ds, self._dc_info, mock_imagecache, extra_specs)
sized_cached_image_ds_loc = cache_root_folder.join(
"%s.%s.vmdk" % (self._image_id, vi.root_gb))
@ -1128,7 +1129,8 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
"fake_vm_ref", self._instance, vi.ii.adapter_type,
vi.ii.disk_type,
str(sized_cached_image_ds_loc),
vi.root_gb * units.Mi, False)
vi.root_gb * units.Mi, False,
disk_io_limits=vi._extra_specs.disk_io_limits)
def test_use_disk_image_as_linked_clone(self):
self._test_use_disk_image_as_linked_clone()
@ -1142,6 +1144,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_copy_virtual_disk,
mock_extend_virtual_disk,
flavor_fits_image=False):
extra_specs = vm_util.ExtraSpecs()
file_size = 10 * units.Gi if flavor_fits_image else 5 * units.Gi
image_info = images.VMwareImage(
image_id=self._image_id,
@ -1153,7 +1156,8 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_imagecache.get_image_cache_folder.return_value = cache_root_folder
vi = vmops.VirtualMachineInstanceConfigInfo(
self._instance, image_info,
self._ds, self._dc_info, mock_imagecache)
self._ds, self._dc_info, mock_imagecache,
extra_specs)
self._vmops._volumeops = mock.Mock()
mock_attach_disk_to_vm = self._vmops._volumeops.attach_disk_to_vm
@ -1173,7 +1177,8 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_attach_disk_to_vm.assert_called_once_with(
"fake_vm_ref", self._instance, vi.ii.adapter_type,
vi.ii.disk_type, '[fake_ds] fake_uuid/fake_uuid.vmdk',
vi.root_gb * units.Mi, False)
vi.root_gb * units.Mi, False,
disk_io_limits=vi._extra_specs.disk_io_limits)
def test_use_disk_image_as_full_clone(self):
self._test_use_disk_image_as_full_clone()
@ -1187,6 +1192,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_create_virtual_disk,
mock_attach_cdrom,
with_root_disk):
extra_specs = vm_util.ExtraSpecs()
image_info = images.VMwareImage(
image_id=self._image_id,
file_size=10 * units.Mi,
@ -1197,7 +1203,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
mock_imagecache.get_image_cache_folder.return_value = cache_root_folder
vi = vmops.VirtualMachineInstanceConfigInfo(
self._instance, image_info,
self._ds, self._dc_info, mock_imagecache)
self._ds, self._dc_info, mock_imagecache, extra_specs)
self._vmops._volumeops = mock.Mock()
mock_attach_disk_to_vm = self._vmops._volumeops.attach_disk_to_vm
@ -1219,7 +1225,8 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
"fake_vm_ref", self._instance,
vi.ii.adapter_type, vi.ii.disk_type,
'[fake_ds] fake_uuid/fake_uuid.vmdk',
vi.root_gb * units.Mi, linked_clone)
vi.root_gb * units.Mi, linked_clone,
disk_io_limits=vi._extra_specs.disk_io_limits)
def test_use_iso_image_with_root_disk(self):
self._test_use_iso_image(with_root_disk=True)

View File

@ -96,7 +96,7 @@ class ExtraSpecs(object):
def __init__(self, cpu_limits=None, hw_version=None,
storage_policy=None, cores_per_socket=None,
memory_limits=None):
memory_limits=None, disk_io_limits=None):
"""ExtraSpecs object holds extra_specs for the instance."""
if cpu_limits is None:
cpu_limits = Limits()
@ -104,6 +104,9 @@ class ExtraSpecs(object):
if memory_limits is None:
memory_limits = Limits()
self.memory_limits = memory_limits
if disk_io_limits is None:
disk_io_limits = Limits()
self.disk_io_limits = disk_io_limits
self.hw_version = hw_version
self.storage_policy = storage_policy
self.cores_per_socket = cores_per_socket
@ -473,7 +476,8 @@ def get_vmdk_attach_config_spec(client_factory,
linked_clone=False,
controller_key=None,
unit_number=None,
device_name=None):
device_name=None,
disk_io_limits=None):
"""Builds the vmdk attach config spec."""
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
@ -481,7 +485,7 @@ def get_vmdk_attach_config_spec(client_factory,
virtual_device_config_spec = create_virtual_disk_spec(client_factory,
controller_key, disk_type, file_path,
disk_size, linked_clone,
unit_number, device_name)
unit_number, device_name, disk_io_limits)
device_config_spec.append(virtual_device_config_spec)
@ -766,7 +770,8 @@ def create_virtual_disk_spec(client_factory, controller_key,
disk_size=None,
linked_clone=False,
unit_number=None,
device_name=None):
device_name=None,
disk_io_limits=None):
"""Builds spec for the creation of a new/ attaching of an already existing
Virtual Disk to the VM.
"""
@ -817,6 +822,11 @@ def create_virtual_disk_spec(client_factory, controller_key,
virtual_disk.unitNumber = unit_number or 0
virtual_disk.capacityInKB = disk_size or 0
if disk_io_limits and disk_io_limits.has_limits():
virtual_disk.storageIOAllocation = _get_allocation_info(
client_factory, disk_io_limits,
'ns0:StorageIOAllocationInfo')
virtual_device_config.device = virtual_disk
return virtual_device_config

View File

@ -307,7 +307,7 @@ class VMwareVMOps(object):
def _get_extra_specs(self, flavor, image_meta=None):
image_meta = image_meta or objects.ImageMeta.from_dict({})
extra_specs = vm_util.ExtraSpecs()
for resource in ['cpu', 'memory']:
for resource in ['cpu', 'memory', 'disk_io']:
for (key, type) in (('limit', int),
('reservation', int),
('shares_level', str),
@ -318,6 +318,7 @@ class VMwareVMOps(object):
key, type(value))
extra_specs.cpu_limits.validate()
extra_specs.memory_limits.validate()
extra_specs.disk_io_limits.validate()
hw_version = flavor.extra_specs.get('vmware:hw_version')
extra_specs.hw_version = hw_version
if CONF.vmware.pbm_enabled:
@ -1688,7 +1689,8 @@ class VMwareVMOps(object):
vm_ref, vi.instance,
vi.ii.adapter_type, vi.ii.disk_type,
str(root_disk_ds_loc),
vi.root_gb * units.Mi, False)
vi.root_gb * units.Mi, False,
disk_io_limits=vi._extra_specs.disk_io_limits)
def _sized_image_exists(self, sized_disk_ds_loc, ds_ref):
ds_browser = self._get_ds_browser(ds_ref)
@ -1761,7 +1763,8 @@ class VMwareVMOps(object):
vm_ref, vi.instance,
vi.ii.adapter_type, vi.ii.disk_type,
str(sized_disk_ds_loc),
vi.root_gb * units.Mi, vi.ii.linked_clone)
vi.root_gb * units.Mi, vi.ii.linked_clone,
disk_io_limits=vi._extra_specs.disk_io_limits)
def _use_iso_image(self, vm_ref, vi):
"""Uses cached image as a bootable virtual cdrom."""
@ -1791,7 +1794,8 @@ class VMwareVMOps(object):
vm_ref, vi.instance,
vi.ii.adapter_type, vi.ii.disk_type,
str(root_disk_ds_loc),
vi.root_gb * units.Mi, linked_clone)
vi.root_gb * units.Mi, linked_clone,
disk_io_limits=vi._extra_specs.disk_io_limits)
def _update_datacenter_cache_from_objects(self, dcs):
"""Updates the datastore/datacenter cache."""

View File

@ -42,7 +42,7 @@ class VMwareVolumeOps(object):
def attach_disk_to_vm(self, vm_ref, instance,
adapter_type, disk_type, vmdk_path=None,
disk_size=None, linked_clone=False,
device_name=None):
device_name=None, disk_io_limits=None):
"""Attach disk to VM by reconfiguration."""
instance_name = instance.name
client_factory = self._session.vim.client.factory
@ -58,7 +58,7 @@ class VMwareVolumeOps(object):
vmdk_attach_config_spec = vm_util.get_vmdk_attach_config_spec(
client_factory, disk_type, vmdk_path,
disk_size, linked_clone, controller_key,
unit_number, device_name)
unit_number, device_name, disk_io_limits)
if controller_spec:
vmdk_attach_config_spec.deviceChange.append(controller_spec)