Provide allocation_ratio/reserved amounts from update_provider_tree()

The purpose of the RT._normalize_inventory_from_cn_obj method is
to set allocation_ratio and reserved amounts on standard resource
class inventory records that get sent to placement if the virt driver
did not specifically set a ratio or reserved value (which none but
the ironic driver do).

If the allocation_ratio or reserved amount is in the inventory
data dict from the virt driver, then the normalize method ignores
it and lets the virt driver take priority.

However, with change I6a706ec5966cdc85f97223617662fe15d3e6dc08,
any virt driver that implements the update_provider_tree() interface
is storing the inventory data on the ProviderTree object which gets
cached and re-used, meaning once allocation_ratio/reserved is set
from RT._normalize_inventory_from_cn_obj, it doesn't get unset and
the normalize method always assumes the driver provided a value which
should not be changed, even if the configuration value changes.

We can make the config option changes take effect by changing
the semantics between _normalize_inventory_from_cn_obj and
drivers that implement the update_provider_tree interface, like
for the libvirt driver. Effectively with this change, when a driver
implements update_provider_tree(), they now control setting the
allocation_ratio and reserved resource amounts for inventory they
report. The libvirt driver will use the same configuration option
values that _normalize_inventory_from_cn_obj used. The only difference
is in update_provider_tree we don't have the ComputeNode facade to
get the "real" default values when the allocation_ratio is 0.0, so
we handle that like "CONF.cpu_allocation_ratio or 16.0". Eventually
that will get cleaned up with blueprint initial-allocation-ratios.

Change-Id: I72c83a95dabd581998470edb9543079acb6536a5
Closes-Bug: #1799727
This commit is contained in:
Matt Riedemann 2018-10-24 13:48:06 -04:00
parent a0eacbf7ff
commit ca279c68a5
7 changed files with 61 additions and 22 deletions

View File

@ -151,6 +151,13 @@ would become:
}
provider_tree.update_inventory(nodename, inv_data)
When reporting inventory for the standard resource classes ``VCPU``,
``MEMORY_MB`` and ``DISK_GB``, implementors of ``update_provider_tree`` may
need to set the ``allocation_ratio`` and ``reserved`` values in the
``inv_data`` dict based on configuration to reflect changes on the compute
for allocation ratios and reserved resource amounts back to the placement
service.
Porting from get_traits
~~~~~~~~~~~~~~~~~~~~~~~
To replace ``get_traits``, developers should use the

View File

@ -944,6 +944,10 @@ class ResourceTracker(object):
# compute_node record if not set by the virt driver) because the
# virt driver does not and will not have access to the compute_node
inv_data = prov_tree.data(nodename).inventory
# TODO(mriedem): Stop calling _normalize_inventory_from_cn_obj when
# a virt driver implements update_provider_tree() since we expect
# the driver to manage the allocation ratios and reserved resource
# amounts.
_normalize_inventory_from_cn_obj(inv_data, compute_node)
prov_tree.update_inventory(nodename, inv_data)
# Flush any changes. If we processed ReshapeNeeded above, allocs is

View File

@ -284,6 +284,14 @@ class TestUpdateComputeNodeReservedAndAllocationRatio(
CONF.reserved_host_disk_mb)
}
def _assert_reserved_inventory(self, inventories):
reserved = self._get_reserved_host_values_from_config()
for rc, res in reserved.items():
self.assertIn('reserved', inventories[rc])
self.assertEqual(res, inventories[rc]['reserved'],
'Unexpected resource provider inventory '
'reserved value for %s' % rc)
def test_update_inventory_reserved_and_allocation_ratio_from_conf(self):
# Start a compute service which should create a corresponding resource
# provider in the placement service.
@ -310,11 +318,7 @@ class TestUpdateComputeNodeReservedAndAllocationRatio(
self.assertIn('allocation_ratio', inventories[rc])
self.assertEqual(ratio, inventories[rc]['allocation_ratio'],
'Unexpected allocation ratio for %s' % rc)
reserved = self._get_reserved_host_values_from_config()
for rc, res in reserved.items():
self.assertIn('reserved', inventories[rc])
self.assertEqual(res, inventories[rc]['reserved'],
'Unexpected reserved value for %s' % rc)
self._assert_reserved_inventory(inventories)
# Now change the configuration values, restart the compute service,
# and ensure the changes are reflected in the resource provider
@ -352,18 +356,9 @@ class TestUpdateComputeNodeReservedAndAllocationRatio(
ratio, getattr(cn, '%s_allocation_ratio' % attr_map[rc]),
'Unexpected ComputeNode allocation ratio for %s' % rc)
# Make sure the values in placement are updated.
# FIXME(mriedem): The config-driven allocation ratio overrides
# are not reflected in placement until bug 1799727 is fixed.
self.assertNotEqual(ratio, inventories[rc]['allocation_ratio'],
'Unexpected resource provider inventory '
'allocation ratio for %s' % rc)
self.assertEqual(ratio, inventories[rc]['allocation_ratio'],
'Unexpected resource provider inventory '
'allocation ratio for %s' % rc)
# The reserved host values should also come from config.
reserved = self._get_reserved_host_values_from_config()
for rc, res in reserved.items():
self.assertIn('reserved', inventories[rc])
# FIXME(mriedem): The config-driven reserved overrides
# are not reflected in placement until bug 1799727 is fixed.
self.assertNotEqual(res, inventories[rc]['reserved'],
'Unexpected resource provider inventory '
'reserved value for %s' % rc)
self._assert_reserved_inventory(inventories)

View File

@ -17962,18 +17962,24 @@ class TestUpdateProviderTree(test.NoDBTestCase):
'min_unit': 1,
'max_unit': self.vcpus,
'step_size': 1,
'allocation_ratio': 16.0,
'reserved': 0,
},
rc_fields.ResourceClass.MEMORY_MB: {
'total': self.memory_mb,
'min_unit': 1,
'max_unit': self.memory_mb,
'step_size': 1,
'allocation_ratio': 1.5,
'reserved': 512,
},
rc_fields.ResourceClass.DISK_GB: {
'total': self.disk_gb,
'min_unit': 1,
'max_unit': self.disk_gb,
'step_size': 1,
'allocation_ratio': 1.0,
'reserved': 0,
},
}

