diff --git a/doc/source/command-objects/volume-backup.rst b/doc/source/command-objects/volume-backup.rst index 3a8f0213df..05b02345ce 100644 --- a/doc/source/command-objects/volume-backup.rst +++ b/doc/source/command-objects/volume-backup.rst @@ -115,6 +115,37 @@ Restore volume backup Volume to restore to (name or ID) +volume backup set +----------------- + +Set volume backup properties + +.. program:: volume backup set +.. code:: bash + + os volume backup set + [--name ] + [--description ] + [--state ] + + +.. option:: --name + + New backup name + +.. option:: --description + + New backup description + +.. option:: --state + + New backup state ("available" or "error") (admin only) + +.. _backup_set-volume-backup: +.. describe:: + + Backup to modify (name or ID) + volume backup show ------------------ diff --git a/openstackclient/tests/unit/volume/v2/test_backup.py b/openstackclient/tests/unit/volume/v2/test_backup.py index 4563387016..306c9eb3e8 100644 --- a/openstackclient/tests/unit/volume/v2/test_backup.py +++ b/openstackclient/tests/unit/volume/v2/test_backup.py @@ -336,6 +336,75 @@ class TestBackupRestore(TestBackup): self.assertIsNone(result) +class TestBackupSet(TestBackup): + + backup = volume_fakes.FakeBackup.create_one_backup() + + def setUp(self): + super(TestBackupSet, self).setUp() + + self.backups_mock.get.return_value = self.backup + + # Get the command object to test + self.cmd = backup.SetVolumeBackup(self.app, None) + + def test_backup_set_name(self): + arglist = [ + '--name', 'new_name', + self.backup.id, + ] + verifylist = [ + ('name', 'new_name'), + ('backup', self.backup.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # In base command class ShowOne in cliff, abstract method take_action() + # returns nothing + result = self.cmd.take_action(parsed_args) + self.backups_mock.update.assert_called_once_with( + self.backup.id, **{'name': 'new_name'}) + self.assertIsNone(result) + + def test_backup_set_state(self): + arglist = [ + '--state', 'error', + self.backup.id + ] + verifylist = [ + ('state', 'error'), + ('backup', self.backup.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.backups_mock.reset_state.assert_called_once_with( + self.backup.id, 'error') + self.assertIsNone(result) + + def test_backup_set_state_failed(self): + self.backups_mock.reset_state.side_effect = exceptions.CommandError() + arglist = [ + '--state', 'error', + self.backup.id + ] + verifylist = [ + ('state', 'error'), + ('backup', self.backup.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + try: + self.cmd.take_action(parsed_args) + self.fail('CommandError should be raised.') + except exceptions.CommandError as e: + self.assertEqual('One or more of the set operations failed', + str(e)) + self.backups_mock.reset_state.assert_called_with( + self.backup.id, 'error') + + class TestBackupShow(TestBackup): backup = volume_fakes.FakeBackup.create_one_backup() diff --git a/openstackclient/volume/v2/backup.py b/openstackclient/volume/v2/backup.py index 07c1c94f75..4a133d3644 100644 --- a/openstackclient/volume/v2/backup.py +++ b/openstackclient/volume/v2/backup.py @@ -281,6 +281,65 @@ class RestoreBackup(RestoreVolumeBackup): return super(RestoreBackup, self).take_action(parsed_args) +class SetVolumeBackup(command.Command): + """Set volume backup properties""" + + def get_parser(self, prog_name): + parser = super(SetVolumeBackup, self).get_parser(prog_name) + parser.add_argument( + "backup", + metavar="", + help=_("Backup to modify (name or ID)") + ) + parser.add_argument( + '--name', + metavar='', + help=_('New backup name') + ) + parser.add_argument( + '--description', + metavar='', + help=_('New backup description') + ) + parser.add_argument( + '--state', + metavar='', + choices=['available', 'error'], + help=_('New backup state ("available" or "error") (admin only)'), + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + backup = utils.find_resource(volume_client.backups, + parsed_args.backup) + result = 0 + if parsed_args.state: + try: + volume_client.backups.reset_state( + backup.id, parsed_args.state) + except Exception as e: + LOG.error(_("Failed to set backup state: %s"), e) + result += 1 + + kwargs = {} + if parsed_args.name: + kwargs['name'] = parsed_args.name + if parsed_args.description: + kwargs['description'] = parsed_args.description + if kwargs: + try: + volume_client.backups.update(backup.id, **kwargs) + except Exception as e: + LOG.error(_("Failed to update backup name " + "or description: %s"), e) + result += 1 + + if result > 0: + raise exceptions.CommandError(_("One or more of the " + "set operations failed")) + + class ShowVolumeBackup(command.ShowOne): """Display volume backup details""" diff --git a/releasenotes/notes/bug-1613261-290a64080fead6c0.yaml b/releasenotes/notes/bug-1613261-290a64080fead6c0.yaml new file mode 100644 index 0000000000..7d239be35c --- /dev/null +++ b/releasenotes/notes/bug-1613261-290a64080fead6c0.yaml @@ -0,0 +1,4 @@ +--- +features: + - Add ``volume backup set`` commands in volume v2. + [Bug `1613261 `_] diff --git a/setup.cfg b/setup.cfg index 14485d768c..574d67d189 100644 --- a/setup.cfg +++ b/setup.cfg @@ -517,6 +517,7 @@ openstack.volume.v2 = volume_backup_delete = openstackclient.volume.v2.backup:DeleteVolumeBackup volume_backup_list = openstackclient.volume.v2.backup:ListVolumeBackup volume_backup_restore = openstackclient.volume.v2.backup:RestoreVolumeBackup + volume_backup_set = openstackclient.volume.v2.backup:SetVolumeBackup volume_backup_show = openstackclient.volume.v2.backup:ShowVolumeBackup volume_type_create = openstackclient.volume.v2.volume_type:CreateVolumeType