blob: 835cc1d6d5b344f30703588e08b6140830866d23 [file] [log] [blame]
Giulio Fidente74b08ad2014-01-18 04:02:51 +01001# Copyright 2014 OpenStack Foundation
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Sirushti Murugesan12dc9732016-07-13 22:49:17 +053016from oslo_serialization import base64
Gorka Eguileor9de20c12015-08-13 11:16:43 +020017from oslo_serialization import jsonutils as json
18
Masayuki Igawa1edf94f2014-03-04 18:34:16 +090019from tempest.api.volume import base
Yaroslav Lobankoved3a35b2016-03-24 22:41:30 -050020from tempest.common import waiters
Giulio Fidente74b08ad2014-01-18 04:02:51 +010021from tempest import config
Ken'ichi Ohmichief1c1ce2017-03-10 11:07:10 -080022from tempest.lib.common.utils import data_utils
Ken'ichi Ohmichi6b279c72017-01-27 18:26:59 -080023from tempest.lib import decorators
Giulio Fidente74b08ad2014-01-18 04:02:51 +010024
25CONF = config.CONF
Giulio Fidente74b08ad2014-01-18 04:02:51 +010026
27
Ken'ichi Ohmichie8afb8c2017-03-27 11:25:37 -070028class VolumesBackupsAdminTest(base.BaseVolumeAdminTest):
zhufl2480d2f2020-08-14 11:16:39 +080029 """Test volume backups"""
Giulio Fidente74b08ad2014-01-18 04:02:51 +010030
31 @classmethod
Rohan Kanade05749152015-01-30 17:15:18 +053032 def skip_checks(cls):
Ken'ichi Ohmichie8afb8c2017-03-27 11:25:37 -070033 super(VolumesBackupsAdminTest, cls).skip_checks()
Giulio Fidente74b08ad2014-01-18 04:02:51 +010034 if not CONF.volume_feature_enabled.backup:
35 raise cls.skipException("Cinder backup feature disabled")
36
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000037 def _delete_backup(self, backup_id):
bkopilov62d21752016-06-08 10:16:11 +030038 self.admin_backups_client.delete_backup(backup_id)
Ken'ichi Ohmichi153b3d92016-08-03 14:35:46 -070039 self.admin_backups_client.wait_for_resource_deletion(backup_id)
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000040
Gorka Eguileor9de20c12015-08-13 11:16:43 +020041 def _decode_url(self, backup_url):
Sirushti Murugesan12dc9732016-07-13 22:49:17 +053042 return json.loads(base64.decode_as_text(backup_url))
Gorka Eguileor9de20c12015-08-13 11:16:43 +020043
44 def _encode_backup(self, backup):
45 retval = json.dumps(backup)
Sirushti Murugesan12dc9732016-07-13 22:49:17 +053046 return base64.encode_as_text(retval)
Gorka Eguileor9de20c12015-08-13 11:16:43 +020047
48 def _modify_backup_url(self, backup_url, changes):
49 backup = self._decode_url(backup_url)
50 backup.update(changes)
51 return self._encode_backup(backup)
52
Ken'ichi Ohmichi6b279c72017-01-27 18:26:59 -080053 @decorators.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d')
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000054 def test_volume_backup_export_import(self):
Gorka Eguileor9de20c12015-08-13 11:16:43 +020055 """Test backup export import functionality.
56
57 Cinder allows exporting DB backup information through its API so it can
58 be imported back in case of a DB loss.
59 """
lkuchlana2beb492016-08-17 12:42:44 +030060 volume = self.create_volume()
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000061 # Create backup
zhuflc6ce5392016-08-17 14:34:37 +080062 backup_name = data_utils.rand_name(self.__class__.__name__ + '-Backup')
jeremy.zhang112b8442018-05-30 22:20:50 +080063 backup = self.create_backup(volume_id=volume['id'], name=backup_name)
jeremy.zhangd1be5012018-06-06 17:25:39 +080064 waiters.wait_for_volume_resource_status(self.volumes_client,
65 volume['id'], 'available')
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000066 self.assertEqual(backup_name, backup['name'])
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000067
68 # Export Backup
bkopilov62d21752016-06-08 10:16:11 +030069 export_backup = (self.admin_backups_client.export_backup(backup['id'])
John Warren6cadeee2015-08-13 17:00:56 +000070 ['backup-record'])
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000071 self.assertTrue(export_backup['backup_service'].startswith(
72 'cinder.backup.drivers'))
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000073
Gorka Eguileor9de20c12015-08-13 11:16:43 +020074 # NOTE(geguileo): Backups are imported with the same backup id
75 # (important for incremental backups among other things), so we cannot
76 # import the exported backup information as it is, because that Backup
77 # ID already exists. So we'll fake the data by changing the backup id
78 # in the exported backup DB info we have retrieved before importing it
79 # back.
80 new_id = data_utils.rand_uuid()
81 new_url = self._modify_backup_url(
82 export_backup['backup_url'], {'id': new_id})
83
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000084 # Import Backup
bkopilov62d21752016-06-08 10:16:11 +030085 import_backup = self.admin_backups_client.import_backup(
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000086 backup_service=export_backup['backup_service'],
Gorka Eguileor9de20c12015-08-13 11:16:43 +020087 backup_url=new_url)['backup']
88
89 # NOTE(geguileo): We delete both backups, but only one of those
90 # deletions will delete data from the backup back-end because they
91 # were both pointing to the same backend data.
92 self.addCleanup(self._delete_backup, new_id)
Gorka Eguileor9de20c12015-08-13 11:16:43 +020093 self.assertEqual(new_id, import_backup['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +020094 waiters.wait_for_volume_resource_status(self.admin_backups_client,
95 import_backup['id'],
96 'available')
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +000097
98 # Verify Import Backup
zhuflf0e8beb2017-08-22 10:56:26 +080099 backups = self.admin_backups_client.list_backups()['backups']
Gorka Eguileor9de20c12015-08-13 11:16:43 +0200100 self.assertIn(new_id, [b['id'] for b in backups])
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +0000101
102 # Restore backup
jeremy.zhang112b8442018-05-30 22:20:50 +0800103 restore = self.backups_client.restore_backup(backup['id'])['restore']
104 self.addCleanup(self.volumes_client.delete_volume,
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +0000105 restore['volume_id'])
Gorka Eguileor9de20c12015-08-13 11:16:43 +0200106 self.assertEqual(backup['id'], restore['backup_id'])
jeremy.zhang04e1d672018-06-07 14:56:36 +0800107
108 # When restore operation is performed then, backup['id']
109 # goes to 'restoring' state so we need to wait for
110 # backup['id'] to become 'available'.
111 waiters.wait_for_volume_resource_status(
112 self.backups_client, backup['id'], 'available')
113 waiters.wait_for_volume_resource_status(
114 self.volumes_client, restore['volume_id'], 'available')
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +0000115
116 # Verify if restored volume is there in volume list
jeremy.zhang112b8442018-05-30 22:20:50 +0800117 volumes = self.volumes_client.list_volumes()['volumes']
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +0000118 self.assertIn(restore['volume_id'], [v['id'] for v in volumes])
ravikumar-venkatesan18c1d0e2015-03-18 11:28:37 +0000119
Ken'ichi Ohmichi6b279c72017-01-27 18:26:59 -0800120 @decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
Ghanshyam Mannb0d15bf2017-05-02 04:55:47 +0000121 def test_volume_backup_reset_status(self):
zhufl2480d2f2020-08-14 11:16:39 +0800122 """Test resetting volume backup status to error"""
lkuchlana2beb492016-08-17 12:42:44 +0300123 # Create a volume
124 volume = self.create_volume()
bkopilov19fc5fd2016-07-06 12:02:18 +0300125 # Create a backup
zhuflc6ce5392016-08-17 14:34:37 +0800126 backup_name = data_utils.rand_name(
127 self.__class__.__name__ + '-Backup')
jeremy.zhang112b8442018-05-30 22:20:50 +0800128 backup = self.create_backup(volume_id=volume['id'], name=backup_name)
jeremy.zhangd1be5012018-06-06 17:25:39 +0800129 waiters.wait_for_volume_resource_status(self.volumes_client,
130 volume['id'], 'available')
bkopilov19fc5fd2016-07-06 12:02:18 +0300131 self.assertEqual(backup_name, backup['name'])
bkopilov19fc5fd2016-07-06 12:02:18 +0300132 # Reset backup status to error
133 self.admin_backups_client.reset_backup_status(backup_id=backup['id'],
134 status="error")
jeremy.zhang112b8442018-05-30 22:20:50 +0800135 waiters.wait_for_volume_resource_status(self.backups_client,
lkuchlan52d7b0d2016-11-07 20:53:19 +0200136 backup['id'], 'error')