View File

@ -857,6 +857,11 @@ class ComputeDriver(object):
"""
raise NotImplementedError()
@staticmethod
def _get_reserved_host_disk_gb_from_config():
import nova.compute.utils as compute_utils # avoid circular import
return compute_utils.convert_mb_to_ceil_gb(CONF.reserved_host_disk_mb)
def update_provider_tree(self, provider_tree, nodename, allocations=None):
"""Update a ProviderTree object with current resource provider and
inventory information.
@ -869,6 +874,12 @@ class ComputeDriver(object):
This method supersedes get_inventory(): if this method is implemented,
get_inventory() is not used.
Implementors of this interface are expected to set ``allocation_ratio``
and ``reserved`` values for inventory records, which may be based on
configuration options, e.g. ``[DEFAULT]/cpu_allocation_ratio``,
depending on the driver and resource class. If not provided, allocation
ratio defaults to 1.0 and reserved defaults to 0 in placement.
:note: Renaming the root provider (by deleting it from provider_tree
and re-adding it with a different name) is not supported at this time.

View File

@ -500,24 +500,34 @@ class FakeDriver(driver.ComputeDriver):
return host_status
def update_provider_tree(self, provider_tree, nodename, allocations=None):
# TODO(mriedem): The allocation_ratio config usage will change with
# blueprint initial-allocation-ratios. For now, the allocation ratio
# config values all default to 0.0 and the ComputeNode provides a
# facade for giving the real defaults, so we have to mimic that here.
inventory = {
'VCPU': {
'total': self.vcpus,
'min_unit': 1,
'max_unit': self.vcpus,
'step_size': 1,
'allocation_ratio': CONF.cpu_allocation_ratio or 16.0,
'reserved': CONF.reserved_host_cpus,
},
'MEMORY_MB': {
'total': self.memory_mb,
'min_unit': 1,
'max_unit': self.memory_mb,
'step_size': 1,
'allocation_ratio': CONF.ram_allocation_ratio or 1.5,
'reserved': CONF.reserved_host_memory_mb,
},
'DISK_GB': {
'total': self.local_gb,
'min_unit': 1,
'max_unit': self.local_gb,
'step_size': 1,
'allocation_ratio': CONF.disk_allocation_ratio or 1.0,
'reserved': self._get_reserved_host_disk_gb_from_config(),
},
}
provider_tree.update_inventory(nodename, inventory)

View File

@ -6455,22 +6455,26 @@ class LibvirtDriver(driver.ComputeDriver):
# TODO(sbauza): Use traits to make a better world.
vgpus = self._get_vgpu_total()
# NOTE(jaypipes): We leave some fields like allocation_ratio and
# reserved out of the returned dicts here because, for now at least,
# the RT injects those values into the inventory dict based on the
# compute_nodes record values.
# TODO(mriedem): The allocation_ratio config usage will change with
# blueprint initial-allocation-ratios. For now, the allocation ratio
# config values all default to 0.0 and the ComputeNode provides a
# facade for giving the real defaults, so we have to mimic that here.
result = {
rc_fields.ResourceClass.VCPU: {
'total': vcpus,
'min_unit': 1,
'max_unit': vcpus,
'step_size': 1,
'allocation_ratio': CONF.cpu_allocation_ratio or 16.0,
'reserved': CONF.reserved_host_cpus,
},
rc_fields.ResourceClass.MEMORY_MB: {
'total': memory_mb,
'min_unit': 1,
'max_unit': memory_mb,
'step_size': 1,
'allocation_ratio': CONF.ram_allocation_ratio or 1.5,
'reserved': CONF.reserved_host_memory_mb,
},
}
@ -6486,6 +6490,8 @@ class LibvirtDriver(driver.ComputeDriver):
'min_unit': 1,
'max_unit': disk_gb,
'step_size': 1,
'allocation_ratio': CONF.disk_allocation_ratio or 1.0,
'reserved': self._get_reserved_host_disk_gb_from_config(),
}
if vgpus > 0: