Return all resources in provider_summaries
The response of ``GET /allocation_candidates`` API provides two fields of ``allocation_requests`` and ``provider_summaries``. The callers, like the filter scheduler in nova, would use information in ``provider_summaries`` in sorting or filtering providers to allocate consumers. However, currently ``provider_summaries`` doesn't contain resource classes that aren't requested. With this patch, ``GET /allocation_candidates`` API returns all resource classes with a new microversion. Change-Id: Ic491f190ebd97d94c18931a0e78d779a55ee47a1 Closes-Bug: #1760276 Blueprint: placement-return-all-resources
This commit is contained in:
parent
10b03bbe01
commit
a40f6b08fa
@ -116,10 +116,14 @@ def _transform_allocation_requests_list(alloc_reqs):
|
||||
return results
|
||||
|
||||
|
||||
def _transform_provider_summaries(p_sums, include_traits=False):
|
||||
def _transform_provider_summaries(p_sums, requests, include_traits=False,
|
||||
include_all_resources=False):
|
||||
"""Turn supplied list of ProviderSummary objects into a dict, keyed by
|
||||
resource provider UUID, of dicts of provider and inventory information. The
|
||||
traits only show up when `include_traits` is `True`.
|
||||
resource provider UUID, of dicts of provider and inventory information.
|
||||
The traits only show up when `include_traits` is `True`.
|
||||
When `include_all_resources` is `True`, all the resource classes are
|
||||
shown while only requested resources are included in the
|
||||
`provider_summaries` when `include_all_resources` is `False`.
|
||||
|
||||
{
|
||||
RP_UUID_1: {
|
||||
@ -158,13 +162,21 @@ def _transform_provider_summaries(p_sums, include_traits=False):
|
||||
"""
|
||||
|
||||
ret = {}
|
||||
requested_resources = set()
|
||||
|
||||
for requested_group in requests.values():
|
||||
requested_resources |= set(requested_group.resources.keys())
|
||||
|
||||
# if include_all_resources is false, only requested resources are
|
||||
# included in the provider_summaries.
|
||||
for ps in p_sums:
|
||||
resources = {
|
||||
psr.resource_class: {
|
||||
'capacity': psr.capacity,
|
||||
'used': psr.used,
|
||||
} for psr in ps.resources
|
||||
} for psr in ps.resources if (
|
||||
include_all_resources or
|
||||
psr.resource_class in requested_resources)
|
||||
}
|
||||
|
||||
ret[ps.resource_provider.uuid] = {'resources': resources}
|
||||
@ -176,7 +188,7 @@ def _transform_provider_summaries(p_sums, include_traits=False):
|
||||
return ret
|
||||
|
||||
|
||||
def _transform_allocation_candidates(alloc_cands, want_version):
|
||||
def _transform_allocation_candidates(alloc_cands, requests, want_version):
|
||||
"""Turn supplied AllocationCandidates object into a dict containing
|
||||
allocation requests and provider summaries.
|
||||
|
||||
@ -193,8 +205,11 @@ def _transform_allocation_candidates(alloc_cands, want_version):
|
||||
alloc_cands.allocation_requests)
|
||||
|
||||
include_traits = want_version.matches((1, 17))
|
||||
p_sums = _transform_provider_summaries(alloc_cands.provider_summaries,
|
||||
include_traits=include_traits)
|
||||
include_all_resources = want_version.matches((1, 27))
|
||||
p_sums = _transform_provider_summaries(
|
||||
alloc_cands.provider_summaries, requests,
|
||||
include_traits=include_traits,
|
||||
include_all_resources=include_all_resources)
|
||||
return {
|
||||
'allocation_requests': a_reqs,
|
||||
'provider_summaries': p_sums,
|
||||
@ -255,7 +270,7 @@ def list_allocation_candidates(req):
|
||||
raise webob.exc.HTTPBadRequest(six.text_type(exc))
|
||||
|
||||
response = req.response
|
||||
trx_cands = _transform_allocation_candidates(cands, want_version)
|
||||
trx_cands = _transform_allocation_candidates(cands, requests, want_version)
|
||||
json_data = jsonutils.dumps(trx_cands)
|
||||
response.body = encodeutils.to_utf8(json_data)
|
||||
response.content_type = 'application/json'
|
||||
|
@ -70,6 +70,9 @@ VERSIONS = [
|
||||
# querystring groups in GET /allocation_candidates
|
||||
'1.26', # Add ability to specify inventory with reserved value equal to
|
||||
# total.
|
||||
'1.27', # Include all resource class inventories in `provider_summaries`
|
||||
# field in response of `GET /allocation_candidates` API even if
|
||||
# the resource class is not in the requested resources.
|
||||
]
|
||||
|
||||
|
||||
|
@ -3684,45 +3684,16 @@ def _merge_candidates(candidates, group_policy=None):
|
||||
|
||||
# Now we have to produce provider summaries. The provider summaries in
|
||||
# the candidates input contain all the information; we just need to
|
||||
# filter it down to only the providers and resource classes* in our
|
||||
# merged list of allocation requests.
|
||||
# *With blueprint placement-return-all-resources, all resource classes
|
||||
# should be included, so that condition will need to be removed either
|
||||
# here or there, depending which lands first.
|
||||
# To make this easier, first index all our allocation requests as a
|
||||
# dict, keyed by resource provider UUID, of sets of resource class
|
||||
# names.
|
||||
rcs_by_rp = collections.defaultdict(set)
|
||||
# filter it down to only the providers in our merged list of allocation
|
||||
# requests.
|
||||
rps_in_areq = set()
|
||||
for areq in areqs:
|
||||
for arr in areq.resource_requests:
|
||||
rcs_by_rp[arr.resource_provider.uuid].add(arr.resource_class)
|
||||
# Now walk the input candidates' provider summaries, building a dict,
|
||||
# keyed by resource provider UUID, of ProviderSummary representing
|
||||
# that provider, and including any of its resource classes found in the
|
||||
# index we built from our allocation requests above*.
|
||||
# *See above.
|
||||
psums_by_rp = {}
|
||||
for psum in all_psums:
|
||||
rp_uuid = psum.resource_provider.uuid
|
||||
# If everything from this provider was filtered out, don't add an
|
||||
# (empty) entry for it.
|
||||
if rp_uuid not in rcs_by_rp:
|
||||
continue
|
||||
if rp_uuid not in psums_by_rp:
|
||||
psums_by_rp[rp_uuid] = ProviderSummary(
|
||||
resource_provider=psum.resource_provider, resources=[],
|
||||
# Should always be the same; no need to check/update below.
|
||||
traits=psum.traits)
|
||||
# NOTE(efried): To subsume blueprint placement-return-all-resources
|
||||
# replace this loop with:
|
||||
# psums_by_rp[rp_uuid].resources = psum.resources
|
||||
resources = set(psums_by_rp[rp_uuid].resources)
|
||||
for psumres in psum.resources:
|
||||
if psumres.resource_class in rcs_by_rp[rp_uuid]:
|
||||
resources.add(psumres)
|
||||
psums_by_rp[rp_uuid].resources = list(resources)
|
||||
rps_in_areq.add(arr.resource_provider.uuid)
|
||||
psums = [psum for psum in all_psums if
|
||||
psum.resource_provider.uuid in rps_in_areq]
|
||||
|
||||
return areqs, list(psums_by_rp.values())
|
||||
return areqs, psums
|
||||
|
||||
|
||||
@base.VersionedObjectRegistry.register_if(False)
|
||||
|
@ -329,3 +329,10 @@ non-sharing tree or associated via the specified aggregate(s).
|
||||
|
||||
Starting with this version, it is allowed to set the reserved value of the
|
||||
resource provider inventory to be equal to total.
|
||||
|
||||
1.27 Include all resource class inventories in provider_summaries
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Include all resource class inventories in the ``provider_summaries`` field in
|
||||
response of the ``GET /allocation_candidates`` API even if the resource class
|
||||
is not in the requested resources.
|
||||
|
@ -399,12 +399,8 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
expected = {
|
||||
'cn1': set([
|
||||
(fields.ResourceClass.VCPU, 8, 0),
|
||||
# TODO(tetsuro) - Bug#1760276: provider_summaries should
|
||||
# include all the resources that the resource provider has,
|
||||
# but currently it includes only resources that are requested.
|
||||
#
|
||||
# (fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
# (fields.ResourceClass.DISK_GB, 2000, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
(fields.ResourceClass.DISK_GB, 2000, 0)
|
||||
]),
|
||||
}
|
||||
self._validate_provider_summary_resources(expected, alloc_cands)
|
||||
@ -1104,6 +1100,7 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
'cn': set([
|
||||
(fields.ResourceClass.VCPU, 24, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
(fields.ResourceClass.DISK_GB, 1600, 0),
|
||||
]),
|
||||
'ss': set([
|
||||
(fields.ResourceClass.DISK_GB, 2000, 0),
|
||||
@ -1154,10 +1151,7 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
'cn': set([
|
||||
(fields.ResourceClass.VCPU, 24, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
# NOTE(efried): We don't (yet) populate provider summaries with
|
||||
# provider resources that aren't part of the result. With
|
||||
# blueprint placement-return-all-requests, uncomment this line:
|
||||
# (fields.ResourceClass.DISK_GB, 1600, 0),
|
||||
(fields.ResourceClass.DISK_GB, 1600, 0),
|
||||
]),
|
||||
'ss': set([
|
||||
(fields.ResourceClass.DISK_GB, 1600, 0),
|
||||
@ -1370,10 +1364,12 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
|
||||
expected = {
|
||||
'cn1': set([
|
||||
(fields.ResourceClass.VCPU, 24, 0)
|
||||
(fields.ResourceClass.VCPU, 24, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
]),
|
||||
'cn2': set([
|
||||
(fields.ResourceClass.VCPU, 24, 0)
|
||||
(fields.ResourceClass.VCPU, 24, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
]),
|
||||
'ss1': set([
|
||||
(fields.ResourceClass.DISK_GB, 1600, 0),
|
||||
@ -1434,9 +1430,11 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
|
||||
expected = {
|
||||
'cn1': set([
|
||||
(fields.ResourceClass.VCPU, 24, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
]),
|
||||
'cn2': set([
|
||||
(fields.ResourceClass.VCPU, 24, 0),
|
||||
(fields.ResourceClass.MEMORY_MB, 2048, 0),
|
||||
]),
|
||||
'ss1': set([
|
||||
(fields.ResourceClass.DISK_GB, 1600, 0),
|
||||
|
@ -277,13 +277,51 @@ tests:
|
||||
$.allocation_requests.`len`: 0
|
||||
$.provider_summaries.`len`: 0
|
||||
|
||||
# Bug#1760276: provider_summaries should include all the resources that the
|
||||
# resource provider has, ut currently it includes only resources that are requested.
|
||||
# Before microversion 1.27, the ``provider_summaries`` field in the response
|
||||
# of the ``GET /allocation_candidates`` API included inventories of resource
|
||||
# classes that are requested.
|
||||
- name: get allocation candidates provider summaries with requested resource
|
||||
GET: /allocation_candidates?resources=VCPU:1
|
||||
status: 200
|
||||
request_headers:
|
||||
openstack-api-version: placement 1.26
|
||||
response_json_paths:
|
||||
$.allocation_requests.`len`: 2
|
||||
$.provider_summaries.`len`: 2
|
||||
$.provider_summaries["$ENVIRON['CN1_UUID']"].resources.`len`: 1
|
||||
$.provider_summaries["$ENVIRON['CN1_UUID']"].resources:
|
||||
VCPU:
|
||||
capacity: 384 # 16.0 * 24
|
||||
used: 0
|
||||
$.provider_summaries["$ENVIRON['CN2_UUID']"].resources.`len`: 1
|
||||
$.provider_summaries["$ENVIRON['CN2_UUID']"].resources:
|
||||
VCPU:
|
||||
capacity: 384 # 16.0 * 24
|
||||
used: 0
|
||||
|
||||
# From microversion 1.27, the ``provider_summaries`` field includes
|
||||
# all the resource class inventories regardless of whether it is requested.
|
||||
- name: get allocation candidates provider summaries with all resources
|
||||
GET: /allocation_candidates?resources=VCPU:1
|
||||
status: 200
|
||||
request_headers:
|
||||
openstack-api-version: placement 1.27
|
||||
response_json_paths:
|
||||
$.allocation_requests.`len`: 2
|
||||
$.provider_summaries.`len`: 2
|
||||
$.provider_summaries["$ENVIRON['CN1_UUID']"].resources.`len`: 2
|
||||
$.provider_summaries["$ENVIRON['CN1_UUID']"].resources:
|
||||
VCPU:
|
||||
capacity: 384 # 16.0 * 24
|
||||
used: 0
|
||||
MEMORY_MB:
|
||||
capacity: 196608 # 1.5 * 128G
|
||||
used: 0
|
||||
$.provider_summaries["$ENVIRON['CN2_UUID']"].resources.`len`: 2
|
||||
$.provider_summaries["$ENVIRON['CN2_UUID']"].resources:
|
||||
VCPU:
|
||||
capacity: 384 # 16.0 * 24
|
||||
used: 0
|
||||
MEMORY_MB:
|
||||
capacity: 196608 # 1.5 * 128G
|
||||
used: 0
|
||||
|
@ -167,6 +167,9 @@ tests:
|
||||
MEMORY_MB:
|
||||
capacity: 4096
|
||||
used: 0
|
||||
DISK_GB:
|
||||
capacity: 500
|
||||
used: 0
|
||||
$.provider_summaries["$ENVIRON['CN_MIDDLE']"].resources:
|
||||
VCPU:
|
||||
capacity: 8
|
||||
|
@ -39,13 +39,13 @@ tests:
|
||||
response_json_paths:
|
||||
$.errors[0].title: Not Acceptable
|
||||
|
||||
- name: latest microversion is 1.26
|
||||
- name: latest microversion is 1.27
|
||||
GET: /
|
||||
request_headers:
|
||||
openstack-api-version: placement latest
|
||||
response_headers:
|
||||
vary: /openstack-api-version/
|
||||
openstack-api-version: placement 1.26
|
||||
openstack-api-version: placement 1.27
|
||||
|
||||
- name: other accept header bad version
|
||||
GET: /
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
From microversion 1.27, the ``provider_summaries`` field in the
|
||||
response of the ``GET /allocation_candidates`` API includes all
|
||||
the resource class inventories, while it had only requested
|
||||
resource class inventories with older microversions.
|
||||
Now callers can use this additional inventory information in
|
||||
making further sorting or filtering decisions.
|
Loading…
x
Reference in New Issue
Block a user