diff --git a/doc/source/command-objects/volume-snapshot.rst b/doc/source/command-objects/volume-snapshot.rst index b84601f464..2d9406b630 100644 --- a/doc/source/command-objects/volume-snapshot.rst +++ b/doc/source/command-objects/volume-snapshot.rst @@ -71,6 +71,9 @@ List volume snapshots [--long] [--limit ] [--marker ] + [--name ] + [--status ] + [--volume ] .. option:: --all-projects @@ -80,6 +83,19 @@ List volume snapshots List additional fields in output +.. option:: --status + + Filters results by a status. + ('available', 'error', 'creating', 'deleting' or 'error-deleting') + +.. option:: --name + + Filters results by a name. + +.. option:: --volume + + Filters results by a volume (name or ID). + .. option:: --limit Maximum number of snapshots to display diff --git a/openstackclient/tests/unit/volume/v1/test_snapshot.py b/openstackclient/tests/unit/volume/v1/test_snapshot.py index 8e30d6a9d5..fd878f4531 100644 --- a/openstackclient/tests/unit/volume/v1/test_snapshot.py +++ b/openstackclient/tests/unit/volume/v1/test_snapshot.py @@ -268,6 +268,7 @@ class TestSnapshotList(TestSnapshot): super(TestSnapshotList, self).setUp() self.volumes_mock.list.return_value = [self.volume] + self.volumes_mock.get.return_value = self.volume self.snapshots_mock.list.return_value = self.snapshots # Get the command to test self.cmd = volume_snapshot.ListVolumeSnapshot(self.app, None) @@ -283,7 +284,13 @@ class TestSnapshotList(TestSnapshot): columns, data = self.cmd.take_action(parsed_args) self.snapshots_mock.list.assert_called_once_with( - search_opts={'all_tenants': False}) + search_opts={ + 'all_tenants': False, + 'display_name': None, + 'status': None, + 'volume_id': None + } + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) @@ -300,11 +307,88 @@ class TestSnapshotList(TestSnapshot): columns, data = self.cmd.take_action(parsed_args) self.snapshots_mock.list.assert_called_once_with( - search_opts={'all_tenants': False} + search_opts={ + 'all_tenants': False, + 'display_name': None, + 'status': None, + 'volume_id': None + } ) self.assertEqual(self.columns_long, columns) self.assertEqual(self.data_long, list(data)) + def test_snapshot_list_name_option(self): + arglist = [ + '--name', self.snapshots[0].display_name, + ] + verifylist = [ + ('all_projects', False), + ('long', False), + ('name', self.snapshots[0].display_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.snapshots_mock.list.assert_called_once_with( + search_opts={ + 'all_tenants': False, + 'display_name': self.snapshots[0].display_name, + 'status': None, + 'volume_id': None + } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_snapshot_list_status_option(self): + arglist = [ + '--status', self.snapshots[0].status, + ] + verifylist = [ + ('all_projects', False), + ('long', False), + ('status', self.snapshots[0].status), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.snapshots_mock.list.assert_called_once_with( + search_opts={ + 'all_tenants': False, + 'display_name': None, + 'status': self.snapshots[0].status, + 'volume_id': None + } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_snapshot_list_volumeid_option(self): + arglist = [ + '--volume', self.volume.id, + ] + verifylist = [ + ('all_projects', False), + ('long', False), + ('volume', self.volume.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.snapshots_mock.list.assert_called_once_with( + search_opts={ + 'all_tenants': False, + 'display_name': None, + 'status': None, + 'volume_id': self.volume.id + } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + def test_snapshot_list_all_projects(self): arglist = [ '--all-projects', @@ -318,7 +402,13 @@ class TestSnapshotList(TestSnapshot): columns, data = self.cmd.take_action(parsed_args) self.snapshots_mock.list.assert_called_once_with( - search_opts={'all_tenants': True}) + search_opts={ + 'all_tenants': True, + 'display_name': None, + 'status': None, + 'volume_id': None + } + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) diff --git a/openstackclient/tests/unit/volume/v2/test_snapshot.py b/openstackclient/tests/unit/volume/v2/test_snapshot.py index b67dd6ebf5..bb238135fc 100644 --- a/openstackclient/tests/unit/volume/v2/test_snapshot.py +++ b/openstackclient/tests/unit/volume/v2/test_snapshot.py @@ -275,6 +275,7 @@ class TestSnapshotList(TestSnapshot): super(TestSnapshotList, self).setUp() self.volumes_mock.list.return_value = [self.volume] + self.volumes_mock.get.return_value = self.volume self.snapshots_mock.list.return_value = self.snapshots # Get the command to test self.cmd = volume_snapshot.ListVolumeSnapshot(self.app, None) @@ -283,14 +284,21 @@ class TestSnapshotList(TestSnapshot): arglist = [] verifylist = [ ('all_projects', False), - ("long", False) + ('long', False) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) self.snapshots_mock.list.assert_called_once_with( - limit=None, marker=None, search_opts={'all_tenants': False}) + limit=None, marker=None, + search_opts={ + 'all_tenants': False, + 'name': None, + 'status': None, + 'volume_id': None + } + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) @@ -313,7 +321,12 @@ class TestSnapshotList(TestSnapshot): self.snapshots_mock.list.assert_called_once_with( limit=2, marker=self.snapshots[0].id, - search_opts={'all_tenants': False} + search_opts={ + 'all_tenants': False, + 'name': None, + 'status': None, + 'volume_id': None + } ) self.assertEqual(self.columns_long, columns) self.assertEqual(self.data_long, list(data)) @@ -331,7 +344,89 @@ class TestSnapshotList(TestSnapshot): columns, data = self.cmd.take_action(parsed_args) self.snapshots_mock.list.assert_called_once_with( - limit=None, marker=None, search_opts={'all_tenants': True}) + limit=None, marker=None, + search_opts={ + 'all_tenants': True, + 'name': None, + 'status': None, + 'volume_id': None + } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_snapshot_list_name_option(self): + arglist = [ + '--name', self.snapshots[0].name, + ] + verifylist = [ + ('all_projects', False), + ('long', False), + ('name', self.snapshots[0].name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.snapshots_mock.list.assert_called_once_with( + limit=None, marker=None, + search_opts={ + 'all_tenants': False, + 'name': self.snapshots[0].name, + 'status': None, + 'volume_id': None + } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_snapshot_list_status_option(self): + arglist = [ + '--status', self.snapshots[0].status, + ] + verifylist = [ + ('all_projects', False), + ('long', False), + ('status', self.snapshots[0].status), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.snapshots_mock.list.assert_called_once_with( + limit=None, marker=None, + search_opts={ + 'all_tenants': False, + 'name': None, + 'status': self.snapshots[0].status, + 'volume_id': None + } + ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_snapshot_list_volumeid_option(self): + arglist = [ + '--volume', self.volume.id, + ] + verifylist = [ + ('all_projects', False), + ('long', False), + ('volume', self.volume.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.snapshots_mock.list.assert_called_once_with( + limit=None, marker=None, + search_opts={ + 'all_tenants': False, + 'name': None, + 'status': None, + 'volume_id': self.volume.id + } + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) diff --git a/openstackclient/volume/v1/volume_snapshot.py b/openstackclient/volume/v1/volume_snapshot.py index c2ecf75b5b..77c93ad4fb 100644 --- a/openstackclient/volume/v1/volume_snapshot.py +++ b/openstackclient/volume/v1/volume_snapshot.py @@ -135,9 +135,31 @@ class ListVolumeSnapshot(command.Lister): default=False, help=_('List additional fields in output'), ) + parser.add_argument( + '--name', + metavar='', + default=None, + help=_('Filters results by a name.') + ) + parser.add_argument( + '--status', + metavar='', + choices=['available', 'error', 'creating', 'deleting', + 'error-deleting'], + help=_("Filters results by a status. " + "('available', 'error', 'creating', 'deleting'" + " or 'error-deleting')") + ) + parser.add_argument( + '--volume', + metavar='', + default=None, + help=_('Filters results by a volume (name or ID).') + ) return parser def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume def _format_volume_id(volume_id): """Return a volume name if available @@ -169,17 +191,25 @@ class ListVolumeSnapshot(command.Lister): # Cache the volume list volume_cache = {} try: - for s in self.app.client_manager.volume.volumes.list(): + for s in volume_client.volumes.list(): volume_cache[s.id] = s except Exception: # Just forget it if there's any trouble pass + volume_id = None + if parsed_args.volume: + volume_id = utils.find_resource( + volume_client.volumes, parsed_args.volume).id + search_opts = { 'all_tenants': parsed_args.all_projects, + 'display_name': parsed_args.name, + 'status': parsed_args.status, + 'volume_id': volume_id, } - data = self.app.client_manager.volume.volume_snapshots.list( + data = volume_client.volume_snapshots.list( search_opts=search_opts) return (column_headers, (utils.get_item_properties( diff --git a/openstackclient/volume/v2/volume_snapshot.py b/openstackclient/volume/v2/volume_snapshot.py index 43f30326ed..86af6d8c43 100644 --- a/openstackclient/volume/v2/volume_snapshot.py +++ b/openstackclient/volume/v2/volume_snapshot.py @@ -151,9 +151,31 @@ class ListVolumeSnapshot(command.Lister): metavar='', help=_('Maximum number of snapshots to display'), ) + parser.add_argument( + '--name', + metavar='', + default=None, + help=_('Filters results by a name.') + ) + parser.add_argument( + '--status', + metavar='', + choices=['available', 'error', 'creating', 'deleting', + 'error-deleting'], + help=_("Filters results by a status. " + "('available', 'error', 'creating', 'deleting'" + " or 'error-deleting')") + ) + parser.add_argument( + '--volume', + metavar='', + default=None, + help=_('Filters results by a volume (name or ID).') + ) return parser def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume def _format_volume_id(volume_id): """Return a volume name if available @@ -180,17 +202,25 @@ class ListVolumeSnapshot(command.Lister): # Cache the volume list volume_cache = {} try: - for s in self.app.client_manager.volume.volumes.list(): + for s in volume_client.volumes.list(): volume_cache[s.id] = s except Exception: # Just forget it if there's any trouble pass + volume_id = None + if parsed_args.volume: + volume_id = utils.find_resource( + volume_client.volumes, parsed_args.volume).id + search_opts = { 'all_tenants': parsed_args.all_projects, + 'name': parsed_args.name, + 'status': parsed_args.status, + 'volume_id': volume_id, } - data = self.app.client_manager.volume.volume_snapshots.list( + data = volume_client.volume_snapshots.list( search_opts=search_opts, marker=parsed_args.marker, limit=parsed_args.limit, diff --git a/releasenotes/notes/bug-1645252-219bfd50c8f04846.yaml b/releasenotes/notes/bug-1645252-219bfd50c8f04846.yaml new file mode 100644 index 0000000000..12b1e42deb --- /dev/null +++ b/releasenotes/notes/bug-1645252-219bfd50c8f04846.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add ``--name``, ``--status`` and ``--volume`` options + to ``volume snapshot list`` command + [Bug `1645252 `_]