Prepare objects for allocation request mappings
We need to carry a 'suffix' through the process of generating allocation requests in order to be able to present those suffixes as a 'mappings' key in a forthcoming microversion. In this patch, the suffix is tracked, but the data is not used when presenting results. A test is added to validate results. Existing tests which check the count of results are adjusted to reflect new results: The possible combinations is now increased because we are accounting for the suffix as a differentiator. Change-Id: I3fdd46a0a92bf9666696a1c5f98afc402cf43b33 Story: 2005575 Task: 33536
This commit is contained in:
@@ -142,7 +142,7 @@ class AllocationCandidates(object):
|
||||
for suffix, request in requests.items():
|
||||
try:
|
||||
rg_ctx = res_ctx.RequestGroupSearchContext(
|
||||
context, request, has_trees, sharing)
|
||||
context, request, has_trees, sharing, suffix)
|
||||
except exception.ResourceProviderNotFound:
|
||||
return [], []
|
||||
|
||||
@@ -244,31 +244,33 @@ class AllocationRequest(object):
|
||||
|
||||
def __hash__(self):
|
||||
# We need a stable sort order on the resource requests to get an
|
||||
# accurate hash. Since we might have either > 1 of the same resource
|
||||
# class or > 1 of the same resource provider we need to sort on both.
|
||||
sorted_rr = sorted(
|
||||
self.resource_requests,
|
||||
key=lambda x: (x.resource_class, x.resource_provider.id))
|
||||
# accurate hash. To avoid needing to update the method everytime
|
||||
# the structure of an AllocationRequestResource changes, we can
|
||||
# sort on the hash of each request resource.
|
||||
sorted_rr = sorted(self.resource_requests, key=lambda x: hash(x))
|
||||
return hash(tuple(sorted_rr))
|
||||
|
||||
|
||||
class AllocationRequestResource(object):
|
||||
|
||||
def __init__(self, resource_provider=None, resource_class=None,
|
||||
amount=None):
|
||||
amount=None, suffix=''):
|
||||
self.resource_provider = resource_provider
|
||||
self.resource_class = resource_class
|
||||
self.amount = amount
|
||||
self.suffix = suffix
|
||||
|
||||
def __eq__(self, other):
|
||||
return ((self.resource_provider.id == other.resource_provider.id) and
|
||||
(self.resource_class == other.resource_class) and
|
||||
(self.amount == other.amount))
|
||||
(self.amount == other.amount) and
|
||||
(self.suffix == other.suffix))
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.resource_provider.id,
|
||||
self.resource_class,
|
||||
self.amount))
|
||||
self.amount,
|
||||
self.suffix))
|
||||
|
||||
|
||||
class ProviderSummary(object):
|
||||
@@ -337,7 +339,8 @@ def _alloc_candidates_multiple_providers(rg_ctx, rp_candidates):
|
||||
AllocationRequestResource(
|
||||
resource_provider=rp_summary.resource_provider,
|
||||
resource_class=rc_cache.RC_CACHE.string_from_id(rp.rc_id),
|
||||
amount=rg_ctx.resources[rp.rc_id]))
|
||||
amount=rg_ctx.resources[rp.rc_id],
|
||||
suffix=rg_ctx.suffix))
|
||||
|
||||
# Next, build up a set of allocation requests. These allocation requests
|
||||
# are AllocationRequest objects, containing resource provider UUIDs,
|
||||
@@ -430,7 +433,8 @@ def _alloc_candidates_single_provider(rg_ctx, rp_tuples):
|
||||
for rp_id, root_id in rp_tuples:
|
||||
rp_summary = summaries[rp_id]
|
||||
req_obj = _allocation_request_for_provider(
|
||||
rg_ctx.context, rg_ctx.resources, rp_summary.resource_provider)
|
||||
rg_ctx.context, rg_ctx.resources, rp_summary.resource_provider,
|
||||
suffix=rg_ctx.suffix)
|
||||
alloc_requests.append(req_obj)
|
||||
# If this is a sharing provider, we have to include an extra
|
||||
# AllocationRequest for every possible anchor.
|
||||
@@ -448,7 +452,8 @@ def _alloc_candidates_single_provider(rg_ctx, rp_tuples):
|
||||
return alloc_requests, list(summaries.values())
|
||||
|
||||
|
||||
def _allocation_request_for_provider(ctx, requested_resources, provider):
|
||||
def _allocation_request_for_provider(ctx, requested_resources, provider,
|
||||
suffix):
|
||||
"""Returns an AllocationRequest object containing AllocationRequestResource
|
||||
objects for each resource class in the supplied requested resources dict.
|
||||
|
||||
@@ -462,7 +467,7 @@ def _allocation_request_for_provider(ctx, requested_resources, provider):
|
||||
AllocationRequestResource(
|
||||
resource_provider=provider,
|
||||
resource_class=rc_cache.RC_CACHE.string_from_id(rc_id),
|
||||
amount=amount,
|
||||
amount=amount, suffix=suffix
|
||||
) for rc_id, amount in requested_resources.items()
|
||||
]
|
||||
# NOTE(efried): This method only produces an AllocationRequest with its
|
||||
|
@@ -46,7 +46,7 @@ class RequestGroupSearchContext(object):
|
||||
"""An adapter object that represents the search for allocation candidates
|
||||
for a single request group.
|
||||
"""
|
||||
def __init__(self, context, request, has_trees, sharing):
|
||||
def __init__(self, context, request, has_trees, sharing, suffix=''):
|
||||
"""Initializes the object retrieving and caching matching providers
|
||||
for each conditions like resource and aggregates from database.
|
||||
|
||||
@@ -56,6 +56,9 @@ class RequestGroupSearchContext(object):
|
||||
# TODO(tetsuro): split this into smaller functions reordering
|
||||
self.context = context
|
||||
|
||||
# The request group suffix
|
||||
self.suffix = suffix
|
||||
|
||||
# A dict, keyed by resource class internal ID, of the amounts of that
|
||||
# resource class being requested by the group.
|
||||
self.resources = {
|
||||
|
@@ -885,7 +885,8 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
return ac_obj.AllocationCandidates.get_by_requests(self.ctx, requests,
|
||||
limit, group_policy)
|
||||
|
||||
def _validate_allocation_requests(self, expected, candidates):
|
||||
def _validate_allocation_requests(self, expected, candidates,
|
||||
expect_suffix=False):
|
||||
"""Assert correctness of allocation requests in allocation candidates.
|
||||
|
||||
This is set up to make it easy for the caller to specify the expected
|
||||
@@ -907,8 +908,11 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
for ar in candidates.allocation_requests:
|
||||
rrs = []
|
||||
for rr in ar.resource_requests:
|
||||
rrs.append((self.rp_uuid_to_name[rr.resource_provider.uuid],
|
||||
rr.resource_class, rr.amount))
|
||||
req_tuple = (self.rp_uuid_to_name[rr.resource_provider.uuid],
|
||||
rr.resource_class, rr.amount)
|
||||
if expect_suffix:
|
||||
req_tuple = req_tuple + (rr.suffix, )
|
||||
rrs.append(req_tuple)
|
||||
rrs.sort()
|
||||
observed.append(rrs)
|
||||
observed.sort()
|
||||
@@ -1007,9 +1011,10 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
)
|
||||
|
||||
expected = [
|
||||
[('cn1', orc.VCPU, 1)]
|
||||
[('cn1', orc.VCPU, 1, '')]
|
||||
]
|
||||
self._validate_allocation_requests(expected, alloc_cands)
|
||||
self._validate_allocation_requests(
|
||||
expected, alloc_cands, expect_suffix=True)
|
||||
|
||||
expected = {
|
||||
'cn1': set([
|
||||
@@ -2916,11 +2921,11 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
# Near the end of _merge candidates we expect 4 different collections
|
||||
# of AllocationRequest to attempt to be added to a set. Admittance is
|
||||
# controlled by the __hash__ and __eq__ of the AllocationRequest which,
|
||||
# in this case, should winnow the results down to 2 since they are
|
||||
# defined to be the same (they have the same resource provider, the
|
||||
# same resource class and the same desired amount), but contribute
|
||||
# via different suffixes.
|
||||
self.assertEqual(2, len(alloc_cands.allocation_requests))
|
||||
# in this case, should keep the results at 4 since they are defined to
|
||||
# be different when they have different suffixes even if they have the
|
||||
# same resource provider, the same resource class and the same desired
|
||||
# amount.
|
||||
self.assertEqual(4, len(alloc_cands.allocation_requests))
|
||||
|
||||
def test_nested_result_count_none(self):
|
||||
"""Tests that we properly winnow allocation requests when including
|
||||
@@ -2946,8 +2951,9 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
}),
|
||||
}, group_policy='none')
|
||||
# 4 VF providers each providing 2, 1, or 0 inventory makes 6
|
||||
# workable combinations.
|
||||
self.assertEqual(6, len(alloc_cands.allocation_requests))
|
||||
# different combinations, plus two more that are effectively
|
||||
# the same but satisfying different suffix mappings.
|
||||
self.assertEqual(8, len(alloc_cands.allocation_requests))
|
||||
|
||||
def test_nested_result_count_different_amounts(self):
|
||||
"""Tests that we properly winnow allocation requests when including
|
||||
@@ -2974,3 +2980,46 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
}),
|
||||
}, group_policy='isolate')
|
||||
self.assertEqual(4, len(alloc_cands.allocation_requests))
|
||||
|
||||
def test_nested_result_suffix_mappings(self):
|
||||
"""Confirm that paying attention to suffix mappings expands
|
||||
the quantity of results and confirm those results.
|
||||
"""
|
||||
self._create_nested_trees()
|
||||
# Make a granular request to check count and suffixes of results.
|
||||
alloc_cands = self._get_allocation_candidates({
|
||||
'': placement_lib.RequestGroup(
|
||||
use_same_provider=False,
|
||||
resources={
|
||||
orc.VCPU: 2,
|
||||
}),
|
||||
'_NET1': placement_lib.RequestGroup(
|
||||
use_same_provider=True,
|
||||
resources={
|
||||
orc.SRIOV_NET_VF: 1,
|
||||
}),
|
||||
'_NET2': placement_lib.RequestGroup(
|
||||
use_same_provider=True,
|
||||
resources={
|
||||
orc.SRIOV_NET_VF: 1,
|
||||
}),
|
||||
}, group_policy='isolate')
|
||||
|
||||
expected = [
|
||||
[('cn1', orc.VCPU, 2, ''),
|
||||
('cn1_numa0_pf0', orc.SRIOV_NET_VF, 1, '_NET1'),
|
||||
('cn1_numa1_pf1', orc.SRIOV_NET_VF, 1, '_NET2')],
|
||||
[('cn1', orc.VCPU, 2, ''),
|
||||
('cn1_numa0_pf0', orc.SRIOV_NET_VF, 1, '_NET2'),
|
||||
('cn1_numa1_pf1', orc.SRIOV_NET_VF, 1, '_NET1')],
|
||||
[('cn2', orc.VCPU, 2, ''),
|
||||
('cn2_numa0_pf0', orc.SRIOV_NET_VF, 1, '_NET1'),
|
||||
('cn2_numa1_pf1', orc.SRIOV_NET_VF, 1, '_NET2')],
|
||||
[('cn2', orc.VCPU, 2, ''),
|
||||
('cn2_numa0_pf0', orc.SRIOV_NET_VF, 1, '_NET2'),
|
||||
('cn2_numa1_pf1', orc.SRIOV_NET_VF, 1, '_NET1')],
|
||||
]
|
||||
|
||||
self.assertEqual(4, len(alloc_cands.allocation_requests))
|
||||
self._validate_allocation_requests(
|
||||
expected, alloc_cands, expect_suffix=True)
|
||||
|
Reference in New Issue
Block a user