diff --git a/doc/source/command-objects/volume.rst b/doc/source/command-objects/volume.rst index 8efa8a669..141c980ab 100644 --- a/doc/source/command-objects/volume.rst +++ b/doc/source/command-objects/volume.rst @@ -121,6 +121,8 @@ List volumes [--status ] [--all-projects] [--long] + [--limit ] + [--marker ] .. option:: --project @@ -166,6 +168,16 @@ List volumes List additional fields in output +.. option:: --limit + + Maximum number of volumes to display + +.. option:: --marker + + The last volume ID of the previous page + + *Volume version 2 only* + volume set ---------- diff --git a/openstackclient/tests/unit/volume/v1/test_volume.py b/openstackclient/tests/unit/volume/v1/test_volume.py index f90566fd5..381928499 100644 --- a/openstackclient/tests/unit/volume/v1/test_volume.py +++ b/openstackclient/tests/unit/volume/v1/test_volume.py @@ -13,6 +13,7 @@ # under the License. # +import argparse import copy import mock @@ -437,6 +438,7 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', None), ('status', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -454,6 +456,7 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', volume_fakes.volume_name), ('status', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -470,6 +473,7 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', None), ('status', volume_fakes.volume_status), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -486,6 +490,7 @@ class TestVolumeList(TestVolume): ('all_projects', True), ('name', None), ('status', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -502,6 +507,7 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', None), ('status', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -532,6 +538,41 @@ class TestVolumeList(TestVolume): ), ) self.assertEqual(datalist, tuple(data)) + def test_volume_list_with_limit(self): + arglist = [ + '--limit', '2', + ] + verifylist = [ + ('long', False), + ('all_projects', False), + ('name', None), + ('status', None), + ('limit', 2), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.volumes_mock.list.assert_called_once_with( + limit=2, + search_opts={ + 'status': None, + 'display_name': None, + 'all_tenants': False, } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) + + def test_volume_list_negative_limit(self): + arglist = [ + "--limit", "-2", + ] + verifylist = [ + ("limit", -2), + ] + self.assertRaises(argparse.ArgumentTypeError, self.check_parser, + self.cmd, arglist, verifylist) + class TestVolumeSet(TestVolume): diff --git a/openstackclient/tests/unit/volume/v2/test_volume.py b/openstackclient/tests/unit/volume/v2/test_volume.py index 66f8f74d4..de059b1b5 100644 --- a/openstackclient/tests/unit/volume/v2/test_volume.py +++ b/openstackclient/tests/unit/volume/v2/test_volume.py @@ -12,6 +12,7 @@ # under the License. # +import argparse import mock from mock import call @@ -553,6 +554,8 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', None), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -581,6 +584,8 @@ class TestVolumeList(TestVolume): ('long', False), ('all_projects', False), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -611,6 +616,8 @@ class TestVolumeList(TestVolume): ('long', False), ('all_projects', False), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -639,6 +646,8 @@ class TestVolumeList(TestVolume): ('long', False), ('all_projects', False), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -668,6 +677,8 @@ class TestVolumeList(TestVolume): ('long', False), ('all_projects', False), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -696,6 +707,8 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', self.mock_volume.name), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -724,6 +737,8 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', None), ('status', self.mock_volume.status), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -752,6 +767,8 @@ class TestVolumeList(TestVolume): ('all_projects', True), ('name', None), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -780,6 +797,8 @@ class TestVolumeList(TestVolume): ('all_projects', False), ('name', None), ('status', None), + ('marker', None), + ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -813,6 +832,58 @@ class TestVolumeList(TestVolume): ), ) self.assertEqual(datalist, tuple(data)) + def test_volume_list_with_marker_and_limit(self): + arglist = [ + "--marker", self.mock_volume.id, + "--limit", "2", + ] + verifylist = [ + ('long', False), + ('all_projects', False), + ('name', None), + ('status', None), + ('marker', self.mock_volume.id), + ('limit', 2), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.assertEqual(self.columns, columns) + + server = self.mock_volume.attachments[0]['server_id'] + device = self.mock_volume.attachments[0]['device'] + msg = 'Attached to %s on %s ' % (server, device) + datalist = (( + self.mock_volume.id, + self.mock_volume.name, + self.mock_volume.status, + self.mock_volume.size, + msg, + ), ) + + self.volumes_mock.list.assert_called_once_with( + marker=self.mock_volume.id, + limit=2, + search_opts={ + 'status': None, + 'project_id': None, + 'user_id': None, + 'display_name': None, + 'all_tenants': False, } + ) + self.assertEqual(datalist, tuple(data)) + + def test_volume_list_negative_limit(self): + arglist = [ + "--limit", "-2", + ] + verifylist = [ + ("limit", -2), + ] + self.assertRaises(argparse.ArgumentTypeError, self.check_parser, + self.cmd, arglist, verifylist) + class TestVolumeSet(TestVolume): diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index 820673bb9..6db6a5f24 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -220,6 +220,13 @@ class ListVolume(command.Lister): default=False, help=_('List additional fields in output'), ) + parser.add_argument( + '--limit', + type=int, + action=parseractions.NonNegativeAction, + metavar='', + help=_('Maximum number of volumes to display'), + ) return parser def take_action(self, parsed_args): @@ -295,7 +302,10 @@ class ListVolume(command.Lister): 'status': parsed_args.status, } - data = volume_client.volumes.list(search_opts=search_opts) + data = volume_client.volumes.list( + search_opts=search_opts, + limit=parsed_args.limit, + ) return (column_headers, (utils.get_item_properties( diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index bd201e004..28946a5f7 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -246,6 +246,18 @@ class ListVolume(command.Lister): default=False, help=_('List additional fields in output'), ) + parser.add_argument( + '--marker', + metavar='', + help=_('The last volume ID of the previous page'), + ) + parser.add_argument( + '--limit', + type=int, + action=parseractions.NonNegativeAction, + metavar='', + help=_('Maximum number of volumes to display'), + ) return parser def take_action(self, parsed_args): @@ -328,7 +340,11 @@ class ListVolume(command.Lister): 'status': parsed_args.status, } - data = volume_client.volumes.list(search_opts=search_opts) + data = volume_client.volumes.list( + search_opts=search_opts, + marker=parsed_args.marker, + limit=parsed_args.limit, + ) return (column_headers, (utils.get_item_properties( diff --git a/releasenotes/notes/bug-1612484-e8605ad8966a455e.yaml b/releasenotes/notes/bug-1612484-e8605ad8966a455e.yaml new file mode 100644 index 000000000..1020585e2 --- /dev/null +++ b/releasenotes/notes/bug-1612484-e8605ad8966a455e.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add ``--limit`` option to ``volume list`` command in volume v1, + add ``--limit`` and ``--marker`` options to ``volume list`` + command in volume v2. + [Bug `1612484 `_]