Support pagination for volume list

Since v2 api supports pagination, we should add this support in
cinderclient too.

Change-Id: I9d4cb9e192523c14cf7df043deabe156dbb8e216
Closes-bug: 1325773
This commit is contained in:
liyingjun
2014-06-04 06:28:45 +08:00
parent d77b6f8287
commit f7e9ece40b
4 changed files with 99 additions and 3 deletions

View File

@@ -102,6 +102,24 @@ class ShellTest(utils.TestCase):
self.run_command('list --all-tenants=1') self.run_command('list --all-tenants=1')
self.assert_called('GET', '/volumes/detail?all_tenants=1') self.assert_called('GET', '/volumes/detail?all_tenants=1')
@httpretty.activate
def test_list_marker(self):
self.register_keystone_auth_fixture()
self.run_command('list --marker=1234')
self.assert_called('GET', '/volumes/detail?marker=1234')
@httpretty.activate
def test_list_limit(self):
self.register_keystone_auth_fixture()
self.run_command('list --limit=10')
self.assert_called('GET', '/volumes/detail?limit=10')
@httpretty.activate
def test_list_sort(self):
self.register_keystone_auth_fixture()
self.run_command('list --sort_key=name --sort_dir=asc')
self.assert_called('GET', '/volumes/detail?sort_dir=asc&sort_key=name')
@httpretty.activate @httpretty.activate
def test_list_availability_zone(self): def test_list_availability_zone(self):
self.register_keystone_auth_fixture() self.register_keystone_auth_fixture()

View File

@@ -23,6 +23,22 @@ cs = fakes.FakeClient()
class VolumesTest(utils.TestCase): class VolumesTest(utils.TestCase):
def test_list_volumes_with_marker_limit(self):
cs.volumes.list(marker=1234, limit=2)
cs.assert_called('GET', '/volumes/detail?limit=2&marker=1234')
def test_list_volumes_with_sort_key_dir(self):
cs.volumes.list(sort_key='id', sort_dir='asc')
cs.assert_called('GET', '/volumes/detail?sort_dir=asc&sort_key=id')
def test_list_volumes_with_invalid_sort_key(self):
self.assertRaises(ValueError,
cs.volumes.list, sort_key='invalid', sort_dir='asc')
def test_list_volumes_with_invalid_sort_dir(self):
self.assertRaises(ValueError,
cs.volumes.list, sort_key='id', sort_dir='invalid')
def test_delete_volume(self): def test_delete_volume(self):
v = cs.volumes.list()[0] v = cs.volumes.list()[0]
v.delete() v.delete()

View File

@@ -156,6 +156,27 @@ def _extract_metadata(args):
help='Filters results by a metadata key and value pair. ' help='Filters results by a metadata key and value pair. '
'OPTIONAL: Default=None.', 'OPTIONAL: Default=None.',
default=None) default=None)
@utils.arg('--marker',
metavar='<marker>',
default=None,
help='Begin returning volumes that appear later in the volume '
'list than that represented by this volume id. '
'OPTIONAL: Default=None.')
@utils.arg('--limit',
metavar='<limit>',
default=None,
help='Maximum number of volumes to return. OPTIONAL: Default=None.')
@utils.arg('--sort_key',
metavar='<sort_key>',
default=None,
help='Key to be sorted, should be (`id`, `status`, `size`, '
'`availability_zone`, `name`, `bootable`, `created_at`). '
'OPTIONAL: Default=None.')
@utils.arg('--sort_dir',
metavar='<sort_dir>',
default=None,
help='Sort direction, should be `desc` or `asc`. '
'OPTIONAL: Default=None.')
@utils.service_type('volumev2') @utils.service_type('volumev2')
def do_list(cs, args): def do_list(cs, args):
"""Lists all volumes.""" """Lists all volumes."""
@@ -170,7 +191,9 @@ def do_list(cs, args):
'status': args.status, 'status': args.status,
'metadata': _extract_metadata(args) if args.metadata else None, 'metadata': _extract_metadata(args) if args.metadata else None,
} }
volumes = cs.volumes.list(search_opts=search_opts) volumes = cs.volumes.list(search_opts=search_opts, marker=args.marker,
limit=args.limit, sort_key=args.sort_key,
sort_dir=args.sort_dir)
_translate_volume_keys(volumes) _translate_volume_keys(volumes)
# Create a list of servers to which the volume is attached # Create a list of servers to which the volume is attached

View File

@@ -24,6 +24,11 @@ except ImportError:
from cinderclient import base from cinderclient import base
SORT_DIR_VALUES = ('asc', 'desc')
SORT_KEY_VALUES = ('id', 'status', 'size', 'availability_zone', 'name',
'bootable', 'created_at')
class Volume(base.Resource): class Volume(base.Resource):
"""A volume is an extra block level storage to the OpenStack instances.""" """A volume is an extra block level storage to the OpenStack instances."""
def __repr__(self): def __repr__(self):
@@ -208,9 +213,17 @@ class VolumeManager(base.ManagerWithFind):
""" """
return self._get("/volumes/%s" % volume_id, "volume") return self._get("/volumes/%s" % volume_id, "volume")
def list(self, detailed=True, search_opts=None): def list(self, detailed=True, search_opts=None, marker=None, limit=None,
sort_key=None, sort_dir=None):
"""Lists all volumes. """Lists all volumes.
:param detailed: Whether to return detailed volume info.
:param search_opts: Search options to filter out volumes.
:param marker: Begin returning volumes that appear later in the volume
list than that represented by this volume id.
:param limit: Maximum number of volumes to return.
:param sort_key: Key to be sorted.
:param sort_dir: Sort direction, should be 'desc' or 'asc'.
:rtype: list of :class:`Volume` :rtype: list of :class:`Volume`
""" """
if search_opts is None: if search_opts is None:
@@ -222,7 +235,33 @@ class VolumeManager(base.ManagerWithFind):
if val: if val:
qparams[opt] = val qparams[opt] = val
query_string = "?%s" % urlencode(qparams) if qparams else "" if marker:
qparams['marker'] = marker
if limit:
qparams['limit'] = limit
if sort_key is not None:
if sort_key in SORT_KEY_VALUES:
qparams['sort_key'] = sort_key
else:
raise ValueError('sort_key must be one of the following: %s.'
% ', '.join(SORT_KEY_VALUES))
if sort_dir is not None:
if sort_dir in SORT_DIR_VALUES:
qparams['sort_dir'] = sort_dir
else:
raise ValueError('sort_dir must be one of the following: %s.'
% ', '.join(SORT_DIR_VALUES))
# Transform the dict to a sequence of two-element tuples in fixed
# order, then the encoded string will be consistent in Python 2&3.
if qparams:
new_qparams = sorted(qparams.items(), key=lambda x: x[0])
query_string = "?%s" % urlencode(new_qparams)
else:
query_string = ""
detail = "" detail = ""
if detailed: if detailed: