Implement allocation candidate mappings

In microversion 1.34 add a 'mappings' key to each allocation
request. Its value is dict keyed by resource group suffixes
with values of a list of resource providers satisfying that
group.

To preserve symmetry, the mappings key may be sent back when
writing allocations so the schema for POST and PUT allocations
and POST /reshaper are updated.

api history, api-ref and reno are added

Change-Id: Ie78ed7e050416d4ccb62697ba608131038bb4303
Story: 2005575
Task: 33536
This commit is contained in:
Chris Dent 2019-06-03 16:06:55 +01:00
parent eb07913442
commit d38844e390
21 changed files with 618 additions and 18 deletions

View File

@ -57,10 +57,17 @@ Response (microversions 1.12 - )
- traits: traits_1_17 - traits: traits_1_17
- parent_provider_uuid: resource_provider_parent_provider_uuid_response_1_29 - parent_provider_uuid: resource_provider_parent_provider_uuid_response_1_29
- root_provider_uuid: resource_provider_root_provider_uuid_1_29 - root_provider_uuid: resource_provider_root_provider_uuid_1_29
- mappings: mappings
Response Example (microversions 1.29 - ) Response Example (microversions 1.34 - )
---------------------------------------- ----------------------------------------
.. literalinclude:: ./samples/allocation_candidates/get-allocation_candidates-1.34.json
:language: javascript
Response Example (microversions 1.29 - 1.33)
--------------------------------------------
.. literalinclude:: ./samples/allocation_candidates/get-allocation_candidates-1.29.json .. literalinclude:: ./samples/allocation_candidates/get-allocation_candidates-1.29.json
:language: javascript :language: javascript

View File

@ -43,6 +43,7 @@ Request
- allocations: allocations_dict_empty - allocations: allocations_dict_empty
- generation: resource_provider_generation_optional - generation: resource_provider_generation_optional
- resources: resources - resources: resources
- mappings: mappings_in_allocations
Request example (microversions 1.28 - ) Request example (microversions 1.28 - )
--------------------------------------- ---------------------------------------
@ -136,6 +137,7 @@ Request (microversions 1.12 - )
- project_id: project_id_body - project_id: project_id_body
- user_id: user_id_body - user_id: user_id_body
- generation: resource_provider_generation_optional - generation: resource_provider_generation_optional
- mappings: mappings_in_allocations
Request example (microversions 1.28 - ) Request example (microversions 1.28 - )
--------------------------------------- ---------------------------------------

View File

@ -462,6 +462,20 @@ inventories:
required: true required: true
description: > description: >
A dictionary of inventories keyed by resource classes. A dictionary of inventories keyed by resource classes.
mappings: &mappings
type: object
in: body
required: true
description: >
A dictionary associating request group suffixes with a list of uuids
identifying the resource providers that satisfied each group. The empty
string and ``[a-zA-Z0-9_-]+`` are valid suffixes. This field may be sent
when writing allocations back to the server but will be ignored; this
preserves symmetry between read and write representations.
min_version: 1.34
mappings_in_allocations:
<<: *mappings
required: false
max_unit: &max_unit max_unit: &max_unit
type: integer type: integer
in: body in: body

View File

@ -38,6 +38,7 @@ Request
- allocations.{consumer_uuid}.allocations.{resource_provider_uuid}.resources: resources - allocations.{consumer_uuid}.allocations.{resource_provider_uuid}.resources: resources
- allocations.{consumer_uuid}.project_id: project_id_body - allocations.{consumer_uuid}.project_id: project_id_body
- allocations.{consumer_uuid}.user_id: user_id_body - allocations.{consumer_uuid}.user_id: user_id_body
- allocations.{consumer_uuid}.mappings: mappings
- allocations.{consumer_uuid}.consumer_generation: consumer_generation - allocations.{consumer_uuid}.consumer_generation: consumer_generation
Request Example Request Example

View File

