From c9efc9e81b4e8b7992d75f06d159faeef8fa77ad Mon Sep 17 00:00:00 2001 From: suguangfeng Date: Fri, 9 Nov 2018 02:52:34 -0500 Subject: [PATCH] Rollback the volume_types table when failed to update quota_usages We create a new volume based on a volume type, then update the volume type name to a new name of 255 characters in length. When updating the volume type table, the quota_usages table is updated synchronously. If DB error occurs in the quota_usages table, we need to roll back the volume types table.Otherwise, when the volume is deleted, the information of the quota_usages table will not be updated. Closes-bug: #1802430 Related-Bug: #1608849 Change-Id: I040ccde7f04ae39258afd9b7322c939c8d796bde (cherry picked from commit c34e42af75b7b31adab7060fc2bd6ddfcab92bf5) --- cinder/tests/unit/test_volume_types.py | 25 +++++++++++++++++++++++++ cinder/volume/volume_types.py | 16 +++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cinder/tests/unit/test_volume_types.py b/cinder/tests/unit/test_volume_types.py index cdba6061b95..f7858aabf79 100644 --- a/cinder/tests/unit/test_volume_types.py +++ b/cinder/tests/unit/test_volume_types.py @@ -19,6 +19,7 @@ import mock import time from oslo_config import cfg +from oslo_db import exception as db_exc from oslo_utils import uuidutils from cinder import context @@ -143,6 +144,30 @@ class VolumeTypeTestCase(test.TestCase): new_type_name) volume_types.destroy(self.ctxt, type_ref.id) + @mock.patch('cinder.quota.VolumeTypeQuotaEngine.' + 'update_quota_resource') + def test_update_volume_type_name_with_db_error(self, mock_update_quota): + type_ref = volume_types.create(self.ctxt, + self.vol_type1_name, + self.vol_type1_specs, + description=self.vol_type1_description) + mock_update_quota.side_effect = db_exc.DBError + new_type_name = self.vol_type1_name + '_updated' + description = 'new_test' + is_public = False + self.assertRaises(exception.VolumeTypeUpdateFailed, + volume_types.update, self.ctxt, type_ref.id, + new_type_name, description, is_public) + mock_update_quota.assert_called_once_with(self.ctxt, + self.vol_type1_name, + new_type_name) + new = volume_types.get_volume_type_by_name(self.ctxt, + self.vol_type1_name) + self.assertEqual(self.vol_type1_name, new.get('name')) + self.assertEqual(self.vol_type1_description, new.get('description')) + self.assertTrue(new.get('is_public')) + volume_types.destroy(self.ctxt, type_ref.id) + def test_volume_type_create_then_destroy_with_non_admin(self): """Ensure volume types can be created and deleted by non-admin user. diff --git a/cinder/volume/volume_types.py b/cinder/volume/volume_types.py index 25b83d5e45c..65f94d7958b 100644 --- a/cinder/volume/volume_types.py +++ b/cinder/volume/volume_types.py @@ -79,9 +79,19 @@ def update(context, id, name, description, is_public=None): if name: old_type_name = old_volume_type.get('name') if old_type_name != name: - QUOTAS.update_quota_resource(elevated, - old_type_name, - name) + old_description = old_volume_type.get('description') + old_public = old_volume_type.get('is_public') + try: + QUOTAS.update_quota_resource(elevated, + old_type_name, + name) + # Rollback the updated information to the original + except db_exc.DBError: + db.volume_type_update(elevated, id, + dict(name=old_type_name, + description=old_description, + is_public=old_public)) + raise except db_exc.DBError: LOG.exception('DB error:') raise exception.VolumeTypeUpdateFailed(id=id)