]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Backups: allow name to be specified during restore
authorAbhishek Lekshmanan <abhishek.lekshmanan@gmail.com>
Mon, 8 Jun 2015 11:14:22 +0000 (16:44 +0530)
committerJohn Griffith <john.griffith8@gmail.com>
Fri, 17 Jul 2015 15:28:55 +0000 (15:28 +0000)
This commit adds the ability to specify a `name` attribute during backup
restore. This will create a volume with the specified name during
restore, instead of the default pattern of the form
`restore-backup-<id>`. In case volume id is specified the `name`
attribute is ignored.

DocImpact
APIImpact
Implements: blueprint backup-restore-display-name
Change-Id: I23730834058d88e30be62624ada3b24cdaeaa6f3
Signed-off-by: Abhishek Lekshmanan <abhishek.lekshmanan@gmail.com>
cinder/api/contrib/backups.py
cinder/backup/api.py
cinder/tests/unit/api/contrib/test_backups.py

index d327fdb39bf59c61aa8bb18607db0616138f7a77..56c561cb7d3c55615b7d670c225fc96feaf93f67 100644 (file)
@@ -287,6 +287,7 @@ class BackupsController(wsgi.Controller):
         context = req.environ['cinder.context']
         restore = body['restore']
         volume_id = restore.get('volume_id', None)
+        name = restore.get('name', None)
 
         LOG.info(_LI("Restoring backup %(backup_id)s to volume %(volume_id)s"),
                  {'backup_id': id, 'volume_id': volume_id},
@@ -295,7 +296,8 @@ class BackupsController(wsgi.Controller):
         try:
             new_restore = self.backup_api.restore(context,
                                                   backup_id=id,
-                                                  volume_id=volume_id)
+                                                  volume_id=volume_id,
+                                                  name=name)
         except exception.InvalidInput as error:
             raise exc.HTTPBadRequest(explanation=error.msg)
         except exception.InvalidVolume as error:
index afb0fcc2f29b21a86010ff21725e4191fa4aa2c4..2c83915bd4cc722e523a1dc2eb23e723e98da30d 100644 (file)
@@ -243,7 +243,7 @@ class API(base.Base):
 
         return backup
 
-    def restore(self, context, backup_id, volume_id=None):
+    def restore(self, context, backup_id, volume_id=None, name=None):
         """Make the RPC call to restore a volume backup."""
         check_policy(context, 'restore')
         backup = self.get(context, backup_id)
@@ -259,11 +259,13 @@ class API(base.Base):
         # Create a volume if none specified. If a volume is specified check
         # it is large enough for the backup
         if volume_id is None:
-            name = 'restore_backup_%s' % backup_id
+            if name is None:
+                name = 'restore_backup_%s' % backup_id
+
             description = 'auto-created_from_restore_from_backup'
 
             LOG.info(_LI("Creating volume of %(size)s GB for restore of "
-                         "backup %(backup_id)s"),
+                         "backup %(backup_id)s."),
                      {'size': size, 'backup_id': backup_id},
                      context=context)
             volume = self.volume_api.create(context, size, name, description)
index f410997ecf1e6f03c7e7396b3f6290a23b2f4ca5..560122bb4f206b2bbc8d347d0a1f1d0c4fb87095 100644 (file)
@@ -951,6 +951,64 @@ class BackupsAPITestCase(test.TestCase):
         self.assertEqual(res.status_int, 202)
         self.assertEqual(res_dict['restore']['backup_id'], backup_id)
 
+    @mock.patch('cinder.volume.API.create')
+    def test_restore_backup_name_specified(self,
+                                           _mock_volume_api_create):
+
+        # Intercept volume creation to ensure created volume
+        # has status of available
+        def fake_volume_api_create(context, size, name, description):
+            volume_id = utils.create_volume(self.context, size=size,
+                                            display_name=name)['id']
+            return db.volume_get(context, volume_id)
+
+        _mock_volume_api_create.side_effect = fake_volume_api_create
+
+        backup_id = self._create_backup(size=5, status='available')
+
+        body = {"restore": {'name': 'vol-01'}}
+        req = webob.Request.blank('/v2/fake/backups/%s/restore' %
+                                  backup_id)
+        req.method = 'POST'
+        req.headers['Content-Type'] = 'application/json'
+        req.body = json.dumps(body)
+        res = req.get_response(fakes.wsgi_app())
+        res_dict = json.loads(res.body)
+
+        description = 'auto-created_from_restore_from_backup'
+        # Assert that we have indeed passed on the name parameter
+        _mock_volume_api_create.assert_called_once_with(
+            mock.ANY,
+            5,
+            body['restore']['name'],
+            description)
+
+        self.assertEqual(202, res.status_int)
+        self.assertEqual(backup_id, res_dict['restore']['backup_id'])
+
+    def test_restore_backup_name_volume_id_specified(self):
+
+        backup_id = self._create_backup(size=5, status='available')
+        orig_vol_name = "vol-00"
+        volume_id = utils.create_volume(self.context, size=5,
+                                        display_name=orig_vol_name)['id']
+        body = {"restore": {'name': 'vol-01', 'volume_id': volume_id}}
+        req = webob.Request.blank('/v2/fake/backups/%s/restore' %
+                                  backup_id)
+        req.method = 'POST'
+        req.headers['Content-Type'] = 'application/json'
+        req.body = json.dumps(body)
+        res = req.get_response(fakes.wsgi_app())
+        res_dict = json.loads(res.body)
+
+        self.assertEqual(202, res.status_int)
+        self.assertEqual(backup_id, res_dict['restore']['backup_id'])
+        self.assertEqual(volume_id, res_dict['restore']['volume_id'])
+        restored_vol = db.volume_get(self.context,
+                                     res_dict['restore']['volume_id'])
+        # Ensure that the original volume name wasn't overridden
+        self.assertEqual(orig_vol_name, restored_vol['display_name'])
+
     @mock.patch('cinder.backup.API.restore')
     def test_restore_backup_with_InvalidInput(self,
                                               _mock_volume_api_restore):