From b838f2225c324926454de4fa8d1dfeb5d1806a21 Mon Sep 17 00:00:00 2001 From: Roman Podoliaka Date: Fri, 15 Jul 2016 21:51:31 +0300 Subject: [PATCH] placement: add filtering by attrs to resource_providers Make it possible to GET /resource_providers passing filters as query params to get only a subset of resource providers. Partially-Implements: blueprint generic-resource-pools Change-Id: I2c905d55ac20fd1c5a285b1e460cdd31dff8c7dd --- .../placement/handlers/resource_provider.py | 21 ++++++++- nova/objects/resource_provider.py | 10 ++++- .../placement/gabbits/resource-provider.yaml | 44 +++++++++++++++++++ .../functional/db/test_resource_provider.py | 4 ++ 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/nova/api/openstack/placement/handlers/resource_provider.py b/nova/api/openstack/placement/handlers/resource_provider.py index a64a9945bd6f..18b2a2f005fb 100644 --- a/nova/api/openstack/placement/handlers/resource_provider.py +++ b/nova/api/openstack/placement/handlers/resource_provider.py @@ -175,8 +175,27 @@ def list_resource_providers(req): a collection of resource providers. """ context = req.environ['placement.context'] + + allowed_filters = set(objects.ResourceProviderList.allowed_filters) + passed_filters = set(req.GET.keys()) + invalid_filters = passed_filters - allowed_filters + if invalid_filters: + raise webob.exc.HTTPBadRequest( + 'Invalid filters: %s' % ', '.join(invalid_filters), + json_formatter=util.json_error_formatter) + + if 'uuid' in req.GET and not uuidutils.is_uuid_like(req.GET['uuid']): + raise webob.exc.HTTPBadRequest( + 'Invalid uuid value: %s' % req.GET['uuid'], + json_formatter=util.json_error_formatter) + + filters = {} + for attr in objects.ResourceProviderList.allowed_filters: + if attr in req.GET: + filters[attr] = req.GET[attr] resource_providers = objects.ResourceProviderList.get_all_by_filters( - context) + context, filters) + response = req.response response.body = jsonutils.dumps(_serialize_providers( req.environ, resource_providers)) diff --git a/nova/objects/resource_provider.py b/nova/objects/resource_provider.py index 60d4496331b8..ea6ceecb3ca3 100644 --- a/nova/objects/resource_provider.py +++ b/nova/objects/resource_provider.py @@ -358,14 +358,20 @@ class ResourceProviderList(base.ObjectListBase, base.NovaObject): 'objects': fields.ListOfObjectsField('ResourceProvider'), } + allowed_filters = ( + 'name', 'uuid' + ) + @staticmethod @db_api.placement_context_manager.reader def _get_all_by_filters_from_db(context, filters): if not filters: filters = {} query = context.session.query(models.ResourceProvider) - if 'name' in filters: - query = query.filter_by(name=filters['name']) + for attr in ResourceProviderList.allowed_filters: + if attr in filters: + query = query.filter( + getattr(models.ResourceProvider, attr) == filters[attr]) query = query.filter_by(can_host=filters.get('can_host', 0)) return query.all() 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 08e54b6ff384..3c3687401d51 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml @@ -98,6 +98,50 @@ tests: $.resource_providers[0].links[?rel = "aggregates"].href: /resource_providers/$ENVIRON['RP_UUID']/aggregates $.resource_providers[0].links[?rel = "usages"].href: /resource_providers/$ENVIRON['RP_UUID']/usages +- name: filter out all resource providers by name + GET: /resource_providers?name=flubblebubble + response_json_paths: + $.resource_providers.`len`: 0 + +- name: filter out all resource providers by uuid + GET: /resource_providers?uuid=d67370b5-4dc0-470d-a4fa-85e8e89abc6c + response_json_paths: + $.resource_providers.`len`: 0 + +- name: list one resource provider filtering by name + GET: /resource_providers?name=$ENVIRON['RP_NAME'] + response_json_paths: + $.resource_providers.`len`: 1 + $.resource_providers[0].uuid: $ENVIRON['RP_UUID'] + $.resource_providers[0].name: $ENVIRON['RP_NAME'] + $.resource_providers[0].links[?rel = "self"].href: /resource_providers/$ENVIRON['RP_UUID'] + $.resource_providers[0].links[?rel = "inventories"].href: /resource_providers/$ENVIRON['RP_UUID']/inventories + $.resource_providers[0].links[?rel = "aggregates"].href: /resource_providers/$ENVIRON['RP_UUID']/aggregates + $.resource_providers[0].links[?rel = "usages"].href: /resource_providers/$ENVIRON['RP_UUID']/usages + +- name: list resource providers filtering by invalid uuid + GET: /resource_providers?uuid=spameggs + status: 400 + response_strings: + - 'Invalid uuid value: spameggs' + +- name: list resource providers providing an invalid filter + GET: /resource_providers?spam=eggs + status: 400 + response_strings: + - 'Invalid filters: spam' + +- name: list one resource provider filtering by uuid + GET: /resource_providers?uuid=$ENVIRON['RP_UUID'] + response_json_paths: + $.resource_providers.`len`: 1 + $.resource_providers[0].uuid: $ENVIRON['RP_UUID'] + $.resource_providers[0].name: $ENVIRON['RP_NAME'] + $.resource_providers[0].links[?rel = "self"].href: /resource_providers/$ENVIRON['RP_UUID'] + $.resource_providers[0].links[?rel = "inventories"].href: /resource_providers/$ENVIRON['RP_UUID']/inventories + $.resource_providers[0].links[?rel = "aggregates"].href: /resource_providers/$ENVIRON['RP_UUID']/aggregates + $.resource_providers[0].links[?rel = "usages"].href: /resource_providers/$ENVIRON['RP_UUID']/usages + - name: update a resource provider PUT: /resource_providers/$RESPONSE['$.resource_providers[0].uuid'] request_headers: diff --git a/nova/tests/functional/db/test_resource_provider.py b/nova/tests/functional/db/test_resource_provider.py index ac63c98d3fa8..39627146c68c 100644 --- a/nova/tests/functional/db/test_resource_provider.py +++ b/nova/tests/functional/db/test_resource_provider.py @@ -387,6 +387,10 @@ class ResourceProviderListTestCase(test.NoDBTestCase): resource_providers = objects.ResourceProviderList.get_all_by_filters( self.context, filters={'can_host': 1}) self.assertEqual(0, len(resource_providers)) + resource_providers = objects.ResourceProviderList.get_all_by_filters( + self.context, filters={'uuid': getattr(uuidsentinel, 'rp_uuid_2')}) + self.assertEqual(1, len(resource_providers)) + self.assertEqual('rp_name_2', resource_providers[0].name) class TestAllocation(ResourceProviderBaseCase):