From b29ccf8aa5cf2081ed46ac53741a8600ae40f071 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Fri, 14 May 2021 09:49:08 +0200 Subject: [PATCH] Support same_subtree in allocation_canadidate query Extend the allocation candidate query generation to include same_subtree query parameters based on the RequestSpec. The same_subtree parameter is available since placement microversion 1.36 but we already bumped our minimum placement requirement to 1.36 in a previous patch. Change-Id: I7447bbb49fcee5197b176aa64fd5f2c930f70fc0 blueprint: qos-minimum-guaranteed-packet-rate --- nova/objects/request_spec.py | 7 +++++++ nova/scheduler/utils.py | 5 +++++ nova/tests/unit/scheduler/test_utils.py | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/nova/objects/request_spec.py b/nova/objects/request_spec.py index a3efbd0bf51d..ce4529b2a2f2 100644 --- a/nova/objects/request_spec.py +++ b/nova/objects/request_spec.py @@ -200,6 +200,12 @@ class RequestSpec(base.NovaObject): # respective obj_load_attr methods. return self.request_level_params.root_forbidden + @property + def same_subtree(self): + # self.request_level_params and .same_subtree lazy-default via their + # respective obj_load_attr methods. + return self.request_level_params.same_subtree + def _image_meta_from_image(self, image): if isinstance(image, objects.ImageMeta): self.image = image @@ -533,6 +539,7 @@ class RequestSpec(base.NovaObject): # NOTE(efried): We don't need to handle request_level_params here yet # because they're set dynamically by the scheduler. That could change # in the future. + # TODO(gibi): handle same_subtree here coming from the neutron ports # NOTE(sbauza): Default the other fields that are not part of the # original contract diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index d3d13ce0e4bb..b68a165480a4 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -70,6 +70,7 @@ class ResourceRequest(object): self._limit = CONF.scheduler.max_placement_results self._root_required: ty.Set[str] = set() self._root_forbidden: ty.Set[str] = set() + self._same_subtree: ty.List[ty.List[str]] = [] self.suffixed_groups_from_flavor = 0 # TODO(stephenfin): Remove this parameter once we drop support for # 'vcpu_pin_set' @@ -132,6 +133,7 @@ class ResourceRequest(object): res_req._root_required = request_spec.root_required # root_required+=!these res_req._root_forbidden = request_spec.root_forbidden + res_req._same_subtree = request_spec.same_subtree # TODO(efried): Handle member_of[$S], which will need to be reconciled # with destination.aggregates handling in resources_from_request_spec @@ -513,6 +515,9 @@ class ResourceRequest(object): sorted(self._root_forbidden)] qparams.append(('root_required', ','.join(vals))) + for group_suffixes in self._same_subtree: + qparams.append(('same_subtree', ','.join(sorted(group_suffixes)))) + for rg in self._rg_by_id.values(): # [('resources[$S]', 'rclass:amount,rclass:amount,...'), # ('required[$S]', 'trait_name,!trait_name,...'), diff --git a/nova/tests/unit/scheduler/test_utils.py b/nova/tests/unit/scheduler/test_utils.py index 9763dc238b8c..4790d4a18e59 100644 --- a/nova/tests/unit/scheduler/test_utils.py +++ b/nova/tests/unit/scheduler/test_utils.py @@ -771,6 +771,28 @@ class TestUtils(TestUtilsBase): ) self.assertEqual(expected_querystring, resources.to_querystring()) + def test_resources_from_request_spec_with_same_subtree(self): + """Tests that there same_subtree query params are added to the + GET /allocation_candidates query string based on the request spec + """ + flavor = objects.Flavor( + vcpus=1, memory_mb=1024, root_gb=15, ephemeral_gb=0, swap=0) + req_lvl_params = objects.RequestLevelParams( + same_subtree=[['group1', 'group2'], ['group3', 'group4']]) + request_spec = objects.RequestSpec( + flavor=flavor, request_level_params=req_lvl_params) + + resources = utils.resources_from_request_spec( + self.context, request_spec, self.mock_host_manager) + + self.assertEqual( + 'limit=1000&' + 'resources=DISK_GB%3A15%2CMEMORY_MB%3A1024%2CVCPU%3A1&' + 'same_subtree=group1%2Cgroup2&' + 'same_subtree=group3%2Cgroup4', + resources.to_querystring() + ) + @mock.patch('nova.compute.utils.is_volume_backed_instance', return_value=False) def test_resources_from_flavor_no_bfv(self, mock_is_bfv):