@ -0,0 +1,96 @@
{
"allocation_requests": [
{
"allocations": {
"92e971c9-777a-48bf-a181-a2ca1105c015": {
"resources": {
"NET_BW_EGR_KILOBIT_PER_SEC": 10
}
},
"cefbdf54-05a8-4db4-ad2b-d6729e5a4de8": {
"resources": {
"NET_BW_EGR_KILOBIT_PER_SEC": 20
}
},
"9a9c6b0f-e8d1-4d16-b053-a2bfe8a76757": {
"resources": {
"VCPU": 1
}
}
},
"mappings": {
"_NET1": [
"92e971c9-777a-48bf-a181-a2ca1105c015"
],
"_NET2": [
"cefbdf54-05a8-4db4-ad2b-d6729e5a4de8"
],
"": [
"9a9c6b0f-e8d1-4d16-b053-a2bfe8a76757"
]
}
}
],
"provider_summaries": {
"be99627d-e848-44ef-8341-683e2e557c58": {
"resources": {},
"traits": [
"COMPUTE_VOLUME_MULTI_ATTACH"
],
"parent_provider_uuid": null,
"root_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58"
},
"9a9c6b0f-e8d1-4d16-b053-a2bfe8a76757": {
"resources": {
"VCPU": {
"capacity": 4,
"used": 0
},
"MEMORY_MB": {
"capacity": 2048,
"used": 0
}
},
"traits": [
"HW_NUMA_ROOT",
"CUSTOM_FOO"
],
"parent_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58",
"root_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58"
},
"ba415f98-1960-4488-b2ed-4518b77eaa60": {
"resources": {},
"traits": [
"CUSTOM_VNIC_TYPE_DIRECT"
],
"parent_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58",
"root_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58"
},
"92e971c9-777a-48bf-a181-a2ca1105c015": {
"resources": {
"NET_BW_EGR_KILOBIT_PER_SEC": {
"capacity": 10000,
"used": 0
}
},
"traits": [
"CUSTOM_PHYSNET1"
],
"parent_provider_uuid": "ba415f98-1960-4488-b2ed-4518b77eaa60",
"root_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58"
},
"cefbdf54-05a8-4db4-ad2b-d6729e5a4de8": {
"resources": {
"NET_BW_EGR_KILOBIT_PER_SEC": {
"capacity": 20000,
"used": 0
}
},
"traits": [
"CUSTOM_PHYSNET2"
],
"parent_provider_uuid": "ba415f98-1960-4488-b2ed-4518b77eaa60",
"root_provider_uuid": "be99627d-e848-44ef-8341-683e2e557c58"
}
}
}

View File

