diff --git a/api-ref/source/allocation_candidates.inc b/api-ref/source/allocation_candidates.inc index 53a4afb03..41dd7599d 100644 --- a/api-ref/source/allocation_candidates.inc +++ b/api-ref/source/allocation_candidates.inc @@ -57,10 +57,17 @@ Response (microversions 1.12 - ) - traits: traits_1_17 - parent_provider_uuid: resource_provider_parent_provider_uuid_response_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 :language: javascript diff --git a/api-ref/source/allocations.inc b/api-ref/source/allocations.inc index 0269af495..fbd8dea99 100644 --- a/api-ref/source/allocations.inc +++ b/api-ref/source/allocations.inc @@ -43,6 +43,7 @@ Request - allocations: allocations_dict_empty - generation: resource_provider_generation_optional - resources: resources + - mappings: mappings_in_allocations Request example (microversions 1.28 - ) --------------------------------------- @@ -136,6 +137,7 @@ Request (microversions 1.12 - ) - project_id: project_id_body - user_id: user_id_body - generation: resource_provider_generation_optional + - mappings: mappings_in_allocations Request example (microversions 1.28 - ) --------------------------------------- diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index f026d7d11..55df413cf 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -462,6 +462,20 @@ inventories: required: true description: > 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 type: integer in: body diff --git a/api-ref/source/reshaper.inc b/api-ref/source/reshaper.inc index 4d23a8913..de56948a7 100644 --- a/api-ref/source/reshaper.inc +++ b/api-ref/source/reshaper.inc @@ -38,6 +38,7 @@ Request - allocations.{consumer_uuid}.allocations.{resource_provider_uuid}.resources: resources - allocations.{consumer_uuid}.project_id: project_id_body - allocations.{consumer_uuid}.user_id: user_id_body + - allocations.{consumer_uuid}.mappings: mappings - allocations.{consumer_uuid}.consumer_generation: consumer_generation Request Example diff --git a/api-ref/source/samples/allocation_candidates/get-allocation_candidates-1.34.json b/api-ref/source/samples/allocation_candidates/get-allocation_candidates-1.34.json new file mode 100644 index 000000000..85b8ded10 --- /dev/null +++ b/api-ref/source/samples/allocation_candidates/get-allocation_candidates-1.34.json @@ -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" + } + } +} diff --git a/placement/handlers/allocation.py b/placement/handlers/allocation.py index b68775807..9be824044 100644 --- a/placement/handlers/allocation.py +++ b/placement/handlers/allocation.py @@ -483,12 +483,19 @@ def set_allocations_for_consumer(req): @wsgi_wrapper.PlacementWsgify # noqa -@microversion.version_handler('1.28') +@microversion.version_handler('1.28', '1.33') @util.require_content('application/json') def set_allocations_for_consumer(req): 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 @microversion.version_handler('1.13') @util.require_content('application/json') @@ -499,6 +506,8 @@ def set_allocations(req): want_schema = schema.POST_ALLOCATIONS_V1_13 if want_version.matches((1, 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) consumers, new_consumers_created = inspect_consumers( diff --git a/placement/handlers/allocation_candidate.py b/placement/handlers/allocation_candidate.py index 4b69aec41..3bccf9dfd 100644 --- a/placement/handlers/allocation_candidate.py +++ b/placement/handlers/allocation_candidate.py @@ -30,7 +30,7 @@ from placement import util 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 allocations dicts keyed by resource provider uuid of resources involved 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: # A default dict of {$rp_uuid: "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: + suffix = rr.suffix + mappings[suffix].append(rr.resource_provider.uuid) res_dict = rp_resources[rr.resource_provider.uuid]['resources'] 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 @@ -214,7 +228,7 @@ def _transform_allocation_candidates(alloc_cands, requests, want_version): """ if want_version.matches((1, 12)): a_reqs = _transform_allocation_requests_dict( - alloc_cands.allocation_requests) + alloc_cands.allocation_requests, want_version) else: a_reqs = _transform_allocation_requests_list( alloc_cands.allocation_requests) diff --git a/placement/handlers/reshaper.py b/placement/handlers/reshaper.py index ec140e548..ef70e4034 100644 --- a/placement/handlers/reshaper.py +++ b/placement/handlers/reshaper.py @@ -44,7 +44,11 @@ def reshape(req): context = req.environ['placement.context'] want_version = req.environ[microversion.MICROVERSION_ENVIRON] 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'] allocations = data['allocations'] # We're going to create several lists of Inventory objects, keyed by rp diff --git a/placement/lib.py b/placement/lib.py index 81e3dfbf9..436d853ac 100644 --- a/placement/lib.py +++ b/placement/lib.py @@ -19,7 +19,7 @@ import re import webob from placement import microversion -from placement.schemas import allocation_candidate +from placement.schemas import common from placement import util @@ -31,11 +31,11 @@ _QS_IN_TREE = 'in_tree' _QS_KEY_PATTERN = re.compile( r"^(%s)(%s)?$" % ('|'.join( (_QS_RESOURCES, _QS_REQUIRED, _QS_MEMBER_OF, _QS_IN_TREE)), - allocation_candidate.GROUP_PAT)) + common.GROUP_PAT)) _QS_KEY_PATTERN_1_33 = re.compile( r"^(%s)(%s)?$" % ('|'.join( (_QS_RESOURCES, _QS_REQUIRED, _QS_MEMBER_OF, _QS_IN_TREE)), - allocation_candidate.GROUP_PAT_1_33)) + common.GROUP_PAT_1_33)) class RequestGroup(object): diff --git a/placement/microversion.py b/placement/microversion.py index abd832c92..fb0932e6b 100644 --- a/placement/microversion.py +++ b/placement/microversion.py @@ -83,6 +83,8 @@ VERSIONS = [ # `GET /resource_providers` and `GET /allocation_candidates` '1.33', # Support granular resource requests with suffixes that match # [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. ] diff --git a/placement/rest_api_version_history.rst b/placement/rest_api_version_history.rst index 34f54aa25..f0b60442d 100644 --- a/placement/rest_api_version_history.rst +++ b/placement/rest_api_version_history.rst @@ -625,3 +625,16 @@ it is now possible to use more complex strings, including UUIDs:: resources_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=XXX &required_PORT_fccc7adb-095e-4bfd-8c9b-942f41990664=YYY &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. diff --git a/placement/schemas/allocation.py b/placement/schemas/allocation.py index 8c49bf771..414372f9e 100644 --- a/placement/schemas/allocation.py +++ b/placement/schemas/allocation.py @@ -167,3 +167,26 @@ POST_ALLOCATIONS_V1_28 = copy.deepcopy(POST_ALLOCATIONS_V1_13) POST_ALLOCATIONS_V1_28["patternProperties"] = { 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 +} diff --git a/placement/schemas/allocation_candidate.py b/placement/schemas/allocation_candidate.py index f5747ab0c..ed47e0b78 100644 --- a/placement/schemas/allocation_candidate.py +++ b/placement/schemas/allocation_candidate.py @@ -13,11 +13,7 @@ import copy - -# 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}' +from placement.schemas import common # 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"]["member_of"] # 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"] = { _GROUP_PAT_FMT % "resources": { "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. 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"] = { _GROUP_PAT_FMT_1_33 % group_type: {"type": "string"} for group_type in ('resources', 'required', 'member_of', 'in_tree')} diff --git a/placement/schemas/common.py b/placement/schemas/common.py index 51d3ee925..da1d691ea 100644 --- a/placement/schemas/common.py +++ b/placement/schemas/common.py @@ -20,3 +20,8 @@ RC_PATTERN = _RC_TRAIT_PATTERN _CUSTOM_RC_TRAIT_PATTERN = "^CUSTOM_%s+$" % _RC_TRAIT_CHAR CUSTOM_RC_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}' diff --git a/placement/schemas/reshaper.py b/placement/schemas/reshaper.py index 1730e5b37..3da8a812b 100644 --- a/placement/schemas/reshaper.py +++ b/placement/schemas/reshaper.py @@ -45,3 +45,8 @@ POST_RESHAPER_SCHEMA = { ], "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 diff --git a/placement/tests/functional/gabbits/allocation-candidates-mappings-numa.yaml b/placement/tests/functional/gabbits/allocation-candidates-mappings-numa.yaml new file mode 100644 index 000000000..88ca011ae --- /dev/null +++ b/placement/tests/functional/gabbits/allocation-candidates-mappings-numa.yaml @@ -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'] diff --git a/placement/tests/functional/gabbits/allocation-candidates-mappings-sharing.yaml b/placement/tests/functional/gabbits/allocation-candidates-mappings-sharing.yaml new file mode 100644 index 000000000..7e7b18a57 --- /dev/null +++ b/placement/tests/functional/gabbits/allocation-candidates-mappings-sharing.yaml @@ -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'])/ diff --git a/placement/tests/functional/gabbits/allocations-mappings.yaml b/placement/tests/functional/gabbits/allocations-mappings.yaml new file mode 100644 index 000000000..cd112a05f --- /dev/null +++ b/placement/tests/functional/gabbits/allocations-mappings.yaml @@ -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/ diff --git a/placement/tests/functional/gabbits/microversion.yaml b/placement/tests/functional/gabbits/microversion.yaml index 317b3caaa..e37cf90ce 100644 --- a/placement/tests/functional/gabbits/microversion.yaml +++ b/placement/tests/functional/gabbits/microversion.yaml @@ -41,13 +41,13 @@ tests: response_json_paths: $.errors[0].title: Not Acceptable -- name: latest microversion is 1.33 +- name: latest microversion is 1.34 GET: / request_headers: openstack-api-version: placement latest response_headers: vary: /openstack-api-version/ - openstack-api-version: placement 1.33 + openstack-api-version: placement 1.34 - name: other accept header bad version GET: / diff --git a/placement/tests/functional/gabbits/reshaper.yaml b/placement/tests/functional/gabbits/reshaper.yaml index 786d43014..9539287bb 100644 --- a/placement/tests/functional/gabbits/reshaper.yaml +++ b/placement/tests/functional/gabbits/reshaper.yaml @@ -556,3 +556,134 @@ tests: response_json_paths: $.usages: {} $.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/ diff --git a/releasenotes/notes/allocation-candidate-mappings-e00cf6deadcee9ab.yaml b/releasenotes/notes/allocation-candidate-mappings-e00cf6deadcee9ab.yaml new file mode 100644 index 000000000..8ac0e7608 --- /dev/null +++ b/releasenotes/notes/allocation-candidate-mappings-e00cf6deadcee9ab.yaml @@ -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