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)