Support Pagination for namespace list

The rest api metadefs/namespaces supports pagination using the parameters
of limit, marker, sort_dir, & sort_key. However, the glance client isn't
passing those parameters through (they come in as kwargs). This is
preventing pagination from working properly in horizon.

This is affecting Horizon support: https://review.openstack.org/#/c/104063/

Change-Id: Ib349cf3a3a437eb1711f350b37d0bd0e7d01330a
Closes-Bug: 1381816
This commit is contained in:
Travis Tripp 2014-10-15 17:46:54 -06:00
parent 3989cd202d
commit 9a4d8580e8
2 changed files with 105 additions and 4 deletions

View File

@ -22,6 +22,8 @@ from glanceclient.openstack.common import strutils
from glanceclient.v2 import schemas
DEFAULT_PAGE_SIZE = 20
SORT_DIR_VALUES = ('asc', 'desc')
SORT_KEY_VALUES = ('created_at', 'namespace')
class NamespaceController(object):
@ -88,8 +90,17 @@ class NamespaceController(object):
def list(self, **kwargs):
"""Retrieve a listing of Namespace objects
:param page_size: Number of namespaces to request in each request
:param page_size: Number of items to request in each paginated request
:param limit: Use to request a specific page size. Expect a response
to a limited request to return between zero and limit
items.
:param marker: Specifies the namespace of the last-seen namespace.
The typical pattern of limit and marker is to make an
initial limited request and then to use the last
namespace from the response as the marker parameter
in a subsequent limited request.
:param sort_key: The field to sort on (for example, 'created_at')
:param sort_dir: The direction to sort ('asc' or 'desc')
:returns generator over list of Namespaces
"""
@ -129,6 +140,25 @@ class NamespaceController(object):
else:
filters['limit'] = kwargs['page_size']
if 'marker' in kwargs:
filters['marker'] = kwargs['marker']
sort_key = kwargs.get('sort_key')
if sort_key is not None:
if sort_key in SORT_KEY_VALUES:
filters['sort_key'] = sort_key
else:
raise ValueError('sort_key must be one of the following: %s.'
% ', '.join(SORT_KEY_VALUES))
sort_dir = kwargs.get('sort_dir')
if sort_dir is not None:
if sort_dir in SORT_DIR_VALUES:
filters['sort_dir'] = sort_dir
else:
raise ValueError('sort_dir must be one of the following: %s.'
% ', '.join(SORT_DIR_VALUES))
for param, value in six.iteritems(filters):
if isinstance(value, list):
filters[param] = strutils.safe_encode(','.join(value))

View File

@ -89,7 +89,7 @@ data_fixtures = {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=1",
"first": "/v2/metadefs/namespaces?limit=2",
"namespaces": [
_get_namespace_fixture(NAMESPACE8),
],
@ -97,6 +97,43 @@ data_fixtures = {
}
)
},
"/v2/metadefs/namespaces?limit=2&marker=%s" % NAMESPACE6: {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=2",
"namespaces": [
_get_namespace_fixture(NAMESPACE7),
_get_namespace_fixture(NAMESPACE8),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&sort_dir=asc": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=1",
"namespaces": [
_get_namespace_fixture(NAMESPACE1),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&sort_key=created_at": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=1",
"namespaces": [
_get_namespace_fixture(NAMESPACE1),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&resource_types=%s" % RESOURCE_TYPE1: {
"GET": (
{},
@ -269,7 +306,7 @@ data_fixtures = {
"updated_at": "2014-08-14T09:07:06Z",
}
),
}
},
}
schema_fixtures = {
@ -521,6 +558,40 @@ class TestNamespaceController(testtools.TestCase):
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
def test_list_with_limit_greater_than_page_size(self):
namespaces = list(self.controller.list(page_size=1, limit=2))
self.assertEqual(2, len(namespaces))
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
def test_list_with_marker(self):
namespaces = list(self.controller.list(marker=NAMESPACE6, page_size=2))
self.assertEqual(2, len(namespaces))
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
def test_list_with_sort_dir(self):
namespaces = list(self.controller.list(sort_dir='asc', limit=1))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
def test_list_with_sort_dir_invalid(self):
# NOTE(TravT): The clients work by returning an iterator.
# Invoking the iterator is what actually executes the logic.
ns_iterator = self.controller.list(sort_dir='foo')
self.assertRaises(ValueError, next, ns_iterator)
def test_list_with_sort_key(self):
namespaces = list(self.controller.list(sort_key='created_at', limit=1))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
def test_list_with_sort_key_invalid(self):
# NOTE(TravT): The clients work by returning an iterator.
# Invoking the iterator is what actually executes the logic.
ns_iterator = self.controller.list(sort_key='foo')
self.assertRaises(ValueError, next, ns_iterator)
def test_list_namespaces_with_one_resource_type_filter(self):
namespaces = list(self.controller.list(
filters={