@ -483,12 +483,19 @@ def set_allocations_for_consumer(req):
@wsgi_wrapper.PlacementWsgify # noqa @wsgi_wrapper.PlacementWsgify # noqa
@microversion.version_handler('1.28') @microversion.version_handler('1.28', '1.33')
@util.require_content('application/json') @util.require_content('application/json')
def set_allocations_for_consumer(req): def set_allocations_for_consumer(req):
return _set_allocations_for_consumer(req, schema.ALLOCATION_SCHEMA_V1_28) return _set_allocations_for_consumer(req, schema.ALLOCATION_SCHEMA_V1_28)
@wsgi_wrapper.PlacementWsgify # noqa
@microversion.version_handler('1.34')
@util.require_content('application/json')
def set_allocations_for_consumer(req):
return _set_allocations_for_consumer(req, schema.ALLOCATION_SCHEMA_V1_34)
@wsgi_wrapper.PlacementWsgify @wsgi_wrapper.PlacementWsgify
@microversion.version_handler('1.13') @microversion.version_handler('1.13')
@util.require_content('application/json') @util.require_content('application/json')
@ -499,6 +506,8 @@ def set_allocations(req):
want_schema = schema.POST_ALLOCATIONS_V1_13 want_schema = schema.POST_ALLOCATIONS_V1_13
if want_version.matches((1, 28)): if want_version.matches((1, 28)):
want_schema = schema.POST_ALLOCATIONS_V1_28 want_schema = schema.POST_ALLOCATIONS_V1_28
if want_version.matches((1, 34)):
want_schema = schema.POST_ALLOCATIONS_V1_34
data = util.extract_json(req.body, want_schema) data = util.extract_json(req.body, want_schema)
consumers, new_consumers_created = inspect_consumers( consumers, new_consumers_created = inspect_consumers(

View File

@ -30,7 +30,7 @@ from placement import util
from placement import wsgi_wrapper from placement import wsgi_wrapper
def _transform_allocation_requests_dict(alloc_reqs): def _transform_allocation_requests_dict(alloc_reqs, want_version):
"""Turn supplied list of AllocationRequest objects into a list of """Turn supplied list of AllocationRequest objects into a list of
allocations dicts keyed by resource provider uuid of resources involved allocations dicts keyed by resource provider uuid of resources involved
in the allocation request. The returned results are intended to be used in the allocation request. The returned results are intended to be used
@ -53,6 +53,12 @@ def _transform_allocation_requests_dict(alloc_reqs):
} }
} }
}, },
# If microversion >=1.34 then map suffixes to providers.
"mappings": {
"_COMPUTE": [$rp_uuid2],
"": [$rp_uuid1]
},
}, },
... ...
] ]
@ -62,10 +68,18 @@ def _transform_allocation_requests_dict(alloc_reqs):
for ar in alloc_reqs: for ar in alloc_reqs:
# A default dict of {$rp_uuid: "resources": {}) # A default dict of {$rp_uuid: "resources": {})
rp_resources = collections.defaultdict(lambda: dict(resources={})) rp_resources = collections.defaultdict(lambda: dict(resources={}))
# A dict to map request group suffixes to the providers that provided
# solutions to that group.
mappings = collections.defaultdict(list)
for rr in ar.resource_requests: for rr in ar.resource_requests:
suffix = rr.suffix
mappings[suffix].append(rr.resource_provider.uuid)
res_dict = rp_resources[rr.resource_provider.uuid]['resources'] res_dict = rp_resources[rr.resource_provider.uuid]['resources']
res_dict[rr.resource_class] = rr.amount res_dict[rr.resource_class] = rr.amount
results.append(dict(allocations=rp_resources)) result = dict(allocations=rp_resources)
if want_version.matches((1, 34)):
result['mappings'] = mappings
results.append(result)
return results return results
@ -214,7 +228,7 @@ def _transform_allocation_candidates(alloc_cands, requests, want_version):
""" """
if want_version.matches((1, 12)): if want_version.matches((1, 12)):
a_reqs = _transform_allocation_requests_dict( a_reqs = _transform_allocation_requests_dict(
alloc_cands.allocation_requests) alloc_cands.allocation_requests, want_version)
else: else:
a_reqs = _transform_allocation_requests_list( a_reqs = _transform_allocation_requests_list(
alloc_cands.allocation_requests) alloc_cands.allocation_requests)

View File

@ -44,7 +44,11 @@ def reshape(req):
context = req.environ['placement.context'] context = req.environ['placement.context']
want_version = req.environ[microversion.MICROVERSION_ENVIRON] want_version = req.environ[microversion.MICROVERSION_ENVIRON]
context.can(policies.RESHAPE) context.can(policies.RESHAPE)
data = util.extract_json(req.body, schema.POST_RESHAPER_SCHEMA)
reshaper_schema = schema.POST_RESHAPER_SCHEMA
if want_version.matches((1, 34)):
reshaper_schema = schema.POST_RESHAPER_SCHEMA_V1_34
data = util.extract_json(req.body, reshaper_schema)
inventories = data['inventories'] inventories = data['inventories']
allocations = data['allocations'] allocations = data['allocations']
# We're going to create several lists of Inventory objects, keyed by rp # We're going to create several lists of Inventory objects, keyed by rp

View File

@ -19,7 +19,7 @@ import re
import webob import webob
from placement import microversion from placement import microversion
from placement.schemas import allocation_candidate from placement.schemas import common
from placement import util from placement import util
@ -31,11 +31,11 @@ _QS_IN_TREE = 'in_tree'
_QS_KEY_PATTERN = re.compile( _QS_KEY_PATTERN = re.compile(
r"^(%s)(%s)?$" % ('|'.join( r"^(%s)(%s)?$" % ('|'.join(
(_QS_RESOURCES, _QS_REQUIRED, _QS_MEMBER_OF, _QS_IN_TREE)), (_QS_RESOURCES, _QS_REQUIRED, _QS_MEMBER_OF, _QS_IN_TREE)),
allocation_candidate.GROUP_PAT)) common.GROUP_PAT))
_QS_KEY_PATTERN_1_33 = re.compile( _QS_KEY_PATTERN_1_33 = re.compile(
r"^(%s)(%s)?$" % ('|'.join( r"^(%s)(%s)?$" % ('|'.join(
(_QS_RESOURCES, _QS_REQUIRED, _QS_MEMBER_OF, _QS_IN_TREE)), (_QS_RESOURCES, _QS_REQUIRED, _QS_MEMBER_OF, _QS_IN_TREE)),
allocation_candidate.GROUP_PAT_1_33)) common.GROUP_PAT_1_33))
class RequestGroup(object): class RequestGroup(object):

