From: Abhishek Lekshmanan Date: Mon, 8 Jun 2015 11:14:22 +0000 (+0530) Subject: Backups: allow name to be specified during restore X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=b515ecc4916715bde2c2b790a7ec2762457ec55a;p=openstack-build%2Fcinder-build.git Backups: allow name to be specified during restore 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-`. 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 --- diff --git a/cinder/api/contrib/backups.py b/cinder/api/contrib/backups.py index d327fdb39..56c561cb7 100644 --- a/cinder/api/contrib/backups.py +++ b/cinder/api/contrib/backups.py @@ -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: diff --git a/cinder/backup/api.py b/cinder/backup/api.py index afb0fcc2f..2c83915bd 100644 --- a/cinder/backup/api.py +++ b/cinder/backup/api.py @@ -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) diff --git a/cinder/tests/unit/api/contrib/test_backups.py b/cinder/tests/unit/api/contrib/test_backups.py index f410997ec..560122bb4 100644 --- a/cinder/tests/unit/api/contrib/test_backups.py +++ b/cinder/tests/unit/api/contrib/test_backups.py @@ -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):