Fix volume backup import test
There is a bug in Cinder (#1455043) and backups are incorrectly imported
into the DB, and once that is fixed current tempest backup import/export
test will fail.
The reason for mentioned failure is that backup imports preserve
original backup id, so we cannot import a backup to a system where it
already exists, as is the case of our test.
This patch fixes this by importing the backup with a "fake" uuid so that
the import doesn't give an error.
Co-Authored-By: Yuriy Nesenenko <ynesenenko@mirantis.com>
Related-Bug: #1476416
Change-Id: I38e1a7b7d269278acd7963b990a263acd3d6e0d5
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index b09cd2c..1289297 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -13,11 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
+import base64
+import six
+
+from oslo_serialization import jsonutils as json
+
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
-from tempest.lib import decorators
from tempest import test
CONF = config.CONF
@@ -41,6 +45,20 @@
self.backups_adm_client.delete_backup(backup_id)
self.backups_adm_client.wait_for_backup_deletion(backup_id)
+ def _decode_url(self, backup_url):
+ return json.loads(base64.decodestring(backup_url))
+
+ def _encode_backup(self, backup):
+ retval = json.dumps(backup)
+ if six.PY3:
+ retval = retval.encode('utf-8')
+ return base64.encodestring(retval)
+
+ def _modify_backup_url(self, backup_url, changes):
+ backup = self._decode_url(backup_url)
+ backup.update(changes)
+ return self._encode_backup(backup)
+
@test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
def test_volume_backup_create_get_detailed_list_restore_delete(self):
# Create backup
@@ -78,9 +96,13 @@
waiters.wait_for_volume_status(self.admin_volume_client,
restore['volume_id'], 'available')
- @decorators.skip_because(bug='1455043')
@test.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d')
def test_volume_backup_export_import(self):
+ """Test backup export import functionality.
+
+ Cinder allows exporting DB backup information through its API so it can
+ be imported back in case of a DB loss.
+ """
# Create backup
backup_name = data_utils.rand_name('Backup')
backup = (self.backups_adm_client.create_backup(
@@ -99,25 +121,40 @@
'cinder.backup.drivers'))
self.assertIsNotNone(export_backup['backup_url'])
+ # NOTE(geguileo): Backups are imported with the same backup id
+ # (important for incremental backups among other things), so we cannot
+ # import the exported backup information as it is, because that Backup
+ # ID already exists. So we'll fake the data by changing the backup id
+ # in the exported backup DB info we have retrieved before importing it
+ # back.
+ new_id = data_utils.rand_uuid()
+ new_url = self._modify_backup_url(
+ export_backup['backup_url'], {'id': new_id})
+
# Import Backup
import_backup = self.backups_adm_client.import_backup(
backup_service=export_backup['backup_service'],
- backup_url=export_backup['backup_url'])['backup']
- self.addCleanup(self._delete_backup, import_backup['id'])
+ backup_url=new_url)['backup']
+
+ # NOTE(geguileo): We delete both backups, but only one of those
+ # deletions will delete data from the backup back-end because they
+ # were both pointing to the same backend data.
+ self.addCleanup(self._delete_backup, new_id)
self.assertIn("id", import_backup)
+ self.assertEqual(new_id, import_backup['id'])
self.backups_adm_client.wait_for_backup_status(import_backup['id'],
'available')
# Verify Import Backup
backups = self.backups_adm_client.list_backups(detail=True)['backups']
- self.assertIn(import_backup['id'], [b['id'] for b in backups])
+ self.assertIn(new_id, [b['id'] for b in backups])
# Restore backup
- restore = (self.backups_adm_client.restore_backup(import_backup['id'])
- ['restore'])
+ restore = self.backups_adm_client.restore_backup(
+ backup['id'])['restore']
self.addCleanup(self.admin_volume_client.delete_volume,
restore['volume_id'])
- self.assertEqual(import_backup['id'], restore['backup_id'])
+ self.assertEqual(backup['id'], restore['backup_id'])
waiters.wait_for_volume_status(self.admin_volume_client,
restore['volume_id'], 'available')