diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-08-21 11:47:55 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-08-21 11:47:55 +0000 |
commit | 09422b600ed797b9dcc58247d0f8a695843c0096 (patch) | |
tree | b61126c8db53a6fa8779a8d33c6882845455ea49 | |
parent | b8e6ad0108a7e26f424edf79143ccd97db8cf478 (diff) | |
parent | f7e9ece40ba33c70c8f73fb4bfb294a8bf806b61 (diff) | |
download | python-cinderclient-09422b600ed797b9dcc58247d0f8a695843c0096.tar.gz |
Merge "Support pagination for volume list"
-rw-r--r-- | cinderclient/tests/v2/test_shell.py | 18 | ||||
-rw-r--r-- | cinderclient/tests/v2/test_volumes.py | 16 | ||||
-rw-r--r-- | cinderclient/v2/shell.py | 25 | ||||
-rw-r--r-- | cinderclient/v2/volumes.py | 43 |
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: |