Update OVO instance on destroy method call

None of the Versioned Objects destroy methods we have update the
instance fields, so after doing a destroy on an instance the status,
deleted, and deleted_at fields will still be the same as they were
before, leaving the instance in an inconsistent state.

This is important because our workers decorator for the HA A-A cleanup
mechanism relies on the status of the resources being properly updated
by the operations.

Change-Id: I4f15356931007e2ca725e477327c1ef67c7db487
Closes-Bug: #1604347
This commit is contained in:
Gorka Eguileor 2016-07-19 12:37:02 +02:00
parent 6cfecade9e
commit b03f539e6e
21 changed files with 239 additions and 79 deletions

View File

@ -407,8 +407,10 @@ def _service_query(context, session=None, read_deleted='no', host=None,
@require_admin_context
def service_destroy(context, service_id):
query = _service_query(context, id=service_id)
if not query.update(models.Service.delete_values()):
updated_values = models.Service.delete_values()
if not query.update(updated_values):
raise exception.ServiceNotFound(service_id=service_id)
return updated_values
@require_admin_context
@ -614,7 +616,7 @@ def quota_destroy(context, project_id, resource):
session = get_session()
with session.begin():
quota_ref = _quota_get(context, project_id, resource, session=session)
quota_ref.delete(session=session)
return quota_ref.delete(session=session)
###################
@ -717,7 +719,7 @@ def quota_class_destroy(context, class_name, resource):
with session.begin():
quota_class_ref = _quota_class_get(context, class_name, resource,
session=session)
quota_class_ref.delete(session=session)
return quota_class_ref.delete(session=session)
@require_admin_context
@ -1287,13 +1289,14 @@ def volume_destroy(context, volume_id):
session = get_session()
now = timeutils.utcnow()
with session.begin():
updated_values = {'status': 'deleted',
'deleted': True,
'deleted_at': now,
'updated_at': literal_column('updated_at'),
'migration_status': None}
model_query(context, models.Volume, session=session).\
filter_by(id=volume_id).\
update({'status': 'deleted',
'deleted': True,
'deleted_at': now,
'updated_at': literal_column('updated_at'),
'migration_status': None})
update(updated_values)
model_query(context, models.VolumeMetadata, session=session).\
filter_by(volume_id=volume_id).\
update({'deleted': True,
@ -1309,6 +1312,8 @@ def volume_destroy(context, volume_id):
update({'deleted': True,
'deleted_at': now,
'updated_at': literal_column('updated_at')})
del updated_values['updated_at']
return updated_values
@require_admin_context
@ -2208,19 +2213,23 @@ def snapshot_create(context, values):
@require_admin_context
@_retry_on_deadlock
def snapshot_destroy(context, snapshot_id):
utcnow = timeutils.utcnow()
session = get_session()
with session.begin():
updated_values = {'status': 'deleted',
'deleted': True,
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')}
model_query(context, models.Snapshot, session=session).\
filter_by(id=snapshot_id).\
update({'status': 'deleted',
'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
update(updated_values)
model_query(context, models.SnapshotMetadata, session=session).\
filter_by(snapshot_id=snapshot_id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')})
del updated_values['updated_at']
return updated_values
@require_context
@ -2928,6 +2937,7 @@ def volume_type_qos_specs_get(context, type_id):
@require_admin_context
@_retry_on_deadlock
def volume_type_destroy(context, id):
utcnow = timeutils.utcnow()
session = get_session()
with session.begin():
_volume_type_get(context, id, session)
@ -2937,19 +2947,22 @@ def volume_type_destroy(context, id):
LOG.error(_LE('VolumeType %s deletion failed, '
'VolumeType in use.'), id)
raise exception.VolumeTypeInUse(volume_type_id=id)
updated_values = {'deleted': True,
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')}
model_query(context, models.VolumeTypes, session=session).\
filter_by(id=id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
update(updated_values)
model_query(context, models.VolumeTypeExtraSpecs, session=session).\
filter_by(volume_type_id=id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')})
model_query(context, models.VolumeTypeProjects, session=session,
read_deleted="int_no").filter_by(
volume_type_id=id).soft_delete(synchronize_session=False)
del updated_values['updated_at']
return updated_values
@require_context
@ -3357,13 +3370,16 @@ def qos_specs_delete(context, qos_specs_id):
session = get_session()
with session.begin():
_qos_specs_get_ref(context, qos_specs_id, session)
updated_values = {'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')}
session.query(models.QualityOfServiceSpecs).\
filter(or_(models.QualityOfServiceSpecs.id == qos_specs_id,
models.QualityOfServiceSpecs.specs_id ==
qos_specs_id)).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
update(updated_values)
del updated_values['updated_at']
return updated_values
@require_admin_context
@ -3868,12 +3884,15 @@ def backup_update(context, backup_id, values):
@require_admin_context
def backup_destroy(context, backup_id):
updated_values = {'status': fields.BackupStatus.DELETED,
'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')}
model_query(context, models.Backup).\
filter_by(id=backup_id).\
update({'status': fields.BackupStatus.DELETED,
'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
update(updated_values)
del updated_values['updated_at']
return updated_values
###############################
@ -3959,6 +3978,7 @@ def transfer_create(context, values):
@require_context
@_retry_on_deadlock
def transfer_destroy(context, transfer_id):
utcnow = timeutils.utcnow()
session = get_session()
with session.begin():
transfer_ref = _transfer_get(context,
@ -3976,11 +3996,16 @@ def transfer_destroy(context, transfer_id):
volume_ref['status'] = 'available'
volume_ref.update(volume_ref)
volume_ref.save(session=session)
updated_values = {'deleted': True,
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')}
model_query(context, models.Transfer, session=session).\
filter_by(id=transfer_id).\
update({'deleted': True,
'deleted_at': timeutils.utcnow(),
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')})
del updated_values['updated_at']
return updated_values
@require_context
@ -4204,14 +4229,21 @@ def consistencygroup_update(context, consistencygroup_id, values):
@require_admin_context
def consistencygroup_destroy(context, consistencygroup_id):
utcnow = timeutils.utcnow()
session = get_session()
with session.begin():
updated_values = {'status': fields.ConsistencyGroupStatus.DELETED,
'deleted': True,
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')}
model_query(context, models.ConsistencyGroup, session=session).\
filter_by(id=consistencygroup_id).\
update({'status': fields.ConsistencyGroupStatus.DELETED,
'deleted': True,
'deleted_at': timeutils.utcnow(),
'deleted_at': utcnow,
'updated_at': literal_column('updated_at')})
del updated_values['updated_at']
return updated_values
def cg_has_cgsnapshot_filter():
@ -4406,12 +4438,15 @@ def cgsnapshot_update(context, cgsnapshot_id, values):
def cgsnapshot_destroy(context, cgsnapshot_id):
session = get_session()
with session.begin():
updated_values = {'status': 'deleted',
'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')}
model_query(context, models.Cgsnapshot, session=session).\
filter_by(id=cgsnapshot_id).\
update({'status': 'deleted',
'deleted': True,
'deleted_at': timeutils.utcnow(),
'updated_at': literal_column('updated_at')})
update(updated_values)
del updated_values['updated_at']
return updated_values
def cgsnapshot_creating_from_src():
@ -4587,11 +4622,14 @@ def message_destroy(context, message):
session = get_session()
now = timeutils.utcnow()
with session.begin():
updated_values = {'deleted': True,
'deleted_at': now,
'updated_at': literal_column('updated_at')}
(model_query(context, models.Message, session=session).
filter_by(id=message.get('id')).
update({'deleted': True,
'deleted_at': now,
'updated_at': literal_column('updated_at')}))
update(updated_values))
del updated_values['updated_at']
return updated_values
###############################

View File

@ -52,8 +52,10 @@ class CinderBase(models.TimestampMixin,
def delete(self, session):
"""Delete this object."""
self.update(self.delete_values())
updated_values = self.delete_values()
self.update(updated_values)
self.save(session=session)
return updated_values
class Service(BASE, CinderBase):

View File

@ -122,7 +122,9 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
def destroy(self):
with self.obj_as_admin():
db.backup_destroy(self._context, self.id)
updated_values = db.backup_destroy(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
@staticmethod
def decode_record(backup_url):

View File

@ -114,7 +114,9 @@ class CGSnapshot(base.CinderPersistentObject, base.CinderObject,
def destroy(self):
with self.obj_as_admin():
db.cgsnapshot_destroy(self._context, self.id)
updated_values = db.cgsnapshot_destroy(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
@base.CinderObjectRegistry.register

View File

@ -136,7 +136,10 @@ class ConsistencyGroup(base.CinderPersistentObject, base.CinderObject,
def destroy(self):
with self.obj_as_admin():
db.consistencygroup_destroy(self._context, self.id)
updated_values = db.consistencygroup_destroy(self._context,
self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
@base.CinderObjectRegistry.register

View File

@ -169,10 +169,11 @@ class QualityOfServiceSpecs(base.CinderPersistentObject,
if self.volume_types:
if not force:
raise exception.QoSSpecsInUse(specs_id=self.id)
else:
# remove all association
db.qos_specs_disassociate_all(self._context, self.id)
db.qos_specs_delete(self._context, self.id)
# remove all association
db.qos_specs_disassociate_all(self._context, self.id)
updated_values = db.qos_specs_delete(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
@base.CinderObjectRegistry.register

View File

@ -95,7 +95,9 @@ class Service(base.CinderPersistentObject, base.CinderObject,
def destroy(self):
with self.obj_as_admin():
db.service_destroy(self._context, self.id)
updated_values = db.service_destroy(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
@classmethod
def _get_minimum_version(cls, attribute, context, binary):

View File

@ -178,7 +178,9 @@ class Snapshot(base.CinderPersistentObject, base.CinderObject,
self.obj_reset_changes()
def destroy(self):
db.snapshot_destroy(self._context, self.id)
updated_values = db.snapshot_destroy(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
def obj_load_attr(self, attrname):
if attrname not in self.OPTIONAL_FIELDS:

View File

@ -327,7 +327,9 @@ class Volume(base.CinderPersistentObject, base.CinderObject,
def destroy(self):
with self.obj_as_admin():
db.volume_destroy(self._context, self.id)
updated_values = db.volume_destroy(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
def obj_load_attr(self, attrname):
if attrname not in self.OPTIONAL_FIELDS:

View File

@ -115,7 +115,9 @@ class VolumeType(base.CinderPersistentObject, base.CinderObject,
def destroy(self):
with self.obj_as_admin():
volume_types.destroy(self._context, self.id)
updated_values = volume_types.destroy(self._context, self.id)
self.update(updated_values)
self.obj_reset_changes(updated_values.keys())
@base.CinderObjectRegistry.register

View File

@ -13,6 +13,8 @@
# under the License.
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder.db.sqlalchemy import models
@ -77,13 +79,22 @@ class TestBackup(test_objects.BaseObjectsTestCase):
backup_update.assert_called_once_with(self.context, backup.id,
{'display_name': 'foobar'})
@mock.patch('cinder.db.backup_destroy')
def test_destroy(self, backup_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.backup_destroy')
def test_destroy(self, backup_destroy, utcnow_mock):
backup_destroy.return_value = {
'status': fields.BackupStatus.DELETED,
'deleted': True,
'deleted_at': utcnow_mock.return_value}
backup = objects.Backup(context=self.context, id=fake.BACKUP_ID)
backup.destroy()
self.assertTrue(backup_destroy.called)
admin_context = backup_destroy.call_args[0][0]
self.assertTrue(admin_context.is_admin)
self.assertTrue(backup.deleted)
self.assertEqual(fields.BackupStatus.DELETED, backup.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
backup.deleted_at)
def test_obj_field_temp_volume_snapshot_id(self):
backup = objects.Backup(context=self.context,

View File

@ -13,6 +13,8 @@
# under the License.
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder import exception
@ -81,14 +83,23 @@ class TestCGSnapshot(test_objects.BaseObjectsTestCase):
cgsnapshot.obj_get_changes())
self.assertRaises(exception.ObjectActionError, cgsnapshot.save)
@mock.patch('cinder.db.cgsnapshot_destroy')
def test_destroy(self, cgsnapshot_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.cgsnapshot_destroy')
def test_destroy(self, cgsnapshot_destroy, utcnow_mock):
cgsnapshot_destroy.return_value = {
'status': 'deleted',
'deleted': True,
'deleted_at': utcnow_mock.return_value}
cgsnapshot = objects.CGSnapshot(context=self.context,
id=fake.CGSNAPSHOT_ID)
cgsnapshot.destroy()
self.assertTrue(cgsnapshot_destroy.called)
admin_context = cgsnapshot_destroy.call_args[0][0]
self.assertTrue(admin_context.is_admin)
self.assertTrue(cgsnapshot.deleted)
self.assertEqual('deleted', cgsnapshot.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
cgsnapshot.deleted_at)
@mock.patch('cinder.objects.consistencygroup.ConsistencyGroup.get_by_id')
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')

View File

@ -13,6 +13,8 @@
# under the License.
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder import exception
@ -146,14 +148,24 @@ class TestConsistencyGroup(test_objects.BaseObjectsTestCase):
mock_vol_get_all_by_group.assert_called_once_with(self.context,
consistencygroup.id)
@mock.patch('cinder.db.consistencygroup_destroy')
def test_destroy(self, consistencygroup_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.consistencygroup_destroy')
def test_destroy(self, consistencygroup_destroy, utcnow_mock):
consistencygroup_destroy.return_value = {
'status': fields.ConsistencyGroupStatus.DELETED,
'deleted': True,
'deleted_at': utcnow_mock.return_value}
consistencygroup = objects.ConsistencyGroup(
context=self.context, id=fake.CONSISTENCY_GROUP_ID)
consistencygroup.destroy()
self.assertTrue(consistencygroup_destroy.called)
admin_context = consistencygroup_destroy.call_args[0][0]
self.assertTrue(admin_context.is_admin)
self.assertTrue(consistencygroup.deleted)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
consistencygroup.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
consistencygroup.deleted_at)
@mock.patch('cinder.db.sqlalchemy.api.consistencygroup_get')
def test_refresh(self, consistencygroup_get):

View File

@ -11,6 +11,8 @@
# under the License.
import mock
from oslo_utils import timeutils
import pytz
from cinder.db.sqlalchemy import models
from cinder import exception
@ -78,17 +80,25 @@ class TestQos(test_objects.BaseObjectsTestCase):
mock.call(self.context, fake.OBJECT_ID, 'key_to_remove1'),
mock.call(self.context, fake.OBJECT_ID, 'key_to_remove2')])
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.objects.VolumeTypeList.get_all_types_for_qos',
return_value=None)
@mock.patch('cinder.db.qos_specs_delete')
def test_destroy_no_vol_types(self, qos_fake_delete, fake_get_vol_types):
@mock.patch('cinder.db.sqlalchemy.api.qos_specs_delete')
def test_destroy_no_vol_types(self, qos_fake_delete, fake_get_vol_types,
utcnow_mock):
qos_fake_delete.return_value = {
'deleted': True,
'deleted_at': utcnow_mock.return_value}
qos_object = objects.QualityOfServiceSpecs._from_db_object(
self.context, objects.QualityOfServiceSpecs(), fake_qos)
qos_object.destroy()
qos_fake_delete.assert_called_once_with(self.context, fake_qos['id'])
qos_fake_delete.assert_called_once_with(mock.ANY, fake_qos['id'])
self.assertTrue(qos_object.deleted)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
qos_object.deleted_at)
@mock.patch('cinder.db.qos_specs_delete')
@mock.patch('cinder.db.sqlalchemy.api.qos_specs_delete')
@mock.patch('cinder.db.qos_specs_disassociate_all')
@mock.patch('cinder.objects.VolumeTypeList.get_all_types_for_qos')
def test_destroy_with_vol_types(self, fake_get_vol_types,
@ -100,7 +110,7 @@ class TestQos(test_objects.BaseObjectsTestCase):
self.assertRaises(exception.QoSSpecsInUse, qos_object.destroy)
qos_object.destroy(force=True)
qos_fake_delete.assert_called_once_with(self.context, fake_qos['id'])
qos_fake_delete.assert_called_once_with(mock.ANY, fake_qos['id'])
qos_fake_disassociate.assert_called_once_with(
self.context, fake_qos['id'])

View File

@ -13,6 +13,8 @@
# under the License.
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder import objects
@ -69,14 +71,21 @@ class TestService(test_objects.BaseObjectsTestCase):
service_update.assert_called_once_with(self.context, service.id,
{'topic': 'foobar'})
@mock.patch('cinder.db.service_destroy')
def test_destroy(self, service_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.service_destroy')
def test_destroy(self, service_destroy, utcnow_mock):
service_destroy.return_value = {
'deleted': True,
'deleted_at': utcnow_mock.return_value}
db_service = fake_service.fake_db_service()
service = objects.Service._from_db_object(
self.context, objects.Service(), db_service)
with mock.patch.object(service._context, 'elevated') as elevated_ctx:
service.destroy()
service_destroy.assert_called_once_with(elevated_ctx(), 123)
self.assertTrue(service.deleted)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
service.deleted_at)
@mock.patch('cinder.db.sqlalchemy.api.service_get')
def test_refresh(self, service_get):

View File

@ -14,6 +14,8 @@
import copy
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder.db.sqlalchemy import models
@ -112,12 +114,21 @@ class TestSnapshot(test_objects.BaseObjectsTestCase):
{'key1': 'value1'},
True)
@mock.patch('cinder.db.snapshot_destroy')
def test_destroy(self, snapshot_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.snapshot_destroy')
def test_destroy(self, snapshot_destroy, utcnow_mock):
snapshot_destroy.return_value = {
'status': 'deleted',
'deleted': True,
'deleted_at': utcnow_mock.return_value}
snapshot = objects.Snapshot(context=self.context, id=fake.SNAPSHOT_ID)
snapshot.destroy()
snapshot_destroy.assert_called_once_with(self.context,
fake.SNAPSHOT_ID)
self.assertTrue(snapshot.deleted)
self.assertEqual('deleted', snapshot.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
snapshot.deleted_at)
@mock.patch('cinder.db.snapshot_metadata_delete')
def test_delete_metadata_key(self, snapshot_metadata_delete):

View File

@ -14,6 +14,8 @@
import ddt
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder import context
@ -132,8 +134,13 @@ class TestVolume(test_objects.BaseObjectsTestCase):
volume.snapshots = objects.SnapshotList()
self.assertRaises(exception.ObjectActionError, volume.save)
@mock.patch('cinder.db.volume_destroy')
def test_destroy(self, volume_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.volume_destroy')
def test_destroy(self, volume_destroy, utcnow_mock):
volume_destroy.return_value = {
'status': 'deleted',
'deleted': True,
'deleted_at': utcnow_mock.return_value}
db_volume = fake_volume.fake_db_volume()
volume = objects.Volume._from_db_object(self.context,
objects.Volume(), db_volume)
@ -141,6 +148,11 @@ class TestVolume(test_objects.BaseObjectsTestCase):
self.assertTrue(volume_destroy.called)
admin_context = volume_destroy.call_args[0][0]
self.assertTrue(admin_context.is_admin)
self.assertTrue(volume.deleted)
self.assertEqual('deleted', volume.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
volume.deleted_at)
self.assertIsNone(volume.migration_status)
def test_obj_fields(self):
volume = objects.Volume(context=self.context, id=fake.VOLUME_ID,

View File

@ -13,6 +13,8 @@
# under the License.
import mock
from oslo_utils import timeutils
import pytz
import six
from cinder import objects
@ -79,8 +81,12 @@ class TestVolumeType(test_objects.BaseObjectsTestCase):
volume_type.name,
volume_type.description)
@mock.patch('cinder.volume.volume_types.destroy')
def test_destroy(self, volume_type_destroy):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow())
@mock.patch('cinder.db.sqlalchemy.api.volume_type_destroy')
def test_destroy(self, volume_type_destroy, utcnow_mock):
volume_type_destroy.return_value = {
'deleted': True,
'deleted_at': utcnow_mock.return_value}
db_volume_type = fake_volume.fake_db_volume_type()
volume_type = objects.VolumeType._from_db_object(self.context,
objects.VolumeType(),
@ -89,6 +95,9 @@ class TestVolumeType(test_objects.BaseObjectsTestCase):
self.assertTrue(volume_type_destroy.called)
admin_context = volume_type_destroy.call_args[0][0]
self.assertTrue(admin_context.is_admin)
self.assertTrue(volume_type.deleted)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC),
volume_type.deleted_at)
@mock.patch('cinder.db.sqlalchemy.api._volume_type_get_full')
def test_refresh(self, volume_type_get):

View File

@ -19,6 +19,7 @@ import datetime
import enum
import mock
from oslo_config import cfg
from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
@ -38,6 +39,7 @@ CONF = cfg.CONF
THREE = 3
THREE_HUNDREDS = 300
ONE_HUNDREDS = 100
UTC_NOW = timeutils.utcnow()
def _quota_reserve(context, project_id):
@ -142,11 +144,14 @@ class DBAPIServiceTestCase(BaseTest):
for key, value in self._get_base_values().items():
self.assertEqual(value, service[key])
def test_service_destroy(self):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=UTC_NOW)
def test_service_destroy(self, utcnow_mock):
service1 = self._create_service({})
service2 = self._create_service({'host': 'fake_host2'})
db.service_destroy(self.ctxt, service1['id'])
self.assertDictEqual(
{'deleted': True, 'deleted_at': UTC_NOW},
db.service_destroy(self.ctxt, service1['id']))
self.assertRaises(exception.ServiceNotFound,
db.service_get, self.ctxt, service1['id'])
self._assertEqualObjects(
@ -393,9 +398,13 @@ class DBAPIVolumeTestCase(BaseTest):
self._assertEqualObjects(volume, db.volume_get(self.ctxt,
volume['id']))
def test_volume_destroy(self):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=UTC_NOW)
def test_volume_destroy(self, utcnow_mock):
volume = db.volume_create(self.ctxt, {})
db.volume_destroy(self.ctxt, volume['id'])
self.assertDictEqual(
{'status': 'deleted', 'deleted': True, 'deleted_at': UTC_NOW,
'migration_status': None},
db.volume_destroy(self.ctxt, volume['id']))
self.assertRaises(exception.VolumeNotFound, db.volume_get,
self.ctxt, volume['id'])
@ -1803,8 +1812,11 @@ class DBAPIQuotaClassTestCase(BaseTest):
qc = db.quota_class_get(self.ctxt, 'test_qc', 'test_resource')
self._assertEqualObjects(self.sample_qc, qc)
def test_quota_class_destroy(self):
db.quota_class_destroy(self.ctxt, 'test_qc', 'test_resource')
@mock.patch('oslo_utils.timeutils.utcnow', return_value=UTC_NOW)
def test_quota_class_destroy(self, utcnow_mock):
self.assertDictEqual(
{'deleted': True, 'deleted_at': UTC_NOW},
db.quota_class_destroy(self.ctxt, 'test_qc', 'test_resource'))
self.assertRaises(exception.QuotaClassNotFound,
db.quota_class_get, self.ctxt,
'test_qc', 'test_resource')
@ -1909,10 +1921,12 @@ class DBAPIQuotaTestCase(BaseTest):
'volumes': {'reserved': 1, 'in_use': 0}},
quota_usage)
def test_quota_destroy(self):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=UTC_NOW)
def test_quota_destroy(self, utcnow_mock):
db.quota_create(self.ctxt, 'project1', 'resource1', 41)
self.assertIsNone(db.quota_destroy(self.ctxt, 'project1',
'resource1'))
self.assertDictEqual(
{'deleted': True, 'deleted_at': UTC_NOW},
db.quota_destroy(self.ctxt, 'project1', 'resource1'))
self.assertRaises(exception.ProjectQuotaNotFound, db.quota_get,
self.ctxt, 'project1', 'resource1')
@ -2134,9 +2148,13 @@ class DBAPIBackupTestCase(BaseTest):
self._assertEqualObjects(updated_values, updated_backup,
self._ignored_keys)
def test_backup_destroy(self):
@mock.patch('oslo_utils.timeutils.utcnow', return_value=UTC_NOW)
def test_backup_destroy(self, utcnow_mock):
for backup in self.created:
db.backup_destroy(self.ctxt, backup['id'])
self.assertDictEqual(
{'status': fields.BackupStatus.DELETED, 'deleted': True,
'deleted_at': UTC_NOW},
db.backup_destroy(self.ctxt, backup['id']))
self.assertFalse(db.backup_get_all(self.ctxt))
def test_backup_not_found(self):

View File

@ -22,6 +22,7 @@ import six
import time
from oslo_db import exception as db_exc
from oslo_utils import timeutils
from cinder import context
from cinder import db
@ -146,7 +147,8 @@ class QoSSpecsTestCase(test.TestCase):
return vol_types
def fake_db_delete(context, id):
pass
return {'deleted': True,
'deleted_at': timeutils.utcnow()}
def fake_disassociate_all(context, id):
pass

View File

@ -90,9 +90,8 @@ def destroy(context, id):
if id is None:
msg = _("id cannot be None")
raise exception.InvalidVolumeType(reason=msg)
else:
elevated = context if context.is_admin else context.elevated()
db.volume_type_destroy(elevated, id)
elevated = context if context.is_admin else context.elevated()
return db.volume_type_destroy(elevated, id)
def get_all_types(context, inactive=0, filters=None, marker=None,