From 0c016c8b9656a113dc980f4cfa260d946464baed Mon Sep 17 00:00:00 2001 From: lisali <xiaoyan.li@intel.com> Date: Tue, 28 Jun 2016 09:58:04 +0800 Subject: [PATCH] Add backup-update Add backup-update command to update name and description of a backup. DocImpact Change-Id: Ie24b2a13f8d1132b65f30e95059479e532fad41a --- cinderclient/tests/unit/v3/fakes.py | 17 +++++++- cinderclient/tests/unit/v3/test_shell.py | 40 +++++++++++++++++++ .../tests/unit/v3/test_volume_backups.py | 31 ++++++++++++++ cinderclient/v3/shell.py | 25 ++++++++++++ cinderclient/v3/volume_backups.py | 16 ++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 cinderclient/tests/unit/v3/test_volume_backups.py diff --git a/cinderclient/tests/unit/v3/fakes.py b/cinderclient/tests/unit/v3/fakes.py index 430f82ff1..50b44d73b 100644 --- a/cinderclient/tests/unit/v3/fakes.py +++ b/cinderclient/tests/unit/v3/fakes.py @@ -21,11 +21,13 @@ from cinderclient.tests.unit.v2 import fakes as fake_v2 class FakeClient(fakes.FakeClient, client.Client): - def __init__(self, *args, **kwargs): + def __init__(self, api_version=None, *args, **kwargs): client.Client.__init__(self, 'username', 'password', 'project_id', 'auth_url', extensions=kwargs.get('extensions')) - self.client = FakeHTTPClient(**kwargs) + self.api_version = api_version + self.client = FakeHTTPClient(api_version=api_version, + **kwargs) def get_volume_api_version_from_endpoint(self): return self.client.get_volume_api_version_from_endpoint() @@ -171,3 +173,14 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient): def put_clusters_disable(self, body): res = self.get_clusters(id=3) return (200, {}, {'cluster': res[2]['clusters'][0]}) + + # + # Backups + # + def put_backups_1234(self, **kw): + backup = fake_v2._stub_backup( + id='1234', + base_uri='http://localhost:8776', + tenant_id='0fa851f6668144cf9cd8c8419c1646c1') + return (200, {}, + {'backups': backup}) diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py index 35e205dd2..f54ed6606 100644 --- a/cinderclient/tests/unit/v3/test_shell.py +++ b/cinderclient/tests/unit/v3/test_shell.py @@ -18,6 +18,7 @@ import mock from requests_mock.contrib import fixture as requests_mock_fixture from cinderclient import client +from cinderclient import exceptions from cinderclient import shell from cinderclient.tests.unit import utils from cinderclient.tests.unit.v3 import fakes @@ -93,3 +94,42 @@ class ShellTest(utils.TestCase): self.assert_called_anytime('GET', '/volumes/1234') self.assert_called_anytime('POST', '/volumes/1234/action', body=expected) + + def test_backup_update(self): + self.run_command('--os-volume-api-version 3.9 ' + 'backup-update --name new_name 1234') + expected = {'backup': {'name': 'new_name'}} + self.assert_called('PUT', '/backups/1234', body=expected) + + def test_backup_update_with_description(self): + self.run_command('--os-volume-api-version 3.9 ' + 'backup-update 1234 --description=new-description') + expected = {'backup': {'description': 'new-description'}} + self.assert_called('PUT', '/backups/1234', body=expected) + + def test_backup_update_all(self): + # rename and change description + self.run_command('--os-volume-api-version 3.9 ' + 'backup-update --name new-name ' + '--description=new-description 1234') + expected = {'backup': { + 'name': 'new-name', + 'description': 'new-description', + }} + self.assert_called('PUT', '/backups/1234', body=expected) + + def test_backup_update_without_arguments(self): + # Call rename with no arguments + self.assertRaises(SystemExit, self.run_command, + '--os-volume-api-version 3.9 backup-update') + + def test_backup_update_bad_request(self): + self.assertRaises(exceptions.ClientException, + self.run_command, + '--os-volume-api-version 3.9 backup-update 1234') + + def test_backup_update_wrong_version(self): + self.assertRaises(exceptions.VersionNotFoundForAPIMethod, + self.run_command, + '--os-volume-api-version 3.8 ' + 'backup-update --name new-name 1234') diff --git a/cinderclient/tests/unit/v3/test_volume_backups.py b/cinderclient/tests/unit/v3/test_volume_backups.py new file mode 100644 index 000000000..3cbbc72f5 --- /dev/null +++ b/cinderclient/tests/unit/v3/test_volume_backups.py @@ -0,0 +1,31 @@ +# Copyright (c) 2016 Intel, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +from cinderclient.tests.unit import utils +from cinderclient.tests.unit.v3 import fakes + +cs = fakes.FakeClient() + + +class VolumesTest(utils.TestCase): + + def test_update(self): + b = cs.backups.get('1234') + backup = b.update(name='new-name') + cs.assert_called( + 'PUT', '/backups/1234', + {'backup': {'name': 'new-name'}}) + self._assert_request_id(backup) diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py index 74d9a3e5b..115906dee 100644 --- a/cinderclient/v3/shell.py +++ b/cinderclient/v3/shell.py @@ -1602,6 +1602,31 @@ def do_backup_reset_state(cs, args): raise exceptions.CommandError(msg) +@utils.arg('backup', metavar='<backup>', + help='Name or ID of backup to rename.') +@utils.arg('--name', nargs='?', metavar='<name>', + help='New name for backup.') +@utils.arg('--description', metavar='<description>', + help='Backup description. Default=None.') +@utils.service_type('volumev3') +@api_versions.wraps('3.9') +def do_backup_update(cs, args): + """Renames a backup.""" + kwargs = {} + + if args.name is not None: + kwargs['name'] = args.name + + if args.description is not None: + kwargs['description'] = args.description + + if not kwargs: + msg = 'Must supply either name or description.' + raise exceptions.ClientException(code=1, message=msg) + + _find_backup(cs, args.backup).update(**kwargs) + + @utils.arg('volume', metavar='<volume>', help='Name or ID of volume to transfer.') @utils.arg('--name', diff --git a/cinderclient/v3/volume_backups.py b/cinderclient/v3/volume_backups.py index 0941fb86b..9a5aa5ca8 100644 --- a/cinderclient/v3/volume_backups.py +++ b/cinderclient/v3/volume_backups.py @@ -33,6 +33,10 @@ class VolumeBackup(base.Resource): def reset_state(self, state): return self.manager.reset_state(self, state) + def update(self, **kwargs): + """Update the name or description for this backup.""" + return self.manager.update(self, **kwargs) + class VolumeBackupManager(base.ManagerWithFind): """Manage :class:`VolumeBackup` resources.""" @@ -126,3 +130,15 @@ class VolumeBackupManager(base.ManagerWithFind): self.run_hooks('modify_body_for_update', body, 'backup-record') resp, body = self.api.client.post("/backups/import_record", body=body) return common_base.DictWithMeta(body['backup'], resp) + + def update(self, backup, **kwargs): + """Update the name or description for a backup. + + :param backup: The :class:`Backup` to update. + """ + if not kwargs: + return + + body = {"backup": kwargs} + + return self._update("/backups/%s" % base.getid(backup), body)