/services?name=<name> API fails when using list_limit

When using list_limit configuration option in Default section of
keystone.conf, the /services?name=<service_name> API fails to find
the service if list_limit value is smaller than the total number
of services and the searched service is not among the first
'list_limit' services. The API should first filter by name and
only afterwards truncate the result list.

Also, this patch fixes setting the 'truncated' attribute of the
driver's hint.limit object when truncating the list outside of
driver_hints.truncated decorator, problem exposed by fixing the
problem described in the first paragraph.

Closes-Bug: #1594482
Change-Id: I832f542c3cb0faf94a1e5bce5a894f7f4d26a8de
This commit is contained in:
Roxana Gherle 2016-06-20 10:53:36 -07:00
parent 78161c8481
commit 6a9a9f002f
4 changed files with 23 additions and 4 deletions

View File

@ -38,7 +38,7 @@ def truncated(f):
_('Cannot truncate a driver call without hints list as ' _('Cannot truncate a driver call without hints list as '
'first parameter after self ')) 'first parameter after self '))
if hints.limit is None: if hints.limit is None or hints.filters:
return f(self, hints, *args, **kwargs) return f(self, hints, *args, **kwargs)
# A limit is set, so ask for one more entry than we need # A limit is set, so ask for one more entry than we need

View File

@ -371,7 +371,11 @@ def _limit(query, hints):
# If we satisfied all the filters, set an upper limit if supplied # If we satisfied all the filters, set an upper limit if supplied
if hints.limit: if hints.limit:
query = query.limit(hints.limit['limit']) original_len = query.count()
limit_query = query.limit(hints.limit['limit'])
if limit_query.count() < original_len:
hints.limit['truncated'] = True
query = limit_query
return query return query

View File

@ -345,12 +345,13 @@ class CatalogTestCase(test_v3.RestfulTestCase):
def test_filter_list_services_by_name(self): def test_filter_list_services_by_name(self):
"""Call ``GET /services?name=<some name>``.""" """Call ``GET /services?name=<some name>``."""
target_ref = self._create_random_service()
# create unrelated services # create unrelated services
self._create_random_service() self._create_random_service()
self._create_random_service() self._create_random_service()
# create the desired service
target_ref = self._create_random_service()
response = self.get('/services?name=' + target_ref['name']) response = self.get('/services?name=' + target_ref['name'])
self.assertValidServiceListResponse(response, ref=target_ref) self.assertValidServiceListResponse(response, ref=target_ref)
@ -360,6 +361,12 @@ class CatalogTestCase(test_v3.RestfulTestCase):
filtered_service = filtered_service_list[0] filtered_service = filtered_service_list[0]
self.assertEqual(target_ref['name'], filtered_service['name']) self.assertEqual(target_ref['name'], filtered_service['name'])
def test_filter_list_services_by_name_with_list_limit(self):
"""Call ``GET /services?name=<some name>``."""
self.config_fixture.config(list_limit=1)
self.test_filter_list_services_by_name()
def test_get_head_service(self): def test_get_head_service(self):
"""Call ``GET & HEAD /services/{service_id}``.""" """Call ``GET & HEAD /services/{service_id}``."""
resource_url = '/services/%(service_id)s' % { resource_url = '/services/%(service_id)s' % {

View File

@ -0,0 +1,8 @@
---
fixes:
- >
[`bug 1594482 <https://bugs.launchpad.net/keystone/+bug/1594482>`_]
When using list_limit config option, the GET /services?name={service_name}
API was first truncating the list and afterwards filtering by name.
The API was fixed to first filter by name and only afterwards truncate the
result list to the desired limit.