diff --git a/cinderclient/tests/unit/v2/test_shell.py b/cinderclient/tests/unit/v2/test_shell.py index b5b8ba537..c47bab37c 100644 --- a/cinderclient/tests/unit/v2/test_shell.py +++ b/cinderclient/tests/unit/v2/test_shell.py @@ -434,6 +434,17 @@ class ShellTest(utils.TestCase): self.run_command('backup-restore 1234') self.assert_called('POST', '/backups/1234/restore') + def test_restore_with_name(self): + self.run_command('backup-restore 1234 --name restore_vol') + expected = {'restore': {'volume_id': None, 'name': 'restore_vol'}} + self.assert_called('POST', '/backups/1234/restore', + body=expected) + + def test_restore_with_name_error(self): + self.assertRaises(exceptions.CommandError, self.run_command, + 'backup-restore 1234 --volume fake_vol --name ' + 'restore_vol') + @mock.patch('cinderclient.utils.print_dict') @mock.patch('cinderclient.utils.find_volume') def test_do_backup_restore(self, @@ -441,9 +452,11 @@ class ShellTest(utils.TestCase): mock_print_dict): backup_id = '1234' volume_id = '5678' + name = None input = { 'backup': backup_id, - 'volume': volume_id + 'volume': volume_id, + 'name': None } args = self._make_args(input) @@ -455,7 +468,8 @@ class ShellTest(utils.TestCase): test_shell.do_backup_restore(self.cs, args) mocked_restore.assert_called_once_with( input['backup'], - volume_id) + volume_id, + name) self.assertTrue(mock_print_dict.called) def test_record_export(self): diff --git a/cinderclient/tests/unit/v2/test_volume_backups.py b/cinderclient/tests/unit/v2/test_volume_backups.py index d493080a8..700c44086 100644 --- a/cinderclient/tests/unit/v2/test_volume_backups.py +++ b/cinderclient/tests/unit/v2/test_volume_backups.py @@ -126,6 +126,16 @@ class VolumeBackupsTest(utils.TestCase): volume_backups_restore.VolumeBackupsRestore) self._assert_request_id(info) + def test_restore_with_name(self): + backup_id = '76a17945-3c6f-435c-975b-b5685db10b62' + name = 'restore_vol' + info = cs.restores.restore(backup_id, name=name) + expected_body = {'restore': {'volume_id': None, 'name': name}} + cs.assert_called('POST', '/backups/%s/restore' % backup_id, + body=expected_body) + self.assertIsInstance(info, + volume_backups_restore.VolumeBackupsRestore) + def test_reset_state(self): b = cs.backups.list()[0] api = '/backups/76a17945-3c6f-435c-975b-b5685db10b62/action' diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py index ebd71e63d..2f8900569 100644 --- a/cinderclient/v3/shell.py +++ b/cinderclient/v3/shell.py @@ -1507,7 +1507,14 @@ def do_backup_delete(cs, args): help=argparse.SUPPRESS) @utils.arg('--volume', metavar='', default=None, - help='Name or ID of volume to which to restore. ' + help='Name or ID of existing volume to which to restore. ' + 'This is mutually exclusive with --name and takes priority. ' + 'Default=None.') +@utils.arg('--name', metavar='', + default=None, + help='Use the name for new volume creation to restore. ' + 'This is mutually exclusive with --volume (or the deprecated ' + '--volume-id) and --volume (or --volume-id) takes priority. ' 'Default=None.') @utils.service_type('volumev3') def do_backup_restore(cs, args): @@ -1515,10 +1522,15 @@ def do_backup_restore(cs, args): vol = args.volume or args.volume_id if vol: volume_id = utils.find_volume(cs, vol).id + if args.name: + args.name = None + print('Mutually exclusive options are specified simultaneously: ' + '"--volume (or the deprecated --volume-id) and --name". ' + 'The --volume (or --volume-id) option takes priority.') else: volume_id = None - restore = cs.restores.restore(args.backup, volume_id) + restore = cs.restores.restore(args.backup, volume_id, args.name) info = {"backup_id": args.backup} info.update(restore._info) diff --git a/cinderclient/v3/volume_backups_restore.py b/cinderclient/v3/volume_backups_restore.py index 911356d03..8a35ed162 100644 --- a/cinderclient/v3/volume_backups_restore.py +++ b/cinderclient/v3/volume_backups_restore.py @@ -31,13 +31,14 @@ class VolumeBackupRestoreManager(base.Manager): """Manage :class:`VolumeBackupsRestore` resources.""" resource_class = VolumeBackupsRestore - def restore(self, backup_id, volume_id=None): + def restore(self, backup_id, volume_id=None, name=None): """Restore a backup to a volume. :param backup_id: The ID of the backup to restore. :param volume_id: The ID of the volume to restore the backup to. + :param name : The name for new volume creation to restore. :rtype: :class:`Restore` """ - body = {'restore': {'volume_id': volume_id}} + body = {'restore': {'volume_id': volume_id, 'name': name}} return self._create("/backups/%s/restore" % backup_id, body, "restore")