Merge "Per-Property ImageMetaPropsWeigher"

This commit is contained in:
Zuul
2025-02-25 19:16:49 +00:00
committed by Gerrit Code Review
5 changed files with 129 additions and 3 deletions

View File

@@ -1086,6 +1086,24 @@ A positive value will favor hosts with the same image properties (packing
strategy) while a negative value will follow a spread strategy that will
favor hosts not already having instances with those image properties.
You can also use
:oslo.config:option:`filter_scheduler.image_props_weight_setting` config option
for defining the exact properties you would like to weigh. For example, if you
configure ``os_distro`` to 2 and ``hw_machine_type`` to 0, then the latter
property won't be weighed while the former will count twice. Say you configure
``os_distro=10,os_secure_boot=1,os_require_quiesce=0``, then when requesting
an instance with an image using those properties, then, for each of the
instances already running on the host having an image using at least one of
those properties, a match of the same ``os_distro`` value (eg. ``windows`` or
``linux``) would count 10 times more than a match of the same
``os_secure_boot`` value (eg. ``true`` or ``false``), while any matches about
the same ``os_require_quiesce`` value wouldn't count.
If you define :oslo.config:option:`filter_scheduler.image_props_weight_setting`
then any property from the image used for booting wouldn't be counted if not
provided in the option value.
The resulted host weight would then be multiplied by the value of
:oslo.config:option:`filter_scheduler.image_props_weight_multiplier`.
Utilization-aware scheduling
----------------------------

View File

@@ -589,6 +589,53 @@ Example:
Related options:
* ``[filter_scheduler] weight_classes``
"""),
cfg.ListOpt("image_props_weight_setting",
default=[],
help="""
Mapping of image properties to weight modifier.
This setting specifies the properties to be weighed and the relative ratios for
each property. This should be a list of key/value pairs, consisting of a series
of one or more 'name=ratio' pairs, separated by commas, where ``name`` is the
name of the property to be weighed, and ``ratio`` is the relative weight for
that metric.
Note that if the ratio is set to 0, the property value is ignored, and instead
the weight will be set to the value of the
``[filter_scheduler] image_props_weight_multiplier`` option.
As an example, let's consider the case where this option is set to:
``os_distro=1, hw_machine_type=-1``
If an instance would boot with an image having ``os_distro=windows`` and
``hw_machine_type=q35``, the final host weight will be:
``(nb_inst(``os_distro=windows``) * 1.0) +
(nb_inst(``hw_machine_type=q35``) * -1)``
where nb_inst(``prop=value``) would give me the number of instances having
an image where ``prop`` is set to ``value`` (eg. the number of instances
running with ``os_distro=windows``)
Possible values:
* A list of zero or more key/value pairs separated by commas, where the key is
a string representing the name of a property and the value is a numeric
weight for that property. If any value is set to 0, the number of instances
match is ignored for that specific property key.
If no key/value pairs are provided, then the weigher will compare all the
instance's images with the requested image properties, all of them weighed
evenly.
The overall host weight will be multiplied by the value of the
``[filter_scheduler] image_props_weight_multiplier`` option.
Related options:
* ``[filter_scheduler] image_props_weight_multiplier``
"""),
cfg.FloatOpt("pci_weight_multiplier",
default=1.0,

View File

@@ -30,6 +30,14 @@ CONF = nova.conf.CONF
class ImagePropertiesWeigher(weights.BaseHostWeigher):
def __init__(self):
self._parse_setting()
def _parse_setting(self):
self.setting = dict(utils.parse_options(
CONF.filter_scheduler.image_props_weight_setting,
sep='=', converter=float,
name="filter_scheduler.image_props_weight_setting"))
def weight_multiplier(self, host_state):
"""Override the weight multiplier."""
@@ -81,6 +89,13 @@ class ImagePropertiesWeigher(weights.BaseHostWeigher):
common_props = requested_props & set(existing_props)
for prop in common_props:
weight += existing_props.count(prop)
for (prop, value) in common_props:
if self.setting:
# Calculate the weigh for each property by what was set
# If it wasn't defined, then don't weigh this property.
weight += self.setting.get(
prop, 0.0) * existing_props.count((prop, value))
else:
# By default, all properties are weighed evenly.
weight += existing_props.count((prop, value))
return weight

View File

@@ -152,3 +152,45 @@ class ImagePropertiesWeigherTestCase(test.NoDBTestCase):
self.assertEqual('host3', weights[0].obj.host)
mock_fm.assert_has_calls([mock.call(), mock.call(),
mock.call(), mock.call()])
@mock.patch('nova.objects.InstanceList.fill_metadata')
def test_multiplier_per_property(self, mock_fm):
self.flags(image_props_weight_multiplier=1.0, group='filter_scheduler')
hostinfo_list = self._get_all_hosts()
# For now, don't exclude any property check and boot with an image
# using both hw_machine_type and os_distro properties.
weights = self.weight_handler.get_weighed_objects(
self.weighers, hostinfo_list,
weighing_properties=objects.RequestSpec(image=PROP_LIN_PC))
# host3 is preferred as it has both of the correct properties with
# the right values.
# host2 and host4 only support one of each property.
expected_weights = [{'weight': 1.0, 'host': 'host3'},
{'weight': (1 / 3), 'host': 'host2'},
{'weight': (1 / 3), 'host': 'host4'},
{'weight': 0.0, 'host': 'host1'}]
self.assertEqual(expected_weights, [weigh.to_dict()
for weigh in weights])
self.assertEqual('host3', weights[0].obj.host)
# Now, let's exclude hw_machine_type property to be weighed.
self.flags(image_props_weight_setting=['os_distro=1',
'hw_machine_type=0'],
group='filter_scheduler')
# Force a refresh of the settings since we updated them
self.weighers[0]._parse_setting()
weights = self.weight_handler.get_weighed_objects(
self.weighers, hostinfo_list,
weighing_properties=objects.RequestSpec(image=PROP_LIN_PC))
# host3 and host4 have instances with linux distro but we favor
# host3 given he has more instances having the same requested property
expected_weights = [{'weight': 1.0, 'host': 'host3'},
{'weight': 0.5, 'host': 'host4'},
{'weight': 0.0, 'host': 'host1'},
{'weight': 0.0, 'host': 'host2'}]
self.assertEqual(expected_weights, [weigh.to_dict()
for weigh in weights])
self.assertEqual('host3', weights[0].obj.host)
mock_fm.assert_has_calls([mock.call(), mock.call(),
mock.call(), mock.call()])

View File

@@ -11,4 +11,8 @@ features:
hosts, modify `image_props_weight_multiplier` to a positive value. If you
want to spread instances with the same properties around all hosts, then
please modify `image_props_weight_multiplier` to a negative value.
Another configuration option
`[filter_scheduler]/image_props_weight_setting` allows you to define
fine-grained weights for each of the properties you actually would like to
weigh (eg. `os_distro`). Please refer to the documentation for more details
about how to use this configuration option.