View File

@ -83,6 +83,8 @@ VERSIONS = [
# `GET /resource_providers` and `GET /allocation_candidates` # `GET /resource_providers` and `GET /allocation_candidates`
'1.33', # Support granular resource requests with suffixes that match '1.33', # Support granular resource requests with suffixes that match
# [A-Za-z0-9_-]{1,64}. # [A-Za-z0-9_-]{1,64}.
'1.34', # Include a mappings key in allocation requests that shows which
# resource providers satisfied which request group suffix.
] ]

View File

@ -625,3 +625,16 @@ it is now possible to use more complex strings, including UUIDs::
resources_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=XXX resources_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=XXX
&required_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=YYY &required_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=YYY
&member_of_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=ZZZ &member_of_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=ZZZ
1.34 - Request group mappings in allocation candidates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: Train
The body of the response to a ``GET /allocation_candidates`` request has been
extended to include a ``mappings`` field with each allocation request. The
value is a dictionary associating request group suffixes with the uuids of
those resource providers that satisfy the identified request group. For
convenience, this mapping can be included in the request payload for
``POST /allocations``, ``PUT /allocations/{consumer_uuid}``, and
``POST /reshaper``, but it will be ignored.

View File

@ -167,3 +167,26 @@ POST_ALLOCATIONS_V1_28 = copy.deepcopy(POST_ALLOCATIONS_V1_13)
POST_ALLOCATIONS_V1_28["patternProperties"] = { POST_ALLOCATIONS_V1_28["patternProperties"] = {
common.UUID_PATTERN: REQUIRED_GENERATION_ALLOCS_POST common.UUID_PATTERN: REQUIRED_GENERATION_ALLOCS_POST
} }
# Microversion 1.34 allows an optional mappings object which associates
# request group suffixes with lists of resource provider uuids.
mappings_schema = {
"type": "object",
"minProperites": 1,
"patternProperties": {
common.GROUP_PAT_1_33: {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"format": "uuid"
}
}
}
}
ALLOCATION_SCHEMA_V1_34 = copy.deepcopy(ALLOCATION_SCHEMA_V1_28)
ALLOCATION_SCHEMA_V1_34['properties']['mappings'] = mappings_schema
POST_ALLOCATIONS_V1_34 = copy.deepcopy(POST_ALLOCATIONS_V1_28)
POST_ALLOCATIONS_V1_34["patternProperties"] = {
common.UUID_PATTERN: ALLOCATION_SCHEMA_V1_34
}

View File

@ -13,11 +13,7 @@
import copy import copy
from placement.schemas import common
# The suffix used with request groups. Prior to 1.33, the group were numbered.
# With 1.33 they become alphanumeric, '_', and '-' with a length limit of 64.
GROUP_PAT = r'[1-9][0-9]*'
GROUP_PAT_1_33 = r'[a-zA-Z0-9_-]{1,64}'
# Represents the allowed query string parameters to the GET # Represents the allowed query string parameters to the GET
@ -66,7 +62,7 @@ del GET_SCHEMA_1_25["required"]
del GET_SCHEMA_1_25["properties"]["required"] del GET_SCHEMA_1_25["properties"]["required"]
del GET_SCHEMA_1_25["properties"]["member_of"] del GET_SCHEMA_1_25["properties"]["member_of"]
# Pattern property key format for a numbered or un-numbered grouping # Pattern property key format for a numbered or un-numbered grouping
_GROUP_PAT_FMT = "^%s(" + GROUP_PAT + ")?$" _GROUP_PAT_FMT = "^%s(" + common.GROUP_PAT + ")?$"
GET_SCHEMA_1_25["patternProperties"] = { GET_SCHEMA_1_25["patternProperties"] = {
_GROUP_PAT_FMT % "resources": { _GROUP_PAT_FMT % "resources": {
"type": "string", "type": "string",
@ -90,7 +86,7 @@ GET_SCHEMA_1_31["patternProperties"][_GROUP_PAT_FMT % "in_tree"] = {
# Microversion 1.33 allows more complex resource group suffixes. # Microversion 1.33 allows more complex resource group suffixes.
GET_SCHEMA_1_33 = copy.deepcopy(GET_SCHEMA_1_31) GET_SCHEMA_1_33 = copy.deepcopy(GET_SCHEMA_1_31)
_GROUP_PAT_FMT_1_33 = "^%s(" + GROUP_PAT_1_33 + ")?$" _GROUP_PAT_FMT_1_33 = "^%s(" + common.GROUP_PAT_1_33 + ")?$"
GET_SCHEMA_1_33["patternProperties"] = { GET_SCHEMA_1_33["patternProperties"] = {
_GROUP_PAT_FMT_1_33 % group_type: {"type": "string"} _GROUP_PAT_FMT_1_33 % group_type: {"type": "string"}
for group_type in ('resources', 'required', 'member_of', 'in_tree')} for group_type in ('resources', 'required', 'member_of', 'in_tree')}

View File

@ -20,3 +20,8 @@ RC_PATTERN = _RC_TRAIT_PATTERN
_CUSTOM_RC_TRAIT_PATTERN = "^CUSTOM_%s+$" % _RC_TRAIT_CHAR _CUSTOM_RC_TRAIT_PATTERN = "^CUSTOM_%s+$" % _RC_TRAIT_CHAR
CUSTOM_RC_PATTERN = _CUSTOM_RC_TRAIT_PATTERN CUSTOM_RC_PATTERN = _CUSTOM_RC_TRAIT_PATTERN
CUSTOM_TRAIT_PATTERN = _CUSTOM_RC_TRAIT_PATTERN CUSTOM_TRAIT_PATTERN = _CUSTOM_RC_TRAIT_PATTERN
# The suffix used with request groups. Prior to 1.33, the group were numbered.
# With 1.33 they become alphanumeric, '_', and '-' with a length limit of 64.
GROUP_PAT = r'[1-9][0-9]*'
GROUP_PAT_1_33 = r'[a-zA-Z0-9_-]{1,64}'

View File

@ -45,3 +45,8 @@ POST_RESHAPER_SCHEMA = {
], ],
"additionalProperties": False, "additionalProperties": False,
} }
POST_RESHAPER_SCHEMA_V1_34 = copy.deepcopy(POST_RESHAPER_SCHEMA)
ALLOCATIONS_V1_34 = copy.deepcopy(allocation.POST_ALLOCATIONS_V1_34)
ALLOCATIONS_V1_34['minProperties'] = 0
POST_RESHAPER_SCHEMA_V1_34['properties']['allocations'] = ALLOCATIONS_V1_34

View File

@ -0,0 +1,87 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Tests for allocation request mappings when using nested providers.
fixtures:
# See the layout diagram in this fixture's docstring in ../fixtures.py
- NUMANetworkFixture
defaults:
request_headers:
x-auth-token: admin
content-type: application/json
accept: application/json
# 1.34 is the microversion at which mappings are expected
openstack-api-version: placement 1.34
tests:
- name: simple mapping non granular
GET: /allocation_candidates
query_parameters:
resources: VCPU:1
response_json_paths:
$.allocation_requests.`len`: 3
$.provider_summaries.`len`: 23
# keys are allocations, mappings
$.allocation_requests[0].`len`: 2
$.allocation_requests[0].mappings[''].`len`: 1
$.allocation_requests[0].mappings[''][0]: /$ENVIRON['CN2_UUID']|$ENVIRON['NUMA0_UUID']|$ENVIRON['NUMA1_UUID']/
- name: no mappings in 1.33
GET: /allocation_candidates
query_parameters:
resources: VCPU:1
request_headers:
openstack-api-version: placement 1.33
response_json_paths:
$.allocation_requests.`len`: 3
$.provider_summaries.`len`: 23
# keys are solely 'allocations'
$.allocation_requests[0].`len`: 1
- name: simple isolated mapping
GET: /allocation_candidates
query_parameters:
resources_LEFT: VCPU:1
resources_RIGHT: VCPU:1
group_policy: isolate
response_json_paths:
$.allocation_requests.`len`: 2
$.provider_summaries.`len`: 12
$.allocation_requests[0].mappings.`len`: 2
$.allocation_requests[0].mappings['_LEFT'][0]: /$ENVIRON['NUMA0_UUID']|$ENVIRON['NUMA1_UUID']/
$.allocation_requests[0].mappings['_RIGHT'][0]: /$ENVIRON['NUMA1_UUID']|$ENVIRON['NUMA0_UUID']/
- name: granular plus not granular
GET: /allocation_candidates
query_parameters:
required_NET1: CUSTOM_PHYSNET1
resources_NET1: NET_BW_EGR_KILOBIT_PER_SEC:10
required_NET2: CUSTOM_PHYSNET2
resources_NET2: NET_BW_EGR_KILOBIT_PER_SEC:20
resources: VCPU:1
group_policy: isolate
response_json_paths:
# two candidates, one for each NUMA node providing VCPU
$.allocation_requests.`len`: 2
$.provider_summaries.`len`: 12
# 3 members of the mappings dict
$.allocation_requests[0].mappings.`len`: 3
# One member of each list in the mappings
$.allocation_requests[0].mappings[''].`len`: 1
$.allocation_requests[0].mappings._NET1.`len`: 1
$.allocation_requests[0].mappings._NET2.`len`: 1
$.allocation_requests[0].mappings[''][0]: /$ENVIRON['NUMA0_UUID']|$ENVIRON['NUMA1_UUID']/
$.allocation_requests[0].mappings._NET1[0]: $ENVIRON['ESN1_UUID']
$.allocation_requests[0].mappings._NET2[0]: $ENVIRON['ESN2_UUID']

View File

@ -0,0 +1,77 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Tests for allocation request mappings.
fixtures:
# See the layout diagram in this fixture's docstring in ../fixtures.py
- GranularFixture
defaults:
request_headers:
x-auth-token: admin
content-type: application/json
accept: application/json
# 1.34 is the microversion at which mappings are expected
openstack-api-version: placement 1.34
tests:
- name: simple mapping non granular
GET: /allocation_candidates
query_parameters:
resources: VCPU:1
required: HW_CPU_X86_SSE
response_json_paths:
$.allocation_requests.`len`: 1
$.provider_summaries.`len`: 1
$.allocation_requests[0].allocations["$ENVIRON['CN_MIDDLE']"].resources:
VCPU: 1
$.allocation_requests[0].mappings:
"":
- $ENVIRON['CN_MIDDLE']
- name: simple mapping with shared
GET: /allocation_candidates
query_parameters:
resources: VCPU:1,DISK_GB:1
required: HW_CPU_X86_SSE
response_json_paths:
$.allocation_requests.`len`: 2
$.provider_summaries.`len`: 3
$.allocation_requests[0].allocations["$ENVIRON['CN_MIDDLE']"].resources:
VCPU: 1
# We can't cleanly test for which providers will show up in which
# mappings in this request, so instead we confirm the size. Other tests
# cover which suitably.
$.allocation_requests[0].mappings.`len`: 1
$.allocation_requests[0].mappings[""].`len`: 2
$.allocation_requests[1].mappings.`len`: 1
$.allocation_requests[1].mappings[""].`len`: 2
- name: group mapping with shared
GET: /allocation_candidates
query_parameters:
resources: VCPU:1
resources_DISK_A: DISK_GB:1
resources_DISK_B: DISK_GB:1
required: HW_CPU_X86_SSE
group_policy: isolate
response_json_paths:
$.allocation_requests.`len`: 2
$.provider_summaries.`len`: 3
$.allocation_requests[0].allocations["$ENVIRON['CN_MIDDLE']"].resources:
VCPU: 1
$.allocation_requests[0].mappings.`len`: 3
$.allocation_requests[0].mappings[""][0]: $ENVIRON['CN_MIDDLE']
$.allocation_requests[0].mappings['_DISK_A'][0]: /(?:$ENVIRON['SHR_DISK_1']|$ENVIRON['SHR_DISK_2'])/
$.allocation_requests[0].mappings['_DISK_B'][0]: /(?:$ENVIRON['SHR_DISK_1']|$ENVIRON['SHR_DISK_2'])/

View File

@ -0,0 +1,100 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Tests that allocation request mappings can be sent back
fixtures:
# See the layout diagram in this fixture's docstring in ../fixtures.py
- NUMANetworkFixture
defaults:
request_headers:
x-auth-token: admin
content-type: application/json
accept: application/json
# 1.34 is the microversion at which mappings are expected
openstack-api-version: placement 1.34
tests:
- name: mappings request
GET: /allocation_candidates
query_parameters:
required_NET1: CUSTOM_PHYSNET1
resources_NET1: NET_BW_EGR_KILOBIT_PER_SEC:10
required_NET2: CUSTOM_PHYSNET2
resources_NET2: NET_BW_EGR_KILOBIT_PER_SEC:20
resources: VCPU:1
group_policy: isolate
- name: put allocation with results
PUT: /allocations/254eea13-27e1-4305-b35f-5dedd9f58ba0
data:
allocations: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].allocations']
mappings: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].mappings']
consumer_generation: null
user_id: 8c974f9a-f266-42f7-8613-a8017cbfb87F
project_id: b2e599e0-ded8-47fd-b8ab-ceb7fca578bd
status: 204
- name: put allocation wrong microversion
PUT: /allocations/5662942e-497f-4a54-8257-dcbb3fa3e5f4
request_headers:
openstack-api-version: placement 1.33
data:
allocations: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].allocations']
mappings: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].mappings']
consumer_generation: null
user_id: 8c974f9a-f266-42f7-8613-a8017cbfb87F
project_id: b2e599e0-ded8-47fd-b8ab-ceb7fca578bd
status: 400
response_json_paths:
$.errors[0].detail: /Additional properties are not allowed/
- name: put allocation mapping bad form
PUT: /allocations/5f9588de-079d-462a-a459-408524ab9b60
data:
allocations: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].allocations']
mappings:
alpha: beta
consumer_generation: null
user_id: 8c974f9a-f266-42f7-8613-a8017cbfb87F
project_id: b2e599e0-ded8-47fd-b8ab-ceb7fca578bd
status: 400
response_json_paths:
# u? accounts for difference in Python 2.7 v. 3.x response
$.errors[0].detail: "/JSON does not validate: u?'beta' is not of type 'array'/"
- name: post allocation with results
POST: /allocations
data:
'0b2c687e-89eb-47f6-bb68-2fc83e28032a':
allocations: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].allocations']
mappings: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].mappings']
consumer_generation: null
user_id: 8c974f9a-f266-42f7-8613-a8017cbfb87F
project_id: b2e599e0-ded8-47fd-b8ab-ceb7fca578bd
status: 204
- name: post allocation wrong microversion
POST: /allocations
request_headers:
openstack-api-version: placement 1.33
data:
'0b2c687e-89eb-47f6-bb68-2fc83e28032a':
allocations: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].allocations']
mappings: $HISTORY['mappings request'].$RESPONSE['$.allocation_requests[0].mappings']
consumer_generation: null
user_id: 8c974f9a-f266-42f7-8613-a8017cbfb87F
project_id: b2e599e0-ded8-47fd-b8ab-ceb7fca578bd
status: 400
response_json_paths:
$.errors[0].detail: /Additional properties are not allowed/

