summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-08-21 11:47:55 +0000
committerGerrit Code Review <review@openstack.org>2014-08-21 11:47:55 +0000
commit09422b600ed797b9dcc58247d0f8a695843c0096 (patch)
treeb61126c8db53a6fa8779a8d33c6882845455ea49
parentb8e6ad0108a7e26f424edf79143ccd97db8cf478 (diff)
parentf7e9ece40ba33c70c8f73fb4bfb294a8bf806b61 (diff)
downloadpython-cinderclient-09422b600ed797b9dcc58247d0f8a695843c0096.tar.gz
Merge "Support pagination for volume list"
-rw-r--r--cinderclient/tests/v2/test_shell.py18
-rw-r--r--cinderclient/tests/v2/test_volumes.py16
-rw-r--r--cinderclient/v2/shell.py25
-rw-r--r--cinderclient/v2/volumes.py43
4 files changed, 99 insertions, 3 deletions
diff --git a/cinderclient/tests/v2/test_shell.py b/cinderclient/tests/v2/test_shell.py
index fa0c1d2..a41d0b4 100644
--- a/cinderclient/tests/v2/test_shell.py
+++ b/cinderclient/tests/v2/test_shell.py
@@ -103,6 +103,24 @@ class ShellTest(utils.TestCase):
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
def test_list_availability_zone(self):
self.register_keystone_auth_fixture()
self.run_command('availability-zone-list')
diff --git a/cinderclient/tests/v2/test_volumes.py b/cinderclient/tests/v2/test_volumes.py
index 81bd88d..fa42b87 100644
--- a/cinderclient/tests/v2/test_volumes.py
+++ b/cinderclient/tests/v2/test_volumes.py
@@ -23,6 +23,22 @@ cs = fakes.FakeClient()
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):
v = cs.volumes.list()[0]
v.delete()
diff --git a/cinderclient/v2/shell.py b/cinderclient/v2/shell.py
index ec6ee68..471240d 100644
--- a/cinderclient/v2/shell.py
+++ b/cinderclient/v2/shell.py
@@ -156,6 +156,27 @@ def _extract_metadata(args):
help='Filters results by a metadata key and value pair. '
'OPTIONAL: 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')
def do_list(cs, args):
"""Lists all volumes."""
@@ -170,7 +191,9 @@ def do_list(cs, args):
'status': args.status,
'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)
# Create a list of servers to which the volume is attached
diff --git a/cinderclient/v2/volumes.py b/cinderclient/v2/volumes.py
index 83a48c0..9a687d0 100644
--- a/cinderclient/v2/volumes.py
+++ b/cinderclient/v2/volumes.py
@@ -24,6 +24,11 @@ except ImportError:
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):
"""A volume is an extra block level storage to the OpenStack instances."""
def __repr__(self):
@@ -208,9 +213,17 @@ class VolumeManager(base.ManagerWithFind):
"""
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.
+ :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`
"""
if search_opts is None:
@@ -222,7 +235,33 @@ class VolumeManager(base.ManagerWithFind):
if 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 = ""
if detailed: