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:
@@ -22,6 +22,8 @@ from glanceclient.openstack.common import strutils
|
|||||||
from glanceclient.v2 import schemas
|
from glanceclient.v2 import schemas
|
||||||
|
|
||||||
DEFAULT_PAGE_SIZE = 20
|
DEFAULT_PAGE_SIZE = 20
|
||||||
|
SORT_DIR_VALUES = ('asc', 'desc')
|
||||||
|
SORT_KEY_VALUES = ('created_at', 'namespace')
|
||||||
|
|
||||||
|
|
||||||
class NamespaceController(object):
|
class NamespaceController(object):
|
||||||
@@ -88,8 +90,17 @@ class NamespaceController(object):
|
|||||||
|
|
||||||
def list(self, **kwargs):
|
def list(self, **kwargs):
|
||||||
"""Retrieve a listing of Namespace objects
|
"""Retrieve a listing of Namespace objects
|
||||||
|
:param page_size: Number of items to request in each paginated request
|
||||||
:param page_size: Number of namespaces to request in each 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
|
:returns generator over list of Namespaces
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -129,6 +140,25 @@ class NamespaceController(object):
|
|||||||
else:
|
else:
|
||||||
filters['limit'] = kwargs['page_size']
|
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):
|
for param, value in six.iteritems(filters):
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
filters[param] = strutils.safe_encode(','.join(value))
|
filters[param] = strutils.safe_encode(','.join(value))
|
||||||
|
@@ -89,7 +89,7 @@ data_fixtures = {
|
|||||||
"GET": (
|
"GET": (
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
"first": "/v2/metadefs/namespaces?limit=1",
|
"first": "/v2/metadefs/namespaces?limit=2",
|
||||||
"namespaces": [
|
"namespaces": [
|
||||||
_get_namespace_fixture(NAMESPACE8),
|
_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: {
|
"/v2/metadefs/namespaces?limit=20&resource_types=%s" % RESOURCE_TYPE1: {
|
||||||
"GET": (
|
"GET": (
|
||||||
{},
|
{},
|
||||||
@@ -269,7 +306,7 @@ data_fixtures = {
|
|||||||
"updated_at": "2014-08-14T09:07:06Z",
|
"updated_at": "2014-08-14T09:07:06Z",
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
schema_fixtures = {
|
schema_fixtures = {
|
||||||
@@ -521,6 +558,40 @@ class TestNamespaceController(testtools.TestCase):
|
|||||||
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
|
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
|
||||||
self.assertEqual(NAMESPACE8, namespaces[1]['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):
|
def test_list_namespaces_with_one_resource_type_filter(self):
|
||||||
namespaces = list(self.controller.list(
|
namespaces = list(self.controller.list(
|
||||||
filters={
|
filters={
|
||||||
|
Reference in New Issue
Block a user