View File

@ -41,13 +41,13 @@ tests:
response_json_paths: response_json_paths:
$.errors[0].title: Not Acceptable $.errors[0].title: Not Acceptable
- name: latest microversion is 1.33 - name: latest microversion is 1.34
GET: / GET: /
request_headers: request_headers:
openstack-api-version: placement latest openstack-api-version: placement latest
response_headers: response_headers:
vary: /openstack-api-version/ vary: /openstack-api-version/
openstack-api-version: placement 1.33 openstack-api-version: placement 1.34
- name: other accept header bad version - name: other accept header bad version
GET: / GET: /

View File

@ -556,3 +556,134 @@ tests:
response_json_paths: response_json_paths:
$.usages: {} $.usages: {}
$.resource_provider_generation: 5 $.resource_provider_generation: 5
# At microversion 1.34 we accept a mappings key with allocations.
- name: reshape with mappings
POST: /reshaper
request_headers:
openstack-api-version: placement 1.34
data:
inventories:
$ENVIRON['RP_UUID']:
resource_provider_generation: 11
inventories:
DISK_GB:
total: 2048
step_size: 10
min_unit: 10
max_unit: 1200
VCPU:
total: 10
max_unit: 8
$ENVIRON['ALT_RP_UUID']:
resource_provider_generation: 5
inventories: {}
allocations:
$ENVIRON['CONSUMER_0']:
allocations:
$ENVIRON['RP_UUID']:
resources:
DISK_GB: 1000
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['USER_ID']
consumer_generation: 3
mappings:
'':
- $ENVIRON['RP_UUID']
'7bd2e864-0415-445c-8fc2-328520ef7642':
allocations:
$ENVIRON['RP_UUID']:
resources:
VCPU: 8
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['USER_ID']
consumer_generation: 1
'2dfa608c-cecb-4fe0-a1bb-950015fa731f':
allocations:
$ENVIRON['RP_UUID']:
resources:
DISK_GB: 20
VCPU: 1
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['ALT_USER_ID']
consumer_generation: 1
$ENVIRON['CONSUMER_ID']:
allocations: {}
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['USER_ID']
consumer_generation: null
$ENVIRON['ALT_CONSUMER_ID']:
allocations:
$ENVIRON['RP_UUID']:
resources:
DISK_GB: 20
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['ALT_USER_ID']
consumer_generation: 3
status: 204
- name: reshape with mappings wrong microversion
POST: /reshaper
request_headers:
openstack-api-version: placement 1.33
data:
inventories:
$ENVIRON['RP_UUID']:
resource_provider_generation: 8
inventories:
DISK_GB:
total: 2048
step_size: 10
min_unit: 10
max_unit: 1200
VCPU:
total: 10
max_unit: 8
$ENVIRON['ALT_RP_UUID']:
resource_provider_generation: 3
inventories: {}
allocations:
$ENVIRON['CONSUMER_0']:
allocations:
$ENVIRON['RP_UUID']:
resources:
DISK_GB: 1000
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['USER_ID']
consumer_generation: 2
mappings:
'':
- $ENVIRON['RP_UUID']
'7bd2e864-0415-445c-8fc2-328520ef7642':
allocations:
$ENVIRON['RP_UUID']:
resources:
VCPU: 8
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['USER_ID']
consumer_generation: null
'2dfa608c-cecb-4fe0-a1bb-950015fa731f':
allocations:
$ENVIRON['RP_UUID']:
resources:
DISK_GB: 20
VCPU: 1
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['ALT_USER_ID']
consumer_generation: null
$ENVIRON['CONSUMER_ID']:
allocations: {}
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['USER_ID']
consumer_generation: 2
$ENVIRON['ALT_CONSUMER_ID']:
allocations:
$ENVIRON['RP_UUID']:
resources:
DISK_GB: 20
project_id: $ENVIRON['PROJECT_ID']
user_id: $ENVIRON['ALT_USER_ID']
consumer_generation: 2
status: 400
response_json_paths:
$.errors[0].detail: /Additional properties are not allowed/

View File

@ -0,0 +1,14 @@
---
features:
- |
In microversion 1.34_ the body of the response to a
``GET /allocation_candidates`` request_ has been extended to include a
``mappings`` field with each allocation request. The value is a dictionary
associating request group suffixes with the uuids of those resource
providers that satisfy the identified request group. For convenience, this
mapping can be included in the request payload for ``POST /allocations``,
``PUT /allocations/{consumer_uuid}``, and ``POST /reshaper``, but it will
be ignored.
.. _1.34: https://docs.openstack.org/placement/latest/placement-api-microversion-history.html#request-group-mappings-in-allocation-candidates
.. _request: https://developer.openstack.org/api-ref/placement/?expanded=list-allocation-candidates-detail#list-allocation-candidates