From 406b7b1cd404c017f5ce47ff555d4e7287187577 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Tue, 27 Mar 2018 11:31:13 +0100 Subject: [PATCH] [placement] Support forbidden traits in API In a new microversion (1.22) expose support for processing forbidden traits in GET /resource_providers and GET /allocation_candidates. A forbidden trait is expressed as part of the required parameter with a "!" prefix: required=CUSTOM_FAST,!CUSTOM_SLOW This change uses db and query processing code adjustments already present in the code but guarded by a flag. If the currently requested microversion matches 1.22 or beyond that flag is True, otherwise False. Reno, api-ref update and api history update are included. Because this microversion changes the value of an existing parameter it was unclear how to best express that in the api-ref. In this case existing parameter references were annotated. Partially implements blueprint placement-forbidden-traits Change-Id: I43e92bc5f97db7a2b09e64c6cb953c07d0561e63 --- .../handlers/allocation_candidate.py | 6 +- .../placement/handlers/resource_provider.py | 5 +- nova/api/openstack/placement/microversion.py | 2 + .../placement/rest_api_version_history.rst | 9 +++ .../gabbits/allocation-candidates.yaml | 21 ++++++ .../placement/gabbits/microversion.yaml | 4 +- .../placement/gabbits/resource-provider.yaml | 65 ++++++++++++++++++- placement-api-ref/source/parameters.yaml | 8 ++- ...ent-forbidden-traits-ace037856aa29a09.yaml | 9 +++ 9 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/placement-forbidden-traits-ace037856aa29a09.yaml diff --git a/nova/api/openstack/placement/handlers/allocation_candidate.py b/nova/api/openstack/placement/handlers/allocation_candidate.py index a92bd57fa..ed7fbac5d 100644 --- a/nova/api/openstack/placement/handlers/allocation_candidate.py +++ b/nova/api/openstack/placement/handlers/allocation_candidate.py @@ -220,7 +220,11 @@ def list_allocation_candidates(req): get_schema = schema.GET_SCHEMA_1_16 util.validate_query_params(req, get_schema) - requests = util.parse_qs_request_groups(req.GET) + # Control whether we handle forbidden traits. + allow_forbidden = want_version.matches((1, 22)) + + requests = util.parse_qs_request_groups( + req.GET, allow_forbidden=allow_forbidden) limit = req.GET.getall('limit') # JSONschema has already confirmed that limit has the form # of an integer. diff --git a/nova/api/openstack/placement/handlers/resource_provider.py b/nova/api/openstack/placement/handlers/resource_provider.py index 528676a3e..6cdbd069f 100644 --- a/nova/api/openstack/placement/handlers/resource_provider.py +++ b/nova/api/openstack/placement/handlers/resource_provider.py @@ -191,6 +191,8 @@ def list_resource_providers(req): elif want_version.matches((1, 3)): schema = rp_schema.GET_RPS_SCHEMA_1_3 + allow_forbidden = want_version.matches((1, 22)) + util.validate_query_params(req, schema) filters = {} @@ -217,7 +219,8 @@ def list_resource_providers(req): elif attr == 'resources': value = util.normalize_resources_qs_param(value) elif attr == 'required': - value = util.normalize_traits_qs_param(value) + value = util.normalize_traits_qs_param( + value, allow_forbidden=allow_forbidden) filters[attr] = value try: resource_providers = rp_obj.ResourceProviderList.get_all_by_filters( diff --git a/nova/api/openstack/placement/microversion.py b/nova/api/openstack/placement/microversion.py index 7bf4c3b87..79956f993 100644 --- a/nova/api/openstack/placement/microversion.py +++ b/nova/api/openstack/placement/microversion.py @@ -61,6 +61,8 @@ VERSIONS = [ '1.20', # Return 200 with provider payload from POST /resource_providers '1.21', # Support ?member_of= queryparam on # GET /allocation_candidates + '1.22', # Support forbidden traits in the required parameter of + # GET /resource_providers and GET /allocation_candidates ] diff --git a/nova/api/openstack/placement/rest_api_version_history.rst b/nova/api/openstack/placement/rest_api_version_history.rst index 22e000332..2644e3733 100644 --- a/nova/api/openstack/placement/rest_api_version_history.rst +++ b/nova/api/openstack/placement/rest_api_version_history.rst @@ -261,3 +261,12 @@ Add support for the `member_of` query parameter to the `GET aggregates. If this parameter is provided, the only resource providers returned will be those in one of the specified aggregates that meet the other parts of the request. + +1.22 Support forbidden traits on resource providers and allocations candidates +------------------------------------------------------------------------------ + +Add support for expressing traits which are forbidden when filtering +``GET /resource_providers`` or ``GET /allocation_candidates``. A forbidden +trait is a properly formatted trait in the existing ``required`` parameter, +prefixed by a ``!``. For example ``required=!STORAGE_DISK_SSD`` asks that the +results not include any resource providers that provide solid state disk. diff --git a/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates.yaml b/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates.yaml index a177329f7..f9f700a4f 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/allocation-candidates.yaml @@ -205,6 +205,14 @@ tests: response_strings: - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC." +- name: get allocation candidates with empty required value 1.22 + GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required= + status: 400 + request_headers: + openstack-api-version: placement 1.22 + response_strings: + - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,!CUSTOM_MAGIC." + - name: get allocation candidates with invalid required value GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=,, status: 400 @@ -234,6 +242,19 @@ tests: - HW_CPU_X86_SSE - HW_CPU_X86_SSE2 +- name: get allocation candidates with forbidden trait + GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=!HW_CPU_X86_SSE + status: 200 + request_headers: + openstack-api-version: placement 1.22 + response_json_paths: + # There are no allocations for CN1 + $.allocation_requests.`len`: 1 + $.allocation_requests[0].allocations.`len`: 2 + $.allocation_requests[0].allocations["$ENVIRON['CN2_UUID']"].resources.VCPU: 1 + $.allocation_requests[0].allocations["$ENVIRON['CN2_UUID']"].resources.MEMORY_MB: 1024 + $.allocation_requests[0].allocations["$ENVIRON['SS_UUID']"].resources.DISK_GB: 100 + - name: get allocation candidates with multiple required traits GET: /allocation_candidates?resources=VCPU:1,MEMORY_MB:1024,DISK_GB:100&required=HW_CPU_X86_SSE,HW_CPU_X86_SSE2 status: 200 diff --git a/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml b/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml index 92bdf55fa..d832cdd1f 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml @@ -39,13 +39,13 @@ tests: response_json_paths: $.errors[0].title: Not Acceptable -- name: latest microversion is 1.21 +- name: latest microversion is 1.22 GET: / request_headers: openstack-api-version: placement latest response_headers: vary: /openstack-api-version/ - openstack-api-version: placement 1.21 + openstack-api-version: placement 1.22 - name: other accept header bad version GET: / diff --git a/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml index d0332f0ad..b39ce6320 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml @@ -463,6 +463,59 @@ tests: # Only RP_UUID satisfies both the tree and trait constraint $.resource_providers[?uuid="$ENVIRON['RP_UUID']"].root_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID'] +- name: list providers for full count + GET: /resource_providers + response_json_paths: + $.resource_providers.`len`: 3 + +- name: list providers forbidden 1.22 + GET: /resource_providers?required=!STORAGE_DISK_SSD + response_json_paths: + $.resource_providers.`len`: 1 + +- name: confirm forbidden trait not there + GET: /resource_providers/$RESPONSE['$.resource_providers[0].uuid']/traits + response_json_paths: + $.traits: [] + +- name: list providers forbidden 1.21 + GET: /resource_providers?required=!STORAGE_DISK_SSD + request_headers: + openstack-api-version: placement 1.21 + status: 400 + response_strings: + - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC. Got: !STORAGE_DISK_SSD" + +- name: list providers forbidden again + GET: /resource_providers?required=!MISC_SHARES_VIA_AGGREGATE + response_json_paths: + $.resource_providers.`len`: 2 + +- name: mixed required and forbidden + GET: /resource_providers?required=!HW_CPU_X86_SGX,STORAGE_DISK_SSD + response_json_paths: + $.resource_providers.`len`: 1 + +- name: confirm mixed required and forbidden + GET: /resource_providers/$RESPONSE['$.resource_providers[0].uuid']/traits + response_json_paths: + $.traits.`sorted`: ['MISC_SHARES_VIA_AGGREGATE', 'STORAGE_DISK_SSD'] + +- name: multiple forbidden + GET: /resource_providers?required=!MISC_SHARES_VIA_AGGREGATE,!HW_CPU_X86_SGX + response_json_paths: + $.resource_providers.`len`: 1 + +- name: confirm multiple forbidden + GET: /resource_providers/$RESPONSE['$.resource_providers[0].uuid']/traits + response_json_paths: + $.traits: [] + +- name: forbidden no apply + GET: /resource_providers?required=!HW_CPU_X86_VMX + response_json_paths: + $.resource_providers.`len`: 3 + - name: create some inventory PUT: /resource_providers/$ENVIRON['ALT_PARENT_PROVIDER_UUID']/inventories request_headers: @@ -492,6 +545,16 @@ tests: - name: invalid 'required' parameter - blank GET: /resource_providers?required= status: 400 + response_strings: + - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,!CUSTOM_MAGIC." + response_json_paths: + $.errors[0].title: Bad Request + +- name: invalid 'required' parameter 1.21 + GET: /resource_providers?required= + request_headers: + openstack-api-version: placement 1.21 + status: 400 response_strings: - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC." response_json_paths: @@ -501,7 +564,7 @@ tests: GET: /resource_providers?required=STORAGE_DISK_SSD,,MISC_SHARES_VIA_AGGREGATE status: 400 response_strings: - - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,CUSTOM_MAGIC." + - "Invalid query string parameters: Expected 'required' parameter value of the form: HW_CPU_X86_VMX,!CUSTOM_MAGIC." response_json_paths: $.errors[0].title: Bad Request diff --git a/placement-api-ref/source/parameters.yaml b/placement-api-ref/source/parameters.yaml index d5941c160..44b7495cf 100644 --- a/placement-api-ref/source/parameters.yaml +++ b/placement-api-ref/source/parameters.yaml @@ -59,7 +59,9 @@ allocation_candidates_required: Accepts a list of comma-separated traits. Allocation requests in the response will be for resource providers that have capacity for all requested resources and the set of those resource providers will - *collectively* contain all of the required traits. + *collectively* contain all of the required traits. **Starting from + microversion 1.22** traits which are forbidden from any resource provider + may be expressed by prefixing a trait with a ``!``. member_of: type: string in: query @@ -91,7 +93,9 @@ resource_provider_required_query: required: false description: > A comma-delimited list of string trait names. Results will be filtered to - include only resource providers having all the specified traits. + include only resource providers having all the specified traits. **Starting + from microversion 1.22** traits which are forbidden from any resource + provider may be expressed by prefixing a trait with a ``!``. min_version: 1.18 resource_provider_tree_query: type: string diff --git a/releasenotes/notes/placement-forbidden-traits-ace037856aa29a09.yaml b/releasenotes/notes/placement-forbidden-traits-ace037856aa29a09.yaml new file mode 100644 index 000000000..b5c0b744d --- /dev/null +++ b/releasenotes/notes/placement-forbidden-traits-ace037856aa29a09.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Placement microversion '1.22' adds support for expressing traits which are + forbidden when filtering ``GET /resource_providers`` or ``GET + /allocation_candidates``. A forbidden trait is a properly formatted trait + in the existing ``required`` parameter, prefixed by a ``!``. For example + ``required=!STORAGE_DISK_SSD`` asks that the results not include any + resource providers that provide solid state disk.