Skip _exclude_nested_providers() if not nested

In rocky cycle, 'GET /allocation_candidates' started to be aware of
nested providers from microversion 1.29, namely, it can have multiple
allocations from multiple resource providers in the same tree in the
allocation requests.

To keep the behavior of microversion before 1.29, it added a filters
to exculde nested providers being unaware of the nested architecture.
However that function "_exclude_nested_providers()" is very heavy
and is executed even if there is no nested provider in the environment
when microversion < 1.29.

This patch changes it to skip it if there is no nested provider.

Since _exclude_nested_providers() should be done before limitting
the candidates, this patch also moves it from hander file to the
deeper layer.

Change-Id: I4efdc65395e69a6d33fba927018d003cce26fa68
Story: 2005669
Task: 30980
This commit is contained in:
Tetsuro Nakamura 2019-05-13 11:34:05 +00:00
parent 5702625561
commit 727fb88dcc
2 changed files with 51 additions and 42 deletions

View File

@ -204,40 +204,6 @@ def _transform_provider_summaries(p_sums, requests, want_version):
return ret
def _exclude_nested_providers(alloc_cands):
"""Exclude allocation requests and provider summaries for old microversions
if they involve more than one provider from the same tree.
"""
# Build a temporary dict, keyed by root RP UUID of sets of UUIDs of all RPs
# in that tree.
tree_rps_by_root = collections.defaultdict(set)
for ps in alloc_cands.provider_summaries:
rp_uuid = ps.resource_provider.uuid
root_uuid = ps.resource_provider.root_provider_uuid
tree_rps_by_root[root_uuid].add(rp_uuid)
# We use this to get a list of sets of providers in each tree
tree_sets = list(tree_rps_by_root.values())
for a_req in alloc_cands.allocation_requests[:]:
alloc_rp_uuids = set([
arr.resource_provider.uuid for arr in a_req.resource_requests])
# If more than one allocation is provided by the same tree, kill
# that allocation request.
if any(len(tree_set & alloc_rp_uuids) > 1 for tree_set in tree_sets):
alloc_cands.allocation_requests.remove(a_req)
# Exclude eliminated providers from the provider summaries.
all_rp_uuids = set()
for a_req in alloc_cands.allocation_requests:
all_rp_uuids |= set(
arr.resource_provider.uuid for arr in a_req.resource_requests)
for ps in alloc_cands.provider_summaries[:]:
if ps.resource_provider.uuid not in all_rp_uuids:
alloc_cands.provider_summaries.remove(ps)
return alloc_cands
def _transform_allocation_candidates(alloc_cands, requests, want_version):
"""Turn supplied AllocationCandidates object into a dict containing
allocation requests and provider summaries.
@ -247,10 +213,6 @@ def _transform_allocation_candidates(alloc_cands, requests, want_version):
'provider_summaries': <PROVIDER_SUMMARIES>,
}
"""
# exclude nested providers with old microversions
if not want_version.matches((1, 29)):
alloc_cands = _exclude_nested_providers(alloc_cands)
if want_version.matches((1, 12)):
a_reqs = _transform_allocation_requests_dict(
alloc_cands.allocation_requests)
@ -312,9 +274,13 @@ def list_allocation_candidates(req):
'The "group_policy" parameter is required when specifying '
'more than one "resources{N}" parameter.')
# We can't be aware of nested architecture with old microversions
nested_aware = want_version.matches((1, 29))
try:
cands = ac_obj.AllocationCandidates.get_by_requests(
context, requests, limit=limit, group_policy=group_policy)
context, requests, limit=limit, group_policy=group_policy,
nested_aware=nested_aware)
except exception.ResourceClassNotFound as exc:
raise webob.exc.HTTPBadRequest(
'Invalid resource class in resources parameter: %(error)s' %

View File

@ -53,7 +53,8 @@ class AllocationCandidates(object):
self.provider_summaries = provider_summaries
@classmethod
def get_by_requests(cls, context, requests, limit=None, group_policy=None):
def get_by_requests(cls, context, requests, limit=None, group_policy=None,
nested_aware=True):
"""Returns an AllocationCandidates object containing all resource
providers matching a set of supplied resource constraints, with a set
of allocation requests constructed from that list of resource
@ -76,12 +77,16 @@ class AllocationCandidates(object):
other. If the value is "isolate", we will filter
out allocation requests where any such
RequestGroups are satisfied by the same RP.
:param nested_aware: If False, we are blind to nested architecture and
can't pick resources from multiple providers even
if they come from the same tree.
:return: An instance of AllocationCandidates with allocation_requests
and provider_summaries satisfying `requests`, limited
according to `limit`.
"""
alloc_reqs, provider_summaries = cls._get_by_requests(
context, requests, limit=limit, group_policy=group_policy)
context, requests, limit=limit, group_policy=group_policy,
nested_aware=nested_aware)
return cls(
allocation_requests=alloc_reqs,
provider_summaries=provider_summaries,
@ -175,7 +180,7 @@ class AllocationCandidates(object):
# reader when that migration is no longer happening.
@db_api.placement_context_manager.writer
def _get_by_requests(cls, context, requests, limit=None,
group_policy=None):
group_policy=None, nested_aware=True):
# TODO(jaypipes): Make a RequestGroupContext object and put these
# pieces of information in there, passing the context to the various
# internal functions handling that part of the request.
@ -214,6 +219,10 @@ class AllocationCandidates(object):
alloc_request_objs, summary_objs = _merge_candidates(
candidates, group_policy=group_policy)
if not nested_aware and has_trees:
alloc_request_objs, summary_objs = _exclude_nested_providers(
alloc_request_objs, summary_objs)
return cls._limit_results(context, alloc_request_objs, summary_objs,
limit)
@ -980,3 +989,37 @@ def _satisfies_group_policy(areqs, group_policy, num_granular_groups):
'request (%d): %s',
num_granular_groups_in_areqs, num_granular_groups, str(areqs))
return False
def _exclude_nested_providers(allocation_requests, provider_summaries):
"""Exclude allocation requests and provider summaries for old microversions
if they involve more than one provider from the same tree.
"""
# Build a temporary dict, keyed by root RP UUID of sets of UUIDs of all RPs
# in that tree.
tree_rps_by_root = collections.defaultdict(set)
for ps in provider_summaries:
rp_uuid = ps.resource_provider.uuid
root_uuid = ps.resource_provider.root_provider_uuid
tree_rps_by_root[root_uuid].add(rp_uuid)
# We use this to get a list of sets of providers in each tree
tree_sets = list(tree_rps_by_root.values())
for a_req in allocation_requests[:]:
alloc_rp_uuids = set([
arr.resource_provider.uuid for arr in a_req.resource_requests])
# If more than one allocation is provided by the same tree, kill
# that allocation request.
if any(len(tree_set & alloc_rp_uuids) > 1 for tree_set in tree_sets):
allocation_requests.remove(a_req)
# Exclude eliminated providers from the provider summaries.
all_rp_uuids = set()
for a_req in allocation_requests:
all_rp_uuids |= set(
arr.resource_provider.uuid for arr in a_req.resource_requests)
for ps in provider_summaries[:]:
if ps.resource_provider.uuid not in all_rp_uuids:
provider_summaries.remove(ps)
return allocation_requests, provider_summaries