diff --git a/cinderclient/api_versions.py b/cinderclient/api_versions.py index bf8cba222..eac6abbc5 100644 --- a/cinderclient/api_versions.py +++ b/cinderclient/api_versions.py @@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__) # key is a deprecated version and value is an alternative version. DEPRECATED_VERSIONS = {"1": "2"} DEPRECATED_VERSION = "2.0" -MAX_VERSION = "3.44" +MAX_VERSION = "3.45" MIN_VERSION = "3.0" _SUBSTITUTIONS = {} diff --git a/cinderclient/base.py b/cinderclient/base.py index 83f873189..5f6fb2532 100644 --- a/cinderclient/base.py +++ b/cinderclient/base.py @@ -105,7 +105,10 @@ class Manager(common_base.HookableMixin): if margin <= len(items_new): # If the limit is reached, return the items. items = items + items_new[:margin] - return common_base.ListWithMeta(items, resp) + if "count" in body: + return common_base.ListWithMeta(items, resp), body['count'] + else: + return common_base.ListWithMeta(items, resp) else: items = items + items_new else: @@ -128,7 +131,10 @@ class Manager(common_base.HookableMixin): # till there is no more items. items = self._list(next, response_key, obj_class, None, limit, items) - return common_base.ListWithMeta(items, resp) + if "count" in body: + return common_base.ListWithMeta(items, resp), body['count'] + else: + return common_base.ListWithMeta(items, resp) def _build_list_url(self, resource_type, detailed=True, search_opts=None, marker=None, limit=None, sort_key=None, sort_dir=None, diff --git a/cinderclient/tests/unit/v2/fakes.py b/cinderclient/tests/unit/v2/fakes.py index 3e40b29bb..ae21eebe0 100644 --- a/cinderclient/tests/unit/v2/fakes.py +++ b/cinderclient/tests/unit/v2/fakes.py @@ -389,9 +389,12 @@ class FakeHTTPClient(base_client.HTTPClient): # def get_snapshots_detail(self, **kw): + if kw.get('with_count', False): + return (200, {}, {'snapshots': [ + _stub_snapshot(), + ], 'count': 1}) return (200, {}, {'snapshots': [ - _stub_snapshot(), - ]}) + _stub_snapshot()]}) def get_snapshots_1234(self, **kw): return (200, {}, {'snapshot': _stub_snapshot(id='1234')}) @@ -464,6 +467,10 @@ class FakeHTTPClient(base_client.HTTPClient): ]}) def get_volumes_detail(self, **kw): + if kw.get('with_count', False): + return (200, {}, {"volumes": [ + _stub_volume(id=kw.get('id', 1234)) + ], "count": 1}) return (200, {}, {"volumes": [ _stub_volume(id=kw.get('id', 1234)) ]}) @@ -885,6 +892,12 @@ class FakeHTTPClient(base_client.HTTPClient): tenant_id = '0fa851f6668144cf9cd8c8419c1646c1' backup1 = '76a17945-3c6f-435c-975b-b5685db10b62' backup2 = 'd09534c6-08b8-4441-9e87-8976f3a8f699' + if kw.get('with_count', False): + return (200, {}, + {'backups': [ + _stub_backup_full(backup1, base_uri, tenant_id), + _stub_backup_full(backup2, base_uri, tenant_id)], + 'count': 2}) return (200, {}, {'backups': [ _stub_backup_full(backup1, base_uri, tenant_id), diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py index 34cf47037..0161987b4 100644 --- a/cinderclient/tests/unit/v3/test_shell.py +++ b/cinderclient/tests/unit/v3/test_shell.py @@ -231,6 +231,10 @@ class ShellTest(utils.TestCase): # NOTE(jdg): we default to detail currently self.assert_called('GET', '/volumes/detail') + def test_list_with_with_count(self): + self.run_command('--os-volume-api-version 3.45 list --with-count') + self.assert_called('GET', '/volumes/detail?with_count=True') + def test_summary(self): self.run_command('--os-volume-api-version 3.12 summary') self.assert_called('GET', '/volumes/summary') @@ -430,6 +434,11 @@ class ShellTest(utils.TestCase): expected = {'backup': {'name': 'new_name'}} self.assert_called('PUT', '/backups/1234', body=expected) + def test_backup_list_with_with_count(self): + self.run_command( + '--os-volume-api-version 3.45 backup-list --with-count') + self.assert_called('GET', '/backups/detail?with_count=True') + def test_backup_update_with_description(self): self.run_command('--os-volume-api-version 3.9 ' 'backup-update 1234 --description=new-description') @@ -742,6 +751,11 @@ class ShellTest(utils.TestCase): expected = {'os-reset_status': expected} self.assert_called('POST', '/volumes/1234/action', body=expected) + def test_snapshot_list_with_with_count(self): + self.run_command( + '--os-volume-api-version 3.45 snapshot-list --with-count') + self.assert_called('GET', '/snapshots/detail?with_count=True') + def test_snapshot_list_with_metadata(self): self.run_command('--os-volume-api-version 3.22 ' 'snapshot-list --metadata key1=val1') diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py index db23d83c0..b5c0ed64a 100644 --- a/cinderclient/v3/shell.py +++ b/cinderclient/v3/shell.py @@ -107,10 +107,21 @@ def do_list_filters(cs, args): help="Filter key and value pairs. Please use 'cinder list-filters' " "to check enabled filters from server. Use 'key~=value' for " "inexact filtering if the key supports. Default=None.") +@utils.arg('--with-count', + type=bool, + default=False, + const=True, + nargs='?', + start_version='3.45', + metavar='', + help="Show total number of backup entities. This is useful when " + "pagination is applied in the request.") def do_backup_list(cs, args): """Lists all backups.""" # pylint: disable=function-redefined + show_count = True if hasattr( + args, 'with_count') and args.with_count else False search_opts = { 'all_tenants': args.all_tenants, 'name': args.name, @@ -122,10 +133,18 @@ def do_backup_list(cs, args): if hasattr(args, 'filters') and args.filters is not None: search_opts.update(shell_utils.extract_filters(args.filters)) - backups = cs.backups.list(search_opts=search_opts, - marker=args.marker, - limit=args.limit, - sort=args.sort) + total_count = 0 + if show_count: + search_opts['with_count'] = args.with_count + backups, total_count = cs.backups.list(search_opts=search_opts, + marker=args.marker, + limit=args.limit, + sort=args.sort) + else: + backups = cs.backups.list(search_opts=search_opts, + marker=args.marker, + limit=args.limit, + sort=args.sort) shell_utils.translate_volume_snapshot_keys(backups) columns = ['ID', 'Volume ID', 'Status', 'Name', 'Size', 'Object Count', 'Container'] @@ -134,6 +153,8 @@ def do_backup_list(cs, args): else: sortby_index = 0 utils.print_list(backups, columns, sortby_index=sortby_index) + if show_count: + print("Backup in total: %s" % total_count) @utils.arg('--detail', @@ -282,13 +303,23 @@ RESET_STATE_RESOURCES = {'volume': utils.find_volume, help="Filter key and value pairs. Please use 'cinder list-filters' " "to check enabled filters from server. Use 'key~=value' " "for inexact filtering if the key supports. Default=None.") +@utils.arg('--with-count', + type=bool, + default=False, + const=True, + nargs='?', + start_version='3.45', + metavar='', + help="Show total number of volume entities. This is useful when " + "pagination is applied in the request.") def do_list(cs, args): """Lists all volumes.""" # pylint: disable=function-redefined # NOTE(thingee): Backwards-compatibility with v1 args if args.display_name is not None: args.name = args.display_name - + show_count = True if hasattr( + args, 'with_count') and args.with_count else False all_tenants = 1 if args.tenant else \ int(os.environ.get("ALL_TENANTS", args.all_tenants)) search_opts = { @@ -323,9 +354,17 @@ def do_list(cs, args): 'The --sort_key and --sort_dir arguments are deprecated and are ' 'not supported with --sort.') - volumes = cs.volumes.list(search_opts=search_opts, marker=args.marker, - limit=args.limit, sort_key=args.sort_key, - sort_dir=args.sort_dir, sort=args.sort) + total_count = 0 + if show_count: + search_opts['with_count'] = args.with_count + volumes, total_count = cs.volumes.list( + search_opts=search_opts, marker=args.marker, + limit=args.limit, sort_key=args.sort_key, + sort_dir=args.sort_dir, sort=args.sort) + else: + volumes = cs.volumes.list(search_opts=search_opts, marker=args.marker, + limit=args.limit, sort_key=args.sort_key, + sort_dir=args.sort_dir, sort=args.sort) shell_utils.translate_volume_keys(volumes) # Create a list of servers to which the volume is attached @@ -353,6 +392,8 @@ def do_list(cs, args): sortby_index = 0 utils.print_list(volumes, key_list, exclude_unavailable=True, sortby_index=sortby_index) + if show_count: + print("Volume in total: %s" % total_count) @utils.arg('entity', metavar='', nargs='+', @@ -1813,9 +1854,20 @@ def do_message_delete(cs, args): help="Filter key and value pairs. Please use 'cinder list-filters' " "to check enabled filters from server. Use 'key~=value' " "for inexact filtering if the key supports. Default=None.") +@utils.arg('--with-count', + type=bool, + default=False, + const=True, + nargs='?', + start_version='3.45', + metavar='', + help="Show total number of snapshot entities. This is useful when " + "pagination is applied in the request.") def do_snapshot_list(cs, args): """Lists all snapshots.""" # pylint: disable=function-redefined + show_count = True if hasattr( + args, 'with_count') and args.with_count else False all_tenants = (1 if args.tenant else int(os.environ.get("ALL_TENANTS", args.all_tenants))) @@ -1842,10 +1894,20 @@ def do_snapshot_list(cs, args): if hasattr(args, 'filters') and args.filters is not None: search_opts.update(shell_utils.extract_filters(args.filters)) - snapshots = cs.volume_snapshots.list(search_opts=search_opts, - marker=args.marker, - limit=args.limit, - sort=args.sort) + total_count = 0 + if show_count: + search_opts['with_count'] = args.with_count + snapshots, total_count = cs.volume_snapshots.list( + search_opts=search_opts, + marker=args.marker, + limit=args.limit, + sort=args.sort) + else: + snapshots = cs.volume_snapshots.list(search_opts=search_opts, + marker=args.marker, + limit=args.limit, + sort=args.sort) + shell_utils.translate_volume_snapshot_keys(snapshots) sortby_index = None if args.sort else 0 if cs.api_version >= api_versions.APIVersion("3.41"): @@ -1857,6 +1919,8 @@ def do_snapshot_list(cs, args): utils.print_list(snapshots, ['ID', 'Volume ID', 'Status', 'Name', 'Size'], sortby_index=sortby_index) + if show_count: + print("Snapshot in total: %s" % total_count) @api_versions.wraps('3.27') diff --git a/releasenotes/notes/list-with-count-78gtf45r66bf8912.yaml b/releasenotes/notes/list-with-count-78gtf45r66bf8912.yaml new file mode 100644 index 000000000..edd964cc2 --- /dev/null +++ b/releasenotes/notes/list-with-count-78gtf45r66bf8912.yaml @@ -0,0 +1,3 @@ +--- +features: + - Added ``with_count`` option in volume, snapshot and backup's list commands since 3.45.