diff --git a/nova/api/openstack/placement/handlers/resource_provider.py b/nova/api/openstack/placement/handlers/resource_provider.py index d8a895e79..703169dd8 100644 --- a/nova/api/openstack/placement/handlers/resource_provider.py +++ b/nova/api/openstack/placement/handlers/resource_provider.py @@ -18,6 +18,7 @@ from oslo_serialization import jsonutils from oslo_utils import uuidutils import webob +from nova.api.openstack.placement import microversion from nova.api.openstack.placement import util from nova import exception from nova.i18n import _ @@ -162,8 +163,11 @@ def list_resource_providers(req): a collection of resource providers. """ context = req.environ['placement.context'] + want_version = req.environ[microversion.MICROVERSION_ENVIRON] allowed_filters = set(objects.ResourceProviderList.allowed_filters) + if not want_version.matches((1, 3)): + allowed_filters.remove('member_of') passed_filters = set(req.GET.keys()) invalid_filters = passed_filters - allowed_filters if invalid_filters: @@ -180,7 +184,18 @@ def list_resource_providers(req): filters = {} for attr in objects.ResourceProviderList.allowed_filters: if attr in req.GET: - filters[attr] = req.GET[attr] + value = req.GET[attr] + # special case member_of to always make its value a + # list, either by accepting the single value, or if it + # starts with 'in:' splitting on ','. + # NOTE(cdent): This will all change when we start using + # JSONSchema validation of query params. + if attr == 'member_of': + if value.startswith('in:'): + value = value[3:].split(',') + else: + value = [value] + filters[attr] = value resource_providers = objects.ResourceProviderList.get_all_by_filters( context, filters) diff --git a/nova/api/openstack/placement/microversion.py b/nova/api/openstack/placement/microversion.py index 72c857822..d293dcf1f 100644 --- a/nova/api/openstack/placement/microversion.py +++ b/nova/api/openstack/placement/microversion.py @@ -37,6 +37,8 @@ VERSIONS = [ '1.0', '1.1', # initial support for aggregate.get_aggregates and set_aggregates '1.2', # Adds /resource_classes resource endpoint + '1.3', # Adds 'member_of' query parameter to get resource providers + # that are members of any of the listed aggregates ] diff --git a/nova/api/openstack/placement/rest_api_version_history.rst b/nova/api/openstack/placement/rest_api_version_history.rst index b500dd1d4..2810af5d6 100644 --- a/nova/api/openstack/placement/rest_api_version_history.rst +++ b/nova/api/openstack/placement/rest_api_version_history.rst @@ -44,3 +44,11 @@ The following new routes are added: Custom resource classes must begin with the prefix "CUSTOM\_" and contain only the letters A through Z, the numbers 0 through 9 and the underscore "\_" character. + +1.3 member_of query parameter +----------------------------- + +Version 1.3 adds support for listing resource providers that are members of +any of the list of aggregates provided using a ``member_of`` query parameter: + +* /resource_providers?member_of=in:{agg1_uuid},{agg2_uuid},{agg3_uuid} diff --git a/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml b/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml index 32a4f4fb9..56a6729e1 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml @@ -37,13 +37,13 @@ tests: response_strings: - "Unacceptable version header: 0.5" -- name: latest microversion is 1.2 +- name: latest microversion is 1.3 GET: / request_headers: openstack-api-version: placement latest response_headers: vary: /OpenStack-API-Version/ - openstack-api-version: placement 1.2 + openstack-api-version: placement 1.3 - name: other accept header bad version GET: / diff --git a/nova/tests/functional/api/openstack/placement/gabbits/resource-provider-aggregates.yaml b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider-aggregates.yaml new file mode 100644 index 000000000..044806803 --- /dev/null +++ b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider-aggregates.yaml @@ -0,0 +1,100 @@ +# Tests filtering resource providers by aggregates + +fixtures: + - APIFixture + +defaults: + request_headers: + x-auth-token: admin + content-type: application/json + accept: application/json + openstack-api-version: placement latest + +tests: + +- name: post new provider 1 + POST: /resource_providers + data: + name: rp_1 + uuid: 893337e9-1e55-49f0-bcfe-6a2f16fbf2f7 + status: 201 + +- name: post new provider 2 + POST: /resource_providers + data: + name: rp_2 + uuid: 5202c48f-c960-4eec-bde3-89c4f22a17b9 + status: 201 + +- name: get by aggregates no result + GET: '/resource_providers?member_of=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91' + response_json_paths: + $.resource_providers: [] + +- name: associate an aggregate with rp1 + PUT: /resource_providers/893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/aggregates + data: + - 83a3d69d-8920-48e2-8914-cadfd8fa2f91 + status: 200 + +- name: get by aggregates one result + GET: '/resource_providers?member_of=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91' + response_json_paths: + $.resource_providers[0].uuid: 893337e9-1e55-49f0-bcfe-6a2f16fbf2f7 + +- name: get by aggregates one result no in + GET: '/resource_providers?member_of=83a3d69d-8920-48e2-8914-cadfd8fa2f91' + response_json_paths: + $.resource_providers[0].uuid: 893337e9-1e55-49f0-bcfe-6a2f16fbf2f7 + +- name: associate an aggregate with rp2 + PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates + data: + - 83a3d69d-8920-48e2-8914-cadfd8fa2f91 + status: 200 + +- name: get by aggregates two result + GET: '/resource_providers?member_of=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91' + response_json_paths: + $.resource_providers.`len`: 2 + $.resource_providers[0].uuid: /5202c48f-c960-4eec-bde3-89c4f22a17b9|893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/ + $.resource_providers[1].uuid: /5202c48f-c960-4eec-bde3-89c4f22a17b9|893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/ + +- name: associate another aggregate with rp2 + PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates + data: + - 99652f11-9f77-46b9-80b7-4b1989be9f8c + status: 200 + +- name: get by both aggregates two + GET: '/resource_providers?member_of=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91,99652f11-9f77-46b9-80b7-4b1989be9f8c' + response_json_paths: + $.resource_providers.`len`: 2 + $.resource_providers[0].uuid: /5202c48f-c960-4eec-bde3-89c4f22a17b9|893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/ + $.resource_providers[1].uuid: /5202c48f-c960-4eec-bde3-89c4f22a17b9|893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/ + +- name: clear aggregates on rp1 + PUT: /resource_providers/893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/aggregates + data: [] + status: 200 + +- name: get by both aggregates one + desc: only one result because we disassociated aggregates in the PUT above + GET: '/resource_providers?member_of=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91,99652f11-9f77-46b9-80b7-4b1989be9f8c' + response_json_paths: + $.resource_providers.`len`: 1 + $.resource_providers[0].uuid: 5202c48f-c960-4eec-bde3-89c4f22a17b9 + +- name: error on old microverison + GET: '/resource_providers?member_of=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91,99652f11-9f77-46b9-80b7-4b1989be9f8c' + request_headers: + openstack-api-version: placement 1.1 + status: 400 + response_json_paths: + $.errors[0].detail: '/Invalid filters: member_of/' + +- name: error on bogus query parameter + GET: '/resource_providers?assoc_with_aggregate=in:83a3d69d-8920-48e2-8914-cadfd8fa2f91,99652f11-9f77-46b9-80b7-4b1989be9f8c' + status: 400 + response_json_paths: + $.errors[0].detail: '/Invalid filters: assoc_with_aggregate/' diff --git a/releasenotes/notes/placement-api-member-of-d8a08d0d0c5700d7.yaml b/releasenotes/notes/placement-api-member-of-d8a08d0d0c5700d7.yaml new file mode 100644 index 000000000..7f1045ffc --- /dev/null +++ b/releasenotes/notes/placement-api-member-of-d8a08d0d0c5700d7.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + A new Placement API microversion 1.3 is added with support for filtering + the list of resource providers to include only those resource providers + which are members of any of the aggregates listed by uuid in the `member_of` + query parameter. The parameter is used when making a + `GET /resource_providers` request. The value of the parameter uses the + `in:` syntax to provide a list of aggregate uuids as follows:: + + /resource_providers?member_of=in:09c931b0-c0d7-4e80-8e01-9e6511db8259,f8ab4fa2-804f-402e-b675-7918bd04b173 + + If other filtering query parameters are present, the results are a boolean + AND of all the filters.