Cleanup for SnapshotObject

Mostly switched from dictionary notation (obj['prop']) to object
notation (obj.prop).
This patch doesn't contain changes for drivers. Drivers need to be
fixed in other patch.

Partial-Implements: blueprint cinder-objects
Change-Id: I98dd519e6dc84315df6caa768ce3f5fc4274431c
This commit is contained in:
Daniel Tadrzak 2015-07-02 15:44:39 +02:00
parent ea67b21c72
commit 200a65fa26
14 changed files with 279 additions and 261 deletions

View File

@ -250,7 +250,7 @@ class API(base.Base):
kwargs['cgsnapshot'] = cgsnapshot kwargs['cgsnapshot'] = cgsnapshot
kwargs['consistencygroup'] = group kwargs['consistencygroup'] = group
kwargs['snapshot'] = snapshot kwargs['snapshot'] = snapshot
volume_type_id = snapshot.get('volume_type_id') volume_type_id = snapshot.volume_type_id
if volume_type_id: if volume_type_id:
kwargs['volume_type'] = volume_types.get_volume_type( kwargs['volume_type'] = volume_types.get_volume_type(
context, volume_type_id) context, volume_type_id)
@ -262,7 +262,7 @@ class API(base.Base):
# and removal of volume entry in the db. # and removal of volume entry in the db.
try: try:
self.volume_api.create(context, self.volume_api.create(context,
snapshot['volume_size'], snapshot.volume_size,
None, None,
None, None,
**kwargs) **kwargs)

View File

@ -87,11 +87,11 @@ class Snapshot(base.CinderPersistentObject, base.CinderObject,
def _reset_metadata_tracking(self, fields=None): def _reset_metadata_tracking(self, fields=None):
if fields is None or 'metadata' in fields: if fields is None or 'metadata' in fields:
self._orig_metadata = (dict(self.metadata) self._orig_metadata = (dict(self.metadata)
if 'metadata' in self else {}) if self.obj_attr_is_set('metadata') else {})
def obj_what_changed(self): def obj_what_changed(self):
changes = super(Snapshot, self).obj_what_changed() changes = super(Snapshot, self).obj_what_changed()
if 'metadata' in self and self.metadata != self._orig_metadata: if hasattr(self, 'metadata') and self.metadata != self._orig_metadata:
changes.add('metadata') changes.add('metadata')
return changes return changes
@ -111,7 +111,7 @@ class Snapshot(base.CinderPersistentObject, base.CinderObject,
value = db_snapshot.get(name) value = db_snapshot.get(name)
if isinstance(field, fields.IntegerField): if isinstance(field, fields.IntegerField):
value = value if value is not None else 0 value = value if value is not None else 0
snapshot[name] = value setattr(snapshot, name, value)
if 'volume' in expected_attrs: if 'volume' in expected_attrs:
volume = objects.Volume(context) volume = objects.Volume(context)
@ -220,8 +220,7 @@ class SnapshotList(base.ObjectListBase, base.CinderObject):
snapshots = db.snapshot_get_all(context, search_opts, marker, limit, snapshots = db.snapshot_get_all(context, search_opts, marker, limit,
sort_keys, sort_dirs, offset) sort_keys, sort_dirs, offset)
return base.obj_make_list(context, cls(), objects.Snapshot, return base.obj_make_list(context, cls(), objects.Snapshot,
snapshots, snapshots, expected_attrs=['metadata'])
expected_attrs=['metadata'])
@base.remotable_classmethod @base.remotable_classmethod
def get_by_host(cls, context, host, filters=None): def get_by_host(cls, context, host, filters=None):

View File

@ -85,7 +85,7 @@ class AdminActionsTest(test.TestCase):
def _issue_snapshot_reset(self, ctx, snapshot, updated_status): def _issue_snapshot_reset(self, ctx, snapshot, updated_status):
req = webob.Request.blank('/v2/fake/snapshots/%s/action' % req = webob.Request.blank('/v2/fake/snapshots/%s/action' %
snapshot['id']) snapshot.id)
req.method = 'POST' req.method = 'POST'
req.headers['content-type'] = 'application/json' req.headers['content-type'] = 'application/json'
req.body = \ req.body = \
@ -353,10 +353,9 @@ class AdminActionsTest(test.TestCase):
} }
snapshot = objects.Snapshot(context=ctx, **kwargs) snapshot = objects.Snapshot(context=ctx, **kwargs)
snapshot.create() snapshot.create()
self.addCleanup(snapshot.destroy)
resp = self._issue_snapshot_reset(ctx, resp = self._issue_snapshot_reset(ctx, snapshot, {'status': 'error'})
snapshot,
{'status': 'error'})
self.assertEqual(202, resp.status_int) self.assertEqual(202, resp.status_int)
snapshot = objects.Snapshot.get_by_id(ctx, snapshot['id']) snapshot = objects.Snapshot.get_by_id(ctx, snapshot['id'])
@ -366,16 +365,16 @@ class AdminActionsTest(test.TestCase):
ctx = context.RequestContext('admin', 'fake', True) ctx = context.RequestContext('admin', 'fake', True)
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test', volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
'provider_location': '', 'size': 1}) 'provider_location': '', 'size': 1})
snapshot = db.snapshot_create(ctx, {'status': 'available', snapshot = objects.Snapshot(ctx, status='available',
'volume_id': volume['id']}) volume_id=volume['id'])
snapshot.create()
self.addCleanup(snapshot.destroy)
resp = self._issue_snapshot_reset(ctx, resp = self._issue_snapshot_reset(ctx, snapshot,
snapshot,
{'status': 'attaching'}) {'status': 'attaching'})
self.assertEqual(400, resp.status_int) self.assertEqual(400, resp.status_int)
snapshot = db.snapshot_get(ctx, snapshot['id']) self.assertEqual('available', snapshot.status)
self.assertEqual('available', snapshot['status'])
def test_force_delete(self): def test_force_delete(self):
# admin context # admin context
@ -862,7 +861,9 @@ class AdminActionsTest(test.TestCase):
host = 'test2' host = 'test2'
ctx = context.RequestContext('admin', 'fake', True) ctx = context.RequestContext('admin', 'fake', True)
volume = self._migrate_volume_prep() volume = self._migrate_volume_prep()
db.snapshot_create(ctx, {'volume_id': volume['id']}) snap = objects.Snapshot(ctx, volume_id=volume['id'])
snap.create()
self.addCleanup(snap.destroy)
self._migrate_volume_exec(ctx, volume, host, expected_status) self._migrate_volume_exec(ctx, volume, host, expected_status)
def test_migrate_volume_bad_force_host_copy(self): def test_migrate_volume_bad_force_host_copy(self):
@ -900,8 +901,8 @@ class AdminActionsTest(test.TestCase):
expected_status = 403 expected_status = 403
expected_id = None expected_id = None
ctx = context.RequestContext('fake', 'fake') ctx = context.RequestContext('fake', 'fake')
volume = self._migrate_volume_comp_exec(ctx, volume, new_volume, False, self._migrate_volume_comp_exec(ctx, volume, new_volume, False,
expected_status, expected_id) expected_status, expected_id)
def test_migrate_volume_comp_no_mig_status(self): def test_migrate_volume_comp_no_mig_status(self):
admin_ctx = context.get_admin_context() admin_ctx = context.get_admin_context()
@ -958,8 +959,8 @@ class AdminActionsTest(test.TestCase):
expected_status = 200 expected_status = 200
expected_id = 'fake2' expected_id = 'fake2'
ctx = context.RequestContext('admin', 'fake', True) ctx = context.RequestContext('admin', 'fake', True)
volume = self._migrate_volume_comp_exec(ctx, volume, new_volume, False, self._migrate_volume_comp_exec(ctx, volume, new_volume, False,
expected_status, expected_id) expected_status, expected_id)
def test_backup_reset_valid_updates(self): def test_backup_reset_valid_updates(self):
vac = admin_actions.BackupAdminController() vac = admin_actions.BackupAdminController()

View File

@ -42,7 +42,8 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
def setUp(self): def setUp(self):
super(ConsistencyGroupsAPITestCase, self).setUp() super(ConsistencyGroupsAPITestCase, self).setUp()
self.cg_api = cinder.consistencygroup.API() self.cg_api = cinder.consistencygroup.API()
self.ctxt = context.RequestContext('fake', 'fake', auth_token=True) self.ctxt = context.RequestContext('fake', 'fake', auth_token=True,
is_admin=True)
def _create_consistencygroup( def _create_consistencygroup(
self, self,
@ -489,6 +490,7 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
volume_type_id = '123456' volume_type_id = '123456'
consistencygroup = self._create_consistencygroup(status='available', consistencygroup = self._create_consistencygroup(status='available',
host='test_host') host='test_host')
remove_volume_id = utils.create_volume( remove_volume_id = utils.create_volume(
self.ctxt, self.ctxt,
volume_type_id=volume_type_id, volume_type_id=volume_type_id,
@ -732,11 +734,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
cgsnapshot_id = utils.create_cgsnapshot( cgsnapshot_id = utils.create_cgsnapshot(
self.ctxt, self.ctxt,
consistencygroup_id=consistencygroup.id)['id'] consistencygroup_id=consistencygroup.id)['id']
snapshot_id = utils.create_snapshot( snapshot = utils.create_snapshot(
self.ctxt, self.ctxt,
volume_id, volume_id,
cgsnapshot_id=cgsnapshot_id, cgsnapshot_id=cgsnapshot_id,
status='available')['id'] status='available')
test_cg_name = 'test cg' test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name, body = {"consistencygroup-from-src": {"name": test_cg_name,
@ -759,7 +761,7 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
self.ctxt.elevated(), res_dict['consistencygroup']['id']) self.ctxt.elevated(), res_dict['consistencygroup']['id'])
cg_ref.destroy() cg_ref.destroy()
db.snapshot_destroy(self.ctxt.elevated(), snapshot_id) snapshot.destroy()
db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id) db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id)
db.volume_destroy(self.ctxt.elevated(), volume_id) db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy() consistencygroup.destroy()
@ -804,11 +806,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
cgsnapshot_id = utils.create_cgsnapshot( cgsnapshot_id = utils.create_cgsnapshot(
self.ctxt, self.ctxt,
consistencygroup_id=consistencygroup.id)['id'] consistencygroup_id=consistencygroup.id)['id']
snapshot_id = utils.create_snapshot( snapshot = utils.create_snapshot(
self.ctxt, self.ctxt,
volume_id, volume_id,
cgsnapshot_id=cgsnapshot_id, cgsnapshot_id=cgsnapshot_id,
status='available')['id'] status='available')
test_cg_name = 'test cg' test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name, body = {"consistencygroup-from-src": {"name": test_cg_name,
@ -828,7 +830,7 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
self.assertEqual(400, res_dict['badRequest']['code']) self.assertEqual(400, res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message']) self.assertIsNotNone(res_dict['badRequest']['message'])
db.snapshot_destroy(self.ctxt.elevated(), snapshot_id) snapshot.destroy()
db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id) db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id)
db.volume_destroy(self.ctxt.elevated(), volume_id) db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy() consistencygroup.destroy()
@ -874,11 +876,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
cgsnapshot_id = utils.create_cgsnapshot( cgsnapshot_id = utils.create_cgsnapshot(
self.ctxt, self.ctxt,
consistencygroup_id=consistencygroup.id)['id'] consistencygroup_id=consistencygroup.id)['id']
snapshot_id = utils.create_snapshot( snapshot = utils.create_snapshot(
self.ctxt, self.ctxt,
volume_id, volume_id,
cgsnapshot_id=cgsnapshot_id, cgsnapshot_id=cgsnapshot_id,
status='available')['id'] status='available')
test_cg_name = 'test cg' test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name, body = {"consistencygroup-from-src": {"name": test_cg_name,
@ -898,7 +900,7 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
'group') 'group')
self.assertIn(msg, res_dict['badRequest']['message']) self.assertIn(msg, res_dict['badRequest']['message'])
db.snapshot_destroy(self.ctxt.elevated(), snapshot_id) snapshot.destroy()
db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id) db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id)
db.volume_destroy(self.ctxt.elevated(), volume_id) db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy() consistencygroup.destroy()
@ -1007,11 +1009,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
cgsnapshot_id = utils.create_cgsnapshot( cgsnapshot_id = utils.create_cgsnapshot(
self.ctxt, self.ctxt,
consistencygroup_id=consistencygroup.id)['id'] consistencygroup_id=consistencygroup.id)['id']
snapshot_id = utils.create_snapshot( snapshot = utils.create_snapshot(
self.ctxt, self.ctxt,
volume_id, volume_id,
cgsnapshot_id=cgsnapshot_id, cgsnapshot_id=cgsnapshot_id,
status='available')['id'] status='available')
test_cg_name = 'test cg' test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name, body = {"consistencygroup-from-src": {"name": test_cg_name,
@ -1030,7 +1032,7 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
msg = _("Create volume failed.") msg = _("Create volume failed.")
self.assertEqual(msg, res_dict['badRequest']['message']) self.assertEqual(msg, res_dict['badRequest']['message'])
db.snapshot_destroy(self.ctxt.elevated(), snapshot_id) snapshot.destroy()
db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id) db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id)
db.volume_destroy(self.ctxt.elevated(), volume_id) db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy() consistencygroup.destroy()

View File

@ -29,6 +29,7 @@ from cinder import db
from cinder.db.sqlalchemy import api as sqa_api from cinder.db.sqlalchemy import api as sqa_api
from cinder.db.sqlalchemy import models as sqa_models from cinder.db.sqlalchemy import models as sqa_models
from cinder import exception from cinder import exception
from cinder import objects
from cinder import quota from cinder import quota
from cinder import test from cinder import test
import cinder.tests.unit.image.fake import cinder.tests.unit.image.fake
@ -41,6 +42,7 @@ CONF = cfg.CONF
class QuotaIntegrationTestCase(test.TestCase): class QuotaIntegrationTestCase(test.TestCase):
def setUp(self): def setUp(self):
objects.register_all()
super(QuotaIntegrationTestCase, self).setUp() super(QuotaIntegrationTestCase, self).setUp()
self.volume_type_name = CONF.default_volume_type self.volume_type_name = CONF.default_volume_type
self.volume_type = db.volume_type_create( self.volume_type = db.volume_type_create(
@ -79,14 +81,15 @@ class QuotaIntegrationTestCase(test.TestCase):
return db.volume_create(self.context, vol) return db.volume_create(self.context, vol)
def _create_snapshot(self, volume): def _create_snapshot(self, volume):
snapshot = {} snapshot = objects.Snapshot(self.context)
snapshot['user_id'] = self.user_id snapshot.user_id = self.user_id or 'fake_user_id'
snapshot['project_id'] = self.project_id snapshot.project_id = self.project_id or 'fake_project_id'
snapshot['volume_id'] = volume['id'] snapshot.volume_id = volume['id']
snapshot['volume_size'] = volume['size'] snapshot.volume_size = volume['size']
snapshot['host'] = volume['host'] snapshot.host = volume['host']
snapshot['status'] = 'available' snapshot.status = 'available'
return db.snapshot_create(self.context, snapshot) snapshot.create()
return snapshot
def _create_backup(self, volume): def _create_backup(self, volume):
backup = {} backup = {}
@ -156,7 +159,7 @@ class QuotaIntegrationTestCase(test.TestCase):
self.assertRaises(exception.SnapshotLimitExceeded, self.assertRaises(exception.SnapshotLimitExceeded,
volume.API().create_snapshot, volume.API().create_snapshot,
self.context, vol_ref, '', '') self.context, vol_ref, '', '')
db.snapshot_destroy(self.context, snap_ref['id']) snap_ref.destroy()
db.volume_destroy(self.context, vol_ref['id']) db.volume_destroy(self.context, vol_ref['id'])
def test_too_many_backups(self): def test_too_many_backups(self):
@ -206,7 +209,7 @@ class QuotaIntegrationTestCase(test.TestCase):
usages = db.quota_usage_get_all_by_project(self.context, usages = db.quota_usage_get_all_by_project(self.context,
self.project_id) self.project_id)
self.assertEqual(20, usages['gigabytes']['in_use']) self.assertEqual(20, usages['gigabytes']['in_use'])
db.snapshot_destroy(self.context, snap_ref['id']) snap_ref.destroy()
db.volume_destroy(self.context, vol_ref['id']) db.volume_destroy(self.context, vol_ref['id'])
def test_too_many_combined_backup_gigabytes(self): def test_too_many_combined_backup_gigabytes(self):
@ -244,8 +247,8 @@ class QuotaIntegrationTestCase(test.TestCase):
self.assertEqual(20, usages['gigabytes']['in_use']) self.assertEqual(20, usages['gigabytes']['in_use'])
self.assertEqual(0, usages['gigabytes']['reserved']) self.assertEqual(0, usages['gigabytes']['reserved'])
db.snapshot_destroy(self.context, snap_ref['id']) snap_ref.destroy()
db.snapshot_destroy(self.context, snap_ref2['id']) snap_ref2.destroy()
db.volume_destroy(self.context, vol_ref['id']) db.volume_destroy(self.context, vol_ref['id'])
db.volume_destroy(self.context, vol_ref2['id']) db.volume_destroy(self.context, vol_ref2['id'])

View File

@ -54,6 +54,7 @@ from cinder.tests.unit.api import fakes
from cinder.tests.unit.brick import fake_lvm from cinder.tests.unit.brick import fake_lvm
from cinder.tests.unit import conf_fixture from cinder.tests.unit import conf_fixture
from cinder.tests.unit import fake_driver from cinder.tests.unit import fake_driver
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit.image import fake as fake_image from cinder.tests.unit.image import fake as fake_image
from cinder.tests.unit.keymgr import fake as fake_keymgr from cinder.tests.unit.keymgr import fake as fake_keymgr
from cinder.tests.unit import utils as tests_utils from cinder.tests.unit import utils as tests_utils
@ -1171,7 +1172,8 @@ class VolumeTestCase(BaseVolumeTestCase):
'status': 'available', 'status': 'available',
'volume_size': 10, 'volume_size': 10,
'volume_type_id': biz_type['id']} 'volume_type_id': biz_type['id']}
snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context,
**snapshot)
# Make sure the case of specifying a type that # Make sure the case of specifying a type that
# doesn't match the snapshots type fails # doesn't match the snapshots type fails
with mock.patch.object(cinder.volume.volume_types, with mock.patch.object(cinder.volume.volume_types,
@ -1184,11 +1186,11 @@ class VolumeTestCase(BaseVolumeTestCase):
name='fake_name', name='fake_name',
description='fake_desc', description='fake_desc',
volume_type=foo_type, volume_type=foo_type,
snapshot=snapshot) snapshot=snapshot_obj)
# Make sure that trying to specify a type # Make sure that trying to specify a type
# when the snapshots type is None fails # when the snapshots type is None fails
snapshot['volume_type_id'] = None snapshot_obj.volume_type_id = None
self.assertRaises(exception.InvalidInput, self.assertRaises(exception.InvalidInput,
volume_api.create, volume_api.create,
self.context, self.context,
@ -1196,12 +1198,12 @@ class VolumeTestCase(BaseVolumeTestCase):
name='fake_name', name='fake_name',
description='fake_desc', description='fake_desc',
volume_type=foo_type, volume_type=foo_type,
snapshot=snapshot) snapshot=snapshot_obj)
snapshot['volume_type_id'] = foo_type['id'] snapshot_obj.volume_type_id = foo_type['id']
volume_api.create(self.context, size=1, name='fake_name', volume_api.create(self.context, size=1, name='fake_name',
description='fake_desc', volume_type=foo_type, description='fake_desc', volume_type=foo_type,
snapshot=snapshot) snapshot=snapshot_obj)
db.volume_type_destroy(context.get_admin_context(), db.volume_type_destroy(context.get_admin_context(),
foo_type['id']) foo_type['id'])
@ -1353,6 +1355,8 @@ class VolumeTestCase(BaseVolumeTestCase):
'status': 'available', 'status': 'available',
'volume_size': 10, 'volume_size': 10,
'volume_type_id': biz_type['id']} 'volume_type_id': biz_type['id']}
snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context,
**snapshot)
with mock.patch.object(db, with mock.patch.object(db,
'service_get_all_by_topic') as mock_get_service, \ 'service_get_all_by_topic') as mock_get_service, \
@ -1372,7 +1376,7 @@ class VolumeTestCase(BaseVolumeTestCase):
name='fake_name', name='fake_name',
description='fake_desc', description='fake_desc',
volume_type=foo_type, volume_type=foo_type,
snapshot=snapshot) snapshot=snapshot_obj)
def test_create_snapshot_driver_not_initialized(self): def test_create_snapshot_driver_not_initialized(self):
volume_src = tests_utils.create_volume(self.context, volume_src = tests_utils.create_volume(self.context,
@ -1389,8 +1393,7 @@ class VolumeTestCase(BaseVolumeTestCase):
self.context, volume_src['id'], snapshot_obj) self.context, volume_src['id'], snapshot_obj)
# NOTE(flaper87): The volume status should be error. # NOTE(flaper87): The volume status should be error.
snapshot = db.snapshot_get(context.get_admin_context(), snapshot_id) self.assertEqual("error", snapshot_obj.status)
self.assertEqual("error", snapshot.status)
# lets cleanup the mess # lets cleanup the mess
self.volume.driver._initialized = True self.volume.driver._initialized = True
@ -1668,8 +1671,7 @@ class VolumeTestCase(BaseVolumeTestCase):
self.volume.create_snapshot(self.context, src_vol['id'], snapshot_obj) self.volume.create_snapshot(self.context, src_vol['id'], snapshot_obj)
# ensure that status of snapshot is 'available' # ensure that status of snapshot is 'available'
snapshot_ref = db.snapshot_get(self.context, snapshot_id)['status'] self.assertEqual('available', snapshot_obj.status)
self.assertEqual('available', snapshot_ref)
dst_vol = tests_utils.create_volume(self.context, dst_vol = tests_utils.create_volume(self.context,
snapshot_id=snapshot_id, snapshot_id=snapshot_id,
@ -1679,7 +1681,7 @@ class VolumeTestCase(BaseVolumeTestCase):
dst_vol['id']) dst_vol['id'])
# cleanup resource # cleanup resource
db.snapshot_destroy(self.context, snapshot_id) snapshot_obj.destroy()
db.volume_destroy(self.context, src_vol_id) db.volume_destroy(self.context, src_vol_id)
@mock.patch( @mock.patch(
@ -1728,8 +1730,7 @@ class VolumeTestCase(BaseVolumeTestCase):
self.volume.create_snapshot(self.context, volume['id'], snapshot_obj) self.volume.create_snapshot(self.context, volume['id'], snapshot_obj)
# ensure that status of snapshot is 'available' # ensure that status of snapshot is 'available'
snapshot_ref = db.snapshot_get(self.context, snapshot_id)['status'] self.assertEqual('available', snapshot_obj.status)
self.assertEqual('available', snapshot_ref)
# create volume from snapshot # create volume from snapshot
dst_vol = tests_utils.create_volume(self.context, dst_vol = tests_utils.create_volume(self.context,
@ -1747,7 +1748,7 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertEqual('available', vol['status']) self.assertEqual('available', vol['status'])
# cleanup resource # cleanup resource
db.snapshot_destroy(self.context, snapshot_id) snapshot_obj.destroy()
db.volume_destroy(self.context, src_vol_id) db.volume_destroy(self.context, src_vol_id)
db.volume_destroy(self.context, dst_vol['id']) db.volume_destroy(self.context, dst_vol['id'])
@ -1946,13 +1947,15 @@ class VolumeTestCase(BaseVolumeTestCase):
snapshot = {'id': 1234, snapshot = {'id': 1234,
'status': 'available', 'status': 'available',
'volume_size': 10} 'volume_size': 10}
snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context,
**snapshot)
self.assertRaises(exception.InvalidInput, self.assertRaises(exception.InvalidInput,
volume_api.create, volume_api.create,
self.context, self.context,
size=1, size=1,
name='fake_name', name='fake_name',
description='fake_desc', description='fake_desc',
snapshot=snapshot) snapshot=snapshot_obj)
def test_create_volume_from_snapshot_fail_wrong_az(self): def test_create_volume_from_snapshot_fail_wrong_az(self):
"""Test volume can't be created from snapshot in a different az.""" """Test volume can't be created from snapshot in a different az."""
@ -1971,11 +1974,9 @@ class VolumeTestCase(BaseVolumeTestCase):
**self.volume_params) **self.volume_params)
self.volume.create_volume(self.context, volume_src['id']) self.volume.create_volume(self.context, volume_src['id'])
snapshot = self._create_snapshot(volume_src['id']) snapshot = self._create_snapshot(volume_src['id'])
snapshot_obj = objects.Snapshot.get_by_id(self.context,
snapshot['id'])
self.volume.create_snapshot(self.context, volume_src['id'], self.volume.create_snapshot(self.context, volume_src['id'],
snapshot_obj) snapshot)
snapshot = db.snapshot_get(self.context, snapshot['id'])
volume_dst = volume_api.create(self.context, volume_dst = volume_api.create(self.context,
size=1, size=1,
@ -2985,17 +2986,19 @@ class VolumeTestCase(BaseVolumeTestCase):
pass pass
@staticmethod @staticmethod
def _create_snapshot(volume_id, size='0', metadata=None): def _create_snapshot(volume_id, size=1, metadata=None):
"""Create a snapshot object.""" """Create a snapshot object."""
snap = {} metadata = metadata or {}
snap['volume_size'] = size snap = objects.Snapshot(context.get_admin_context())
snap['user_id'] = 'fake' snap.volume_size = size
snap['project_id'] = 'fake' snap.user_id = 'fake'
snap['volume_id'] = volume_id snap.project_id = 'fake'
snap['status'] = "creating" snap.volume_id = volume_id
snap.status = "creating"
if metadata is not None: if metadata is not None:
snap['metadata'] = metadata snap.metadata = metadata
return db.snapshot_create(context.get_admin_context(), snap) snap.create()
return snap
def test_create_delete_snapshot(self): def test_create_delete_snapshot(self):
"""Test snapshot can be created and deleted.""" """Test snapshot can be created and deleted."""
@ -3020,13 +3023,12 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertEqual(2, len(self.notifier.notifications), self.assertEqual(2, len(self.notifier.notifications),
self.notifier.notifications) self.notifier.notifications)
snapshot_id = self._create_snapshot(volume['id'], snapshot = self._create_snapshot(volume['id'], size=volume['size'])
size=volume['size'])['id'] snapshot_id = snapshot.id
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id) self.volume.create_snapshot(self.context, volume['id'], snapshot)
self.volume.create_snapshot(self.context, volume['id'], snapshot_obj) self.assertEqual(
self.assertEqual(snapshot_id, snapshot_id, objects.Snapshot.get_by_id(self.context,
db.snapshot_get(context.get_admin_context(), snapshot_id).id)
snapshot_id).id)
msg = self.notifier.notifications[2] msg = self.notifier.notifications[2]
self.assertEqual('snapshot.create.start', msg['event_type']) self.assertEqual('snapshot.create.start', msg['event_type'])
expected = { expected = {
@ -3055,7 +3057,7 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertEqual(4, len(self.notifier.notifications), self.assertEqual(4, len(self.notifier.notifications),
self.notifier.notifications) self.notifier.notifications)
self.volume.delete_snapshot(self.context, snapshot_obj) self.volume.delete_snapshot(self.context, snapshot)
msg = self.notifier.notifications[4] msg = self.notifier.notifications[4]
self.assertEqual('snapshot.delete.start', msg['event_type']) self.assertEqual('snapshot.delete.start', msg['event_type'])
expected['status'] = 'available' expected['status'] = 'available'
@ -3071,9 +3073,9 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertEqual(6, len(self.notifier.notifications), self.assertEqual(6, len(self.notifier.notifications),
self.notifier.notifications) self.notifier.notifications)
snap = db.snapshot_get(context.get_admin_context(read_deleted='yes'), snap = objects.Snapshot.get_by_id(context.get_admin_context(
snapshot_id) read_deleted='yes'), snapshot_id)
self.assertEqual('deleted', snap['status']) self.assertEqual('deleted', snap.status)
self.assertRaises(exception.NotFound, self.assertRaises(exception.NotFound,
db.snapshot_get, db.snapshot_get,
self.context, self.context,
@ -3086,16 +3088,12 @@ class VolumeTestCase(BaseVolumeTestCase):
volume = tests_utils.create_volume(self.context, **self.volume_params) volume = tests_utils.create_volume(self.context, **self.volume_params)
snapshot = self._create_snapshot(volume['id'], size=volume['size'], snapshot = self._create_snapshot(volume['id'], size=volume['size'],
metadata=test_meta) metadata=test_meta)
snapshot_id = snapshot['id'] snapshot_id = snapshot.id
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id)
snap = db.snapshot_get(context.get_admin_context(), snapshot_id) result_dict = snapshot.metadata
result_dict = dict(snap)
result_meta = { self.assertEqual(test_meta, result_dict)
result_dict['snapshot_metadata'][0].key: self.volume.delete_snapshot(self.context, snapshot)
result_dict['snapshot_metadata'][0].value}
self.assertEqual(test_meta, result_meta)
self.volume.delete_snapshot(self.context, snapshot_obj)
self.assertRaises(exception.NotFound, self.assertRaises(exception.NotFound,
db.snapshot_get, db.snapshot_get,
self.context, self.context,
@ -3228,13 +3226,11 @@ class VolumeTestCase(BaseVolumeTestCase):
"""Test volume can't be deleted with dependent snapshots.""" """Test volume can't be deleted with dependent snapshots."""
volume = tests_utils.create_volume(self.context, **self.volume_params) volume = tests_utils.create_volume(self.context, **self.volume_params)
self.volume.create_volume(self.context, volume['id']) self.volume.create_volume(self.context, volume['id'])
snapshot_id = self._create_snapshot(volume['id'], snapshot = self._create_snapshot(volume['id'], size=volume['size'])
size=volume['size'])['id'] self.volume.create_snapshot(self.context, volume['id'], snapshot)
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id) self.assertEqual(
self.volume.create_snapshot(self.context, volume['id'], snapshot_obj) snapshot.id, objects.Snapshot.get_by_id(self.context,
self.assertEqual(snapshot_id, snapshot.id).id)
db.snapshot_get(context.get_admin_context(),
snapshot_id).id)
volume['status'] = 'available' volume['status'] = 'available'
volume['host'] = 'fakehost' volume['host'] = 'fakehost'
@ -3245,7 +3241,7 @@ class VolumeTestCase(BaseVolumeTestCase):
volume_api.delete, volume_api.delete,
self.context, self.context,
volume) volume)
self.volume.delete_snapshot(self.context, snapshot_obj) self.volume.delete_snapshot(self.context, snapshot)
self.volume.delete_volume(self.context, volume['id']) self.volume.delete_volume(self.context, volume['id'])
def test_delete_volume_in_consistency_group(self): def test_delete_volume_in_consistency_group(self):
@ -3263,23 +3259,19 @@ class VolumeTestCase(BaseVolumeTestCase):
"""Test snapshot can be created and deleted.""" """Test snapshot can be created and deleted."""
volume = tests_utils.create_volume(self.context, **self.volume_params) volume = tests_utils.create_volume(self.context, **self.volume_params)
self.volume.create_volume(self.context, volume['id']) self.volume.create_volume(self.context, volume['id'])
snapshot_id = self._create_snapshot(volume['id'], snapshot = self._create_snapshot(volume['id'], size=volume['size'])
size=volume['size'])['id'] self.volume.create_snapshot(self.context, volume['id'], snapshot)
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id)
self.volume.create_snapshot(self.context, volume['id'], snapshot_obj)
snapshot = db.snapshot_get(context.get_admin_context(),
snapshot_id)
volume_api = cinder.volume.api.API() volume_api = cinder.volume.api.API()
snapshot['status'] = 'badstatus' snapshot.status = 'badstatus'
self.assertRaises(exception.InvalidSnapshot, self.assertRaises(exception.InvalidSnapshot,
volume_api.delete_snapshot, volume_api.delete_snapshot,
self.context, self.context,
snapshot) snapshot)
snapshot['status'] = 'error' snapshot.status = 'error'
self.volume.delete_snapshot(self.context, snapshot_obj) self.volume.delete_snapshot(self.context, snapshot)
self.volume.delete_volume(self.context, volume['id']) self.volume.delete_volume(self.context, volume['id'])
def test_create_snapshot_force(self): def test_create_snapshot_force(self):
@ -3306,7 +3298,7 @@ class VolumeTestCase(BaseVolumeTestCase):
volume, volume,
'fake_name', 'fake_name',
'fake_description') 'fake_description')
db.snapshot_destroy(self.context, snapshot_ref['id']) snapshot_ref.destroy()
db.volume_destroy(self.context, volume['id']) db.volume_destroy(self.context, volume['id'])
# create volume and attach to the host # create volume and attach to the host
@ -3329,7 +3321,7 @@ class VolumeTestCase(BaseVolumeTestCase):
volume, volume,
'fake_name', 'fake_name',
'fake_description') 'fake_description')
db.snapshot_destroy(self.context, snapshot_ref['id']) snapshot_ref.destroy()
db.volume_destroy(self.context, volume['id']) db.volume_destroy(self.context, volume['id'])
def test_create_snapshot_from_bootable_volume(self): def test_create_snapshot_from_bootable_volume(self):
@ -3346,13 +3338,12 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertTrue(vol_glance_meta) self.assertTrue(vol_glance_meta)
# create snapshot from bootable volume # create snapshot from bootable volume
snap_id = self._create_snapshot(volume_id)['id'] snap = self._create_snapshot(volume_id)
snapshot_obj = objects.Snapshot.get_by_id(self.context, snap_id) self.volume.create_snapshot(ctxt, volume_id, snap)
self.volume.create_snapshot(ctxt, volume_id, snapshot_obj)
# get snapshot's volume_glance_metadata # get snapshot's volume_glance_metadata
snap_glance_meta = db.volume_snapshot_glance_metadata_get( snap_glance_meta = db.volume_snapshot_glance_metadata_get(
ctxt, snap_id) ctxt, snap.id)
self.assertTrue(snap_glance_meta) self.assertTrue(snap_glance_meta)
# ensure that volume's glance metadata is copied # ensure that volume's glance metadata is copied
@ -3363,11 +3354,10 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertDictMatch(vol_glance_dict, snap_glance_dict) self.assertDictMatch(vol_glance_dict, snap_glance_dict)
# ensure that snapshot's status is changed to 'available' # ensure that snapshot's status is changed to 'available'
snapshot_ref = db.snapshot_get(ctxt, snap_id)['status'] self.assertEqual('available', snap.status)
self.assertEqual('available', snapshot_ref)
# cleanup resource # cleanup resource
db.snapshot_destroy(ctxt, snap_id) snap.destroy()
db.volume_destroy(ctxt, volume_id) db.volume_destroy(ctxt, volume_id)
def test_create_snapshot_from_bootable_volume_fail(self): def test_create_snapshot_from_bootable_volume_fail(self):
@ -3387,10 +3377,8 @@ class VolumeTestCase(BaseVolumeTestCase):
vol_glance_meta = db.volume_glance_metadata_get(ctxt, volume_id) vol_glance_meta = db.volume_glance_metadata_get(ctxt, volume_id)
self.assertTrue(vol_glance_meta) self.assertTrue(vol_glance_meta)
snap = self._create_snapshot(volume_id) snap = self._create_snapshot(volume_id)
snap_id = snap['id'] snap_stat = snap.status
snap_stat = snap['status'] self.assertTrue(snap.id)
snapshot_obj = objects.Snapshot.get_by_id(self.context, snap_id)
self.assertTrue(snap_id)
self.assertTrue(snap_stat) self.assertTrue(snap_stat)
# set to return DB exception # set to return DB exception
@ -3403,19 +3391,18 @@ class VolumeTestCase(BaseVolumeTestCase):
self.volume.create_snapshot, self.volume.create_snapshot,
ctxt, ctxt,
volume_id, volume_id,
snapshot_obj) snap)
# get snapshot's volume_glance_metadata # get snapshot's volume_glance_metadata
self.assertRaises(exception.GlanceMetadataNotFound, self.assertRaises(exception.GlanceMetadataNotFound,
db.volume_snapshot_glance_metadata_get, db.volume_snapshot_glance_metadata_get,
ctxt, snap_id) ctxt, snap.id)
# ensure that status of snapshot is 'error' # ensure that status of snapshot is 'error'
snapshot_ref = db.snapshot_get(ctxt, snap_id)['status'] self.assertEqual('error', snap.status)
self.assertEqual('error', snapshot_ref)
# cleanup resource # cleanup resource
db.snapshot_destroy(ctxt, snap_id) snap.destroy()
db.volume_destroy(ctxt, volume_id) db.volume_destroy(ctxt, volume_id)
def test_create_snapshot_from_bootable_volume_with_volume_metadata_none( def test_create_snapshot_from_bootable_volume_with_volume_metadata_none(
@ -3427,19 +3414,17 @@ class VolumeTestCase(BaseVolumeTestCase):
# set bootable flag of volume to True # set bootable flag of volume to True
db.volume_update(self.context, volume_id, {'bootable': True}) db.volume_update(self.context, volume_id, {'bootable': True})
snapshot_id = self._create_snapshot(volume['id'])['id'] snapshot = self._create_snapshot(volume['id'])
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id) self.volume.create_snapshot(self.context, volume['id'], snapshot)
self.volume.create_snapshot(self.context, volume['id'], snapshot_obj)
self.assertRaises(exception.GlanceMetadataNotFound, self.assertRaises(exception.GlanceMetadataNotFound,
db.volume_snapshot_glance_metadata_get, db.volume_snapshot_glance_metadata_get,
self.context, snapshot_id) self.context, snapshot.id)
# ensure that status of snapshot is 'available' # ensure that status of snapshot is 'available'
snapshot_ref = db.snapshot_get(self.context, snapshot_id)['status'] self.assertEqual('available', snapshot.status)
self.assertEqual('available', snapshot_ref)
# cleanup resource # cleanup resource
db.snapshot_destroy(self.context, snapshot_id) snapshot.destroy()
db.volume_destroy(self.context, volume_id) db.volume_destroy(self.context, volume_id)
def test_delete_busy_snapshot(self): def test_delete_busy_snapshot(self):
@ -3453,10 +3438,8 @@ class VolumeTestCase(BaseVolumeTestCase):
volume = tests_utils.create_volume(self.context, **self.volume_params) volume = tests_utils.create_volume(self.context, **self.volume_params)
volume_id = volume['id'] volume_id = volume['id']
self.volume.create_volume(self.context, volume_id) self.volume.create_volume(self.context, volume_id)
snapshot_id = self._create_snapshot(volume_id, snapshot = self._create_snapshot(volume_id, size=volume['size'])
size=volume['size'])['id'] self.volume.create_snapshot(self.context, volume_id, snapshot)
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id)
self.volume.create_snapshot(self.context, volume_id, snapshot_obj)
self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot') self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot')
@ -3464,8 +3447,9 @@ class VolumeTestCase(BaseVolumeTestCase):
mox.IgnoreArg()).AndRaise( mox.IgnoreArg()).AndRaise(
exception.SnapshotIsBusy(snapshot_name='fake')) exception.SnapshotIsBusy(snapshot_name='fake'))
self.mox.ReplayAll() self.mox.ReplayAll()
self.volume.delete_snapshot(self.context, snapshot_obj) snapshot_id = snapshot.id
snapshot_ref = db.snapshot_get(self.context, snapshot_id) self.volume.delete_snapshot(self.context, snapshot)
snapshot_ref = objects.Snapshot.get_by_id(self.context, snapshot_id)
self.assertEqual(snapshot_id, snapshot_ref.id) self.assertEqual(snapshot_id, snapshot_ref.id)
self.assertEqual("available", snapshot_ref.status) self.assertEqual("available", snapshot_ref.status)
@ -3481,9 +3465,9 @@ class VolumeTestCase(BaseVolumeTestCase):
volume = tests_utils.create_volume(self.context, **self.volume_params) volume = tests_utils.create_volume(self.context, **self.volume_params)
volume_id = volume['id'] volume_id = volume['id']
self.volume.create_volume(self.context, volume_id) self.volume.create_volume(self.context, volume_id)
snapshot_id = self._create_snapshot(volume_id)['id'] snapshot = self._create_snapshot(volume_id)
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id) snapshot_id = snapshot.id
self.volume.create_snapshot(self.context, volume_id, snapshot_obj) self.volume.create_snapshot(self.context, volume_id, snapshot)
self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot') self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot')
@ -3491,8 +3475,8 @@ class VolumeTestCase(BaseVolumeTestCase):
mox.IgnoreArg()).AndRaise( mox.IgnoreArg()).AndRaise(
exception.SnapshotIsBusy(snapshot_name='fake')) exception.SnapshotIsBusy(snapshot_name='fake'))
self.mox.ReplayAll() self.mox.ReplayAll()
self.volume.delete_snapshot(self.context, snapshot_obj) self.volume.delete_snapshot(self.context, snapshot)
snapshot_ref = db.snapshot_get(self.context, snapshot_id) snapshot_ref = objects.Snapshot.get_by_id(self.context, snapshot_id)
self.assertEqual(snapshot_id, snapshot_ref.id) self.assertEqual(snapshot_id, snapshot_ref.id)
self.assertEqual("available", snapshot_ref.status) self.assertEqual("available", snapshot_ref.status)
@ -3500,7 +3484,7 @@ class VolumeTestCase(BaseVolumeTestCase):
self.assertRaises(exception.VolumeBackendAPIException, self.assertRaises(exception.VolumeBackendAPIException,
self.volume.delete_snapshot, self.volume.delete_snapshot,
self.context, self.context,
snapshot_obj) snapshot)
self.assertRaises(exception.VolumeBackendAPIException, self.assertRaises(exception.VolumeBackendAPIException,
self.volume.delete_volume, self.volume.delete_volume,
self.context, self.context,
@ -3847,16 +3831,16 @@ class VolumeTestCase(BaseVolumeTestCase):
# create raw snapshot # create raw snapshot
volume = tests_utils.create_volume(self.context, **self.volume_params) volume = tests_utils.create_volume(self.context, **self.volume_params)
snapshot = self._create_snapshot(volume['id']) snapshot = self._create_snapshot(volume['id'])
snapshot_obj = objects.Snapshot.get_by_id(self.context, snapshot_id = snapshot.id
snapshot['id']) self.assertIsNone(snapshot.display_name)
self.assertIsNone(snapshot['display_name'])
# use volume.api to update name # use volume.api to update name
volume_api = cinder.volume.api.API() volume_api = cinder.volume.api.API()
update_dict = {'display_name': 'test update name'} update_dict = {'display_name': 'test update name'}
volume_api.update_snapshot(self.context, snapshot_obj, update_dict) volume_api.update_snapshot(self.context, snapshot, update_dict)
# read changes from db # read changes from db
snap = db.snapshot_get(context.get_admin_context(), snapshot['id']) snap = objects.Snapshot.get_by_id(context.get_admin_context(),
self.assertEqual('test update name', snap['display_name']) snapshot_id)
self.assertEqual('test update name', snap.display_name)
@mock.patch.object(QUOTAS, 'reserve') @mock.patch.object(QUOTAS, 'reserve')
def test_extend_volume(self, reserve): def test_extend_volume(self, reserve):
@ -5088,25 +5072,28 @@ class VolumeTestCase(BaseVolumeTestCase):
'cgsnapshot_id': '1'} 'cgsnapshot_id': '1'}
snp3 = {'id': '3', 'name': 'snap 3', snp3 = {'id': '3', 'name': 'snap 3',
'cgsnapshot_id': '1'} 'cgsnapshot_id': '1'}
snp1_obj = fake_snapshot.fake_snapshot_obj(self.context, **snp1)
snp2_obj = fake_snapshot.fake_snapshot_obj(self.context, **snp2)
snp3_obj = fake_snapshot.fake_snapshot_obj(self.context, **snp3)
volumes = [] volumes = []
snapshots = [] snapshots = []
volumes.append(vol1) volumes.append(vol1)
volumes.append(vol2) volumes.append(vol2)
volumes.append(vol3) volumes.append(vol3)
snapshots.append(snp2) snapshots.append(snp2_obj)
snapshots.append(snp3) snapshots.append(snp3_obj)
snapshots.append(snp1) snapshots.append(snp1_obj)
i = 0 i = 0
for vol in volumes: for vol in volumes:
snap = snapshots[i] snap = snapshots[i]
i += 1 i += 1
self.assertNotEqual(vol['snapshot_id'], snap['id']) self.assertNotEqual(vol['snapshot_id'], snap.id)
sorted_snaps = self.volume._sort_snapshots(volumes, snapshots) sorted_snaps = self.volume._sort_snapshots(volumes, snapshots)
i = 0 i = 0
for vol in volumes: for vol in volumes:
snap = sorted_snaps[i] snap = sorted_snaps[i]
i += 1 i += 1
self.assertEqual(vol['snapshot_id'], snap['id']) self.assertEqual(vol['snapshot_id'], snap.id)
snapshots[2]['id'] = '9999' snapshots[2]['id'] = '9999'
self.assertRaises(exception.SnapshotNotFound, self.assertRaises(exception.SnapshotNotFound,
@ -5173,16 +5160,16 @@ class VolumeTestCase(BaseVolumeTestCase):
cgsnapshot = db.cgsnapshot_create(context.get_admin_context(), cgsnap) cgsnapshot = db.cgsnapshot_create(context.get_admin_context(), cgsnap)
# Create a snapshot object # Create a snapshot object
snap = {} snap = objects.Snapshot(context.get_admin_context())
snap['volume_size'] = size snap.volume_size = size
snap['user_id'] = 'fake' snap.user_id = 'fake'
snap['project_id'] = 'fake' snap.project_id = 'fake'
snap['volume_id'] = volume_id snap.volume_id = volume_id
snap['status'] = "available" snap.status = "available"
snap['cgsnapshot_id'] = cgsnapshot['id'] snap.cgsnapshot_id = cgsnapshot['id']
snapshot = db.snapshot_create(context.get_admin_context(), snap) snap.create()
return cgsnapshot, snapshot return cgsnapshot, snap
@mock.patch('cinder.volume.driver.VolumeDriver.create_consistencygroup', @mock.patch('cinder.volume.driver.VolumeDriver.create_consistencygroup',
autospec=True, autospec=True,
@ -5923,31 +5910,41 @@ class GetActiveByWindowTestCase(BaseVolumeTestCase):
self.db_attrs[i]['volume_id'] = 1 self.db_attrs[i]['volume_id'] = 1
# Not in window # Not in window
db.snapshot_create(self.ctx, self.db_attrs[0]) del self.db_attrs[0]['id']
snap1 = objects.Snapshot(self.ctx, **self.db_attrs[0])
snap1.create()
# In - deleted in window # In - deleted in window
db.snapshot_create(self.ctx, self.db_attrs[1]) del self.db_attrs[1]['id']
snap2 = objects.Snapshot(self.ctx, **self.db_attrs[1])
snap2.create()
# In - deleted after window # In - deleted after window
db.snapshot_create(self.ctx, self.db_attrs[2]) del self.db_attrs[2]['id']
snap3 = objects.Snapshot(self.ctx, **self.db_attrs[2])
snap3.create()
# In - created in window # In - created in window
db.snapshot_create(self.context, self.db_attrs[3]) del self.db_attrs[3]['id']
# Not of window. snap4 = objects.Snapshot(self.ctx, **self.db_attrs[3])
db.snapshot_create(self.context, self.db_attrs[4]) snap4.create()
snapshots = db.snapshot_get_active_by_window( # Not of window.
del self.db_attrs[4]['id']
snap5 = objects.Snapshot(self.ctx, **self.db_attrs[4])
snap5.create()
snapshots = objects.SnapshotList.get_active_by_window(
self.context, self.context,
datetime.datetime(1, 3, 1, 1, 1, 1), datetime.datetime(1, 3, 1, 1, 1, 1),
datetime.datetime(1, 4, 1, 1, 1, 1), datetime.datetime(1, 4, 1, 1, 1, 1)).objects
project_id='p1')
self.assertEqual(3, len(snapshots)) self.assertEqual(3, len(snapshots))
self.assertEqual(u'2', snapshots[0].id) self.assertEqual(snap2.id, snapshots[0].id)
self.assertEqual(u'1', snapshots[0].volume.id) self.assertEqual(u'1', snapshots[0].volume_id)
self.assertEqual(u'3', snapshots[1].id) self.assertEqual(snap3.id, snapshots[1].id)
self.assertEqual(u'1', snapshots[1].volume.id) self.assertEqual(u'1', snapshots[1].volume_id)
self.assertEqual(u'4', snapshots[2].id) self.assertEqual(snap4.id, snapshots[2].id)
self.assertEqual(u'1', snapshots[2].volume.id) self.assertEqual(u'1', snapshots[2].volume_id)
class DriverTestCase(test.TestCase): class DriverTestCase(test.TestCase):

View File

@ -19,6 +19,7 @@ Unit Tests for volume types extra specs code
from cinder import context from cinder import context
from cinder import db from cinder import db
from cinder import exception from cinder import exception
from cinder import objects
from cinder import test from cinder import test
@ -27,6 +28,7 @@ class VolumeGlanceMetadataTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(VolumeGlanceMetadataTestCase, self).setUp() super(VolumeGlanceMetadataTestCase, self).setUp()
self.ctxt = context.get_admin_context() self.ctxt = context.get_admin_context()
objects.register_all()
def test_vol_glance_metadata_bad_vol_id(self): def test_vol_glance_metadata_bad_vol_id(self):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
@ -112,17 +114,19 @@ class VolumeGlanceMetadataTestCase(test.TestCase):
def test_vol_glance_metadata_copy_to_snapshot(self): def test_vol_glance_metadata_copy_to_snapshot(self):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
db.volume_create(ctxt, {'id': 1}) db.volume_create(ctxt, {'id': 1})
db.snapshot_create(ctxt, {'id': 100, 'volume_id': 1}) snap = objects.Snapshot(ctxt, volume_id=1)
snap.create()
db.volume_glance_metadata_create(ctxt, 1, 'key1', 'value1') db.volume_glance_metadata_create(ctxt, 1, 'key1', 'value1')
db.volume_glance_metadata_copy_to_snapshot(ctxt, 100, 1) db.volume_glance_metadata_copy_to_snapshot(ctxt, snap.id, 1)
expected_meta = {'snapshot_id': '100', expected_meta = {'snapshot_id': snap.id,
'key': 'key1', 'key': 'key1',
'value': 'value1'} 'value': 'value1'}
for meta in db.volume_snapshot_glance_metadata_get(ctxt, 100): for meta in db.volume_snapshot_glance_metadata_get(ctxt, snap.id):
for (key, value) in expected_meta.items(): for (key, value) in expected_meta.items():
self.assertEqual(value, meta[key]) self.assertEqual(value, meta[key])
snap.destroy()
def test_vol_glance_metadata_copy_from_volume_to_volume(self): def test_vol_glance_metadata_copy_from_volume_to_volume(self):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
@ -142,18 +146,21 @@ class VolumeGlanceMetadataTestCase(test.TestCase):
vol1 = db.volume_create(self.ctxt, {}) vol1 = db.volume_create(self.ctxt, {})
vol2 = db.volume_create(self.ctxt, {}) vol2 = db.volume_create(self.ctxt, {})
db.volume_glance_metadata_create(self.ctxt, vol1['id'], 'm1', 'v1') db.volume_glance_metadata_create(self.ctxt, vol1['id'], 'm1', 'v1')
snapshot = db.snapshot_create(self.ctxt, {'volume_id': vol1['id']}) snapshot = objects.Snapshot(self.ctxt, volume_id=vol1['id'])
db.volume_glance_metadata_copy_to_snapshot(self.ctxt, snapshot['id'], snapshot.create()
db.volume_glance_metadata_copy_to_snapshot(self.ctxt, snapshot.id,
vol1['id']) vol1['id'])
db.volume_glance_metadata_copy_to_volume(self.ctxt, vol2['id'], db.volume_glance_metadata_copy_to_volume(self.ctxt, vol2['id'],
snapshot['id']) snapshot.id)
metadata = db.volume_glance_metadata_get(self.ctxt, vol2['id']) metadata = db.volume_glance_metadata_get(self.ctxt, vol2['id'])
metadata = {m['key']: m['value'] for m in metadata} metadata = {m['key']: m['value'] for m in metadata}
self.assertEqual({'m1': 'v1'}, metadata) self.assertEqual({'m1': 'v1'}, metadata)
def test_volume_snapshot_glance_metadata_get_nonexistent(self): def test_volume_snapshot_glance_metadata_get_nonexistent(self):
vol = db.volume_create(self.ctxt, {}) vol = db.volume_create(self.ctxt, {})
snapshot = db.snapshot_create(self.ctxt, {'volume_id': vol['id']}) snapshot = objects.Snapshot(self.ctxt, volume_id=vol['id'])
snapshot.create()
self.assertRaises(exception.GlanceMetadataNotFound, self.assertRaises(exception.GlanceMetadataNotFound,
db.volume_snapshot_glance_metadata_get, db.volume_snapshot_glance_metadata_get,
self.ctxt, snapshot['id']) self.ctxt, snapshot.id)
snapshot.destroy()

View File

@ -45,17 +45,16 @@ class VolumeRpcAPITestCase(test.TestCase):
vol['status'] = "available" vol['status'] = "available"
vol['attach_status'] = "detached" vol['attach_status'] = "detached"
vol['metadata'] = {"test_key": "test_val"} vol['metadata'] = {"test_key": "test_val"}
vol['size'] = 1
volume = db.volume_create(self.context, vol) volume = db.volume_create(self.context, vol)
snpshot = { kwargs = {
'id': 1,
'volume_id': 'fake_id',
'status': "creating", 'status': "creating",
'progress': '0%', 'progress': '0%',
'volume_size': 0,
'display_name': 'fake_name', 'display_name': 'fake_name',
'display_description': 'fake_description'} 'display_description': 'fake_description'}
snapshot = db.snapshot_create(self.context, snpshot) snapshot = tests_utils.create_snapshot(self.context, vol['id'],
**kwargs)
source_group = tests_utils.create_consistencygroup( source_group = tests_utils.create_consistencygroup(
self.context, self.context,
@ -85,9 +84,7 @@ class VolumeRpcAPITestCase(test.TestCase):
group2 = objects.ConsistencyGroup.get_by_id(self.context, group2.id) group2 = objects.ConsistencyGroup.get_by_id(self.context, group2.id)
self.fake_volume = jsonutils.to_primitive(volume) self.fake_volume = jsonutils.to_primitive(volume)
self.fake_volume_metadata = volume["volume_metadata"] self.fake_volume_metadata = volume["volume_metadata"]
self.fake_snapshot = jsonutils.to_primitive(snapshot) self.fake_snapshot = snapshot
self.fake_snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context,
**snpshot)
self.fake_reservations = ["RESERVATION"] self.fake_reservations = ["RESERVATION"]
self.fake_cg = group self.fake_cg = group
self.fake_cg2 = group2 self.fake_cg2 = group2
@ -124,7 +121,7 @@ class VolumeRpcAPITestCase(test.TestCase):
if 'snapshot' in expected_msg: if 'snapshot' in expected_msg:
snapshot = expected_msg['snapshot'] snapshot = expected_msg['snapshot']
del expected_msg['snapshot'] del expected_msg['snapshot']
expected_msg['snapshot_id'] = snapshot['id'] expected_msg['snapshot_id'] = snapshot.id
expected_msg['snapshot'] = snapshot expected_msg['snapshot'] = snapshot
if 'host' in expected_msg: if 'host' in expected_msg:
del expected_msg['host'] del expected_msg['host']
@ -228,19 +225,19 @@ class VolumeRpcAPITestCase(test.TestCase):
self._test_volume_api('create_snapshot', self._test_volume_api('create_snapshot',
rpc_method='cast', rpc_method='cast',
volume=self.fake_volume, volume=self.fake_volume,
snapshot=self.fake_snapshot_obj) snapshot=self.fake_snapshot)
def test_delete_snapshot(self): def test_delete_snapshot(self):
self._test_volume_api('delete_snapshot', self._test_volume_api('delete_snapshot',
rpc_method='cast', rpc_method='cast',
snapshot=self.fake_snapshot_obj, snapshot=self.fake_snapshot,
host='fake_host', host='fake_host',
unmanage_only=False) unmanage_only=False)
def test_delete_snapshot_with_unmanage_only(self): def test_delete_snapshot_with_unmanage_only(self):
self._test_volume_api('delete_snapshot', self._test_volume_api('delete_snapshot',
rpc_method='cast', rpc_method='cast',
snapshot=self.fake_snapshot_obj, snapshot=self.fake_snapshot,
host='fake_host', host='fake_host',
unmanage_only=True) unmanage_only=True)

View File

@ -18,6 +18,7 @@
import datetime import datetime
import mock import mock
import six
from oslo_concurrency import processutils from oslo_concurrency import processutils
from oslo_config import cfg from oslo_config import cfg
@ -25,11 +26,12 @@ from oslo_config import cfg
from cinder import context from cinder import context
from cinder import exception from cinder import exception
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder import utils from cinder import utils
from cinder.volume import throttling from cinder.volume import throttling
from cinder.volume import utils as volume_utils from cinder.volume import utils as volume_utils
CONF = cfg.CONF CONF = cfg.CONF
@ -193,11 +195,19 @@ class NotifyUsageTestCase(test.TestCase):
'snapshot.test_suffix', 'snapshot.test_suffix',
mock_usage.return_value) mock_usage.return_value)
def test_usage_from_snapshot(self): @mock.patch('cinder.objects.Volume.get_by_id')
def test_usage_from_snapshot(self, volume_get_by_id):
raw_volume = {
'id': '55614621',
'availability_zone': 'nova'
}
ctxt = context.get_admin_context()
volume_obj = fake_volume.fake_volume_obj(ctxt, **raw_volume)
volume_get_by_id.return_value = volume_obj
raw_snapshot = { raw_snapshot = {
'project_id': '12b0330ec2584a', 'project_id': '12b0330ec2584a',
'user_id': '158cba1b8c2bb6008e', 'user_id': '158cba1b8c2bb6008e',
'volume': {'availability_zone': 'nova'}, 'volume': volume_obj,
'volume_id': '55614621', 'volume_id': '55614621',
'volume_size': 1, 'volume_size': 1,
'id': '343434a2', 'id': '343434a2',
@ -205,9 +215,13 @@ class NotifyUsageTestCase(test.TestCase):
'created_at': '2014-12-11T10:10:00', 'created_at': '2014-12-11T10:10:00',
'status': 'pause', 'status': 'pause',
'deleted': '', 'deleted': '',
'metadata': {'fake_snap_meta_key': 'fake_snap_meta_value'}, 'snapshot_metadata': [{'key': 'fake_snap_meta_key',
'value': 'fake_snap_meta_value'}],
'expected_attrs': ['metadata'],
} }
usage_info = volume_utils._usage_from_snapshot(raw_snapshot)
snapshot_obj = fake_snapshot.fake_snapshot_obj(ctxt, **raw_snapshot)
usage_info = volume_utils._usage_from_snapshot(snapshot_obj)
expected_snapshot = { expected_snapshot = {
'tenant_id': '12b0330ec2584a', 'tenant_id': '12b0330ec2584a',
'user_id': '158cba1b8c2bb6008e', 'user_id': '158cba1b8c2bb6008e',
@ -216,12 +230,13 @@ class NotifyUsageTestCase(test.TestCase):
'volume_size': 1, 'volume_size': 1,
'snapshot_id': '343434a2', 'snapshot_id': '343434a2',
'display_name': '11', 'display_name': '11',
'created_at': '2014-12-11T10:10:00', 'created_at': 'DONTCARE',
'status': 'pause', 'status': 'pause',
'deleted': '', 'deleted': '',
'metadata': "{'fake_snap_meta_key': 'fake_snap_meta_value'}", 'metadata': six.text_type({'fake_snap_meta_key':
u'fake_snap_meta_value'}),
} }
self.assertEqual(expected_snapshot, usage_info) self.assertDictMatch(expected_snapshot, usage_info)
@mock.patch('cinder.db.volume_glance_metadata_get') @mock.patch('cinder.db.volume_glance_metadata_get')
@mock.patch('cinder.db.volume_attachment_get_used_by_volume_id') @mock.patch('cinder.db.volume_attachment_get_used_by_volume_id')

View File

@ -88,18 +88,20 @@ def create_snapshot(ctxt,
display_name='test_snapshot', display_name='test_snapshot',
display_description='this is a test snapshot', display_description='this is a test snapshot',
cgsnapshot_id = None, cgsnapshot_id = None,
status='creating'): status='creating',
**kwargs):
vol = db.volume_get(ctxt, volume_id) vol = db.volume_get(ctxt, volume_id)
snap = {} snap = objects.Snapshot(ctxt)
snap['volume_id'] = volume_id snap.volume_id = volume_id
snap['user_id'] = ctxt.user_id snap.user_id = ctxt.user_id or 'fake_user_id'
snap['project_id'] = ctxt.project_id snap.project_id = ctxt.project_id or 'fake_project_id'
snap['status'] = status snap.status = status
snap['volume_size'] = vol['size'] snap.volume_size = vol['size']
snap['display_name'] = display_name snap.display_name = display_name
snap['display_description'] = display_description snap.display_description = display_description
snap['cgsnapshot_id'] = cgsnapshot_id snap.cgsnapshot_id = cgsnapshot_id
return db.snapshot_create(ctxt, snap) snap.create()
return snap
def create_consistencygroup(ctxt, def create_consistencygroup(ctxt,

View File

@ -250,10 +250,10 @@ class API(base.Base):
raise exception.InvalidInput(reason=msg) raise exception.InvalidInput(reason=msg)
if snapshot and volume_type: if snapshot and volume_type:
if volume_type['id'] != snapshot['volume_type_id']: if volume_type['id'] != snapshot.volume_type_id:
if not self._retype_is_possible(context, if not self._retype_is_possible(context,
volume_type['id'], volume_type['id'],
snapshot['volume_type_id'], snapshot.volume_type_id,
volume_type): volume_type):
msg = _("Invalid volume_type provided: %s (requested " msg = _("Invalid volume_type provided: %s (requested "
"type is not compatible; recommend omitting " "type is not compatible; recommend omitting "
@ -516,7 +516,7 @@ class API(base.Base):
# so build the resource tag manually for now. # so build the resource tag manually for now.
LOG.info(_LI("Snapshot retrieved successfully."), LOG.info(_LI("Snapshot retrieved successfully."),
resource={'type': 'snapshot', resource={'type': 'snapshot',
'id': snapshot['id']}) 'id': snapshot.id})
return snapshot return snapshot
def get_volume(self, context, volume_id): def get_volume(self, context, volume_id):
@ -933,23 +933,23 @@ class API(base.Base):
@wrap_check_policy @wrap_check_policy
def delete_snapshot(self, context, snapshot, force=False, def delete_snapshot(self, context, snapshot, force=False,
unmanage_only=False): unmanage_only=False):
if not force and snapshot['status'] not in ["available", "error"]: if not force and snapshot.status not in ["available", "error"]:
LOG.error(_LE('Unable to delete snapshot: %(snap_id)s, ' LOG.error(_LE('Unable to delete snapshot: %(snap_id)s, '
'due to invalid status. ' 'due to invalid status. '
'Status must be available or ' 'Status must be available or '
'error, not %(snap_status)s.'), 'error, not %(snap_status)s.'),
{'snap_id': snapshot['id'], {'snap_id': snapshot.id,
'snap_status': snapshot['status']}) 'snap_status': snapshot.status})
msg = _("Volume Snapshot status must be available or error.") msg = _("Volume Snapshot status must be available or error.")
raise exception.InvalidSnapshot(reason=msg) raise exception.InvalidSnapshot(reason=msg)
cgsnapshot_id = snapshot.get('cgsnapshot_id', None) cgsnapshot_id = snapshot.cgsnapshot_id
if cgsnapshot_id: if cgsnapshot_id:
msg = _('Unable to delete snapshot %s because it is part of a ' msg = _('Unable to delete snapshot %s because it is part of a '
'consistency group.') % snapshot['id'] 'consistency group.') % snapshot.id
LOG.error(msg) LOG.error(msg)
raise exception.InvalidSnapshot(reason=msg) raise exception.InvalidSnapshot(reason=msg)
snapshot_obj = self.get_snapshot(context, snapshot['id']) snapshot_obj = self.get_snapshot(context, snapshot.id)
snapshot_obj.status = 'deleting' snapshot_obj.status = 'deleting'
snapshot_obj.save() snapshot_obj.save()
@ -1105,14 +1105,14 @@ class API(base.Base):
def get_snapshot_metadata(self, context, snapshot): def get_snapshot_metadata(self, context, snapshot):
"""Get all metadata associated with a snapshot.""" """Get all metadata associated with a snapshot."""
snapshot_obj = self.get_snapshot(context, snapshot['id']) snapshot_obj = self.get_snapshot(context, snapshot.id)
LOG.info(_LI("Get snapshot metadata completed successfully."), LOG.info(_LI("Get snapshot metadata completed successfully."),
resource=snapshot) resource=snapshot)
return snapshot_obj.metadata return snapshot_obj.metadata
def delete_snapshot_metadata(self, context, snapshot, key): def delete_snapshot_metadata(self, context, snapshot, key):
"""Delete the given metadata item from a snapshot.""" """Delete the given metadata item from a snapshot."""
snapshot_obj = self.get_snapshot(context, snapshot['id']) snapshot_obj = self.get_snapshot(context, snapshot.id)
snapshot_obj.delete_metadata_key(context, key) snapshot_obj.delete_metadata_key(context, key)
LOG.info(_LI("Delete snapshot metadata completed successfully."), LOG.info(_LI("Delete snapshot metadata completed successfully."),
resource=snapshot) resource=snapshot)

View File

@ -141,12 +141,12 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
""" """
def validate_snap_size(size): def validate_snap_size(size):
if snapshot and size < snapshot['volume_size']: if snapshot and size < snapshot.volume_size:
msg = _("Volume size '%(size)s'GB cannot be smaller than" msg = _("Volume size '%(size)s'GB cannot be smaller than"
" the snapshot size %(snap_size)sGB. " " the snapshot size %(snap_size)sGB. "
"They must be >= original snapshot size.") "They must be >= original snapshot size.")
msg = msg % {'size': size, msg = msg % {'size': size,
'snap_size': snapshot['volume_size']} 'snap_size': snapshot.volume_size}
raise exception.InvalidInput(reason=msg) raise exception.InvalidInput(reason=msg)
def validate_source_size(size): def validate_source_size(size):
@ -176,7 +176,7 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
if not size and source_volume: if not size and source_volume:
size = source_volume['size'] size = source_volume['size']
elif not size and snapshot: elif not size and snapshot:
size = snapshot['volume_size'] size = snapshot.volume_size
size = utils.as_int(size) size = utils.as_int(size)
LOG.debug("Validating volume '%(size)s' using %(functors)s" % LOG.debug("Validating volume '%(size)s' using %(functors)s" %

View File

@ -721,7 +721,6 @@ class VolumeManager(manager.SchedulerDependentManager):
self._notify_about_snapshot_usage(context, snapshot, "create.end") self._notify_about_snapshot_usage(context, snapshot, "create.end")
LOG.info(_LI("Create snapshot completed successfully"), LOG.info(_LI("Create snapshot completed successfully"),
resource=snapshot) resource=snapshot)
return snapshot.id
@locked_snapshot_operation @locked_snapshot_operation
def delete_snapshot(self, context, snapshot, unmanage_only=False): def delete_snapshot(self, context, snapshot, unmanage_only=False):
@ -730,8 +729,7 @@ class VolumeManager(manager.SchedulerDependentManager):
snapshot._context = context snapshot._context = context
project_id = snapshot.project_id project_id = snapshot.project_id
self._notify_about_snapshot_usage( self._notify_about_snapshot_usage(context, snapshot, "delete.start")
context, snapshot, "delete.start")
try: try:
# NOTE(flaper87): Verify the driver is enabled # NOTE(flaper87): Verify the driver is enabled
@ -769,11 +767,9 @@ class VolumeManager(manager.SchedulerDependentManager):
'gigabytes': -snapshot.volume_size, 'gigabytes': -snapshot.volume_size,
} }
volume_ref = self.db.volume_get(context, snapshot.volume_id) volume_ref = self.db.volume_get(context, snapshot.volume_id)
QUOTAS.add_volume_type_opts(context, QUOTAS.add_volume_type_opts(context, reserve_opts,
reserve_opts,
volume_ref.get('volume_type_id')) volume_ref.get('volume_type_id'))
reservations = QUOTAS.reserve(context, reservations = QUOTAS.reserve(context, project_id=project_id,
project_id=project_id,
**reserve_opts) **reserve_opts)
except Exception: except Exception:
reservations = None reservations = None
@ -788,7 +784,6 @@ class VolumeManager(manager.SchedulerDependentManager):
QUOTAS.commit(context, reservations, project_id=project_id) QUOTAS.commit(context, reservations, project_id=project_id)
LOG.info(_LI("Delete snapshot completed successfully"), LOG.info(_LI("Delete snapshot completed successfully"),
resource=snapshot) resource=snapshot)
return True
def attach_volume(self, context, volume_id, instance_uuid, host_name, def attach_volume(self, context, volume_id, instance_uuid, host_name,
mountpoint, mode): mountpoint, mode):
@ -2152,7 +2147,7 @@ class VolumeManager(manager.SchedulerDependentManager):
"not in a valid state. Valid states are: " "not in a valid state. Valid states are: "
"%(valid)s.") % "%(valid)s.") %
{'group': group.id, {'group': group.id,
'snap': snap['id'], 'snap': snap.id,
'valid': VALID_CREATE_CG_SRC_SNAP_STATUS}) 'valid': VALID_CREATE_CG_SRC_SNAP_STATUS})
raise exception.InvalidConsistencyGroup(reason=msg) raise exception.InvalidConsistencyGroup(reason=msg)
@ -2268,7 +2263,7 @@ class VolumeManager(manager.SchedulerDependentManager):
sorted_snapshots = [] sorted_snapshots = []
for vol in volumes: for vol in volumes:
found_snaps = filter( found_snaps = filter(
lambda snap: snap['id'] == vol['snapshot_id'], snapshots) lambda snap: snap.id == vol['snapshot_id'], snapshots)
if not found_snaps: if not found_snaps:
LOG.error(_LE("Source snapshot cannot be found for target " LOG.error(_LE("Source snapshot cannot be found for target "
"volume %(volume_id)s."), "volume %(volume_id)s."),

View File

@ -139,19 +139,19 @@ def notify_about_backup_usage(context, backup, event_suffix,
usage_info) usage_info)
def _usage_from_snapshot(snapshot_ref, **extra_usage_info): def _usage_from_snapshot(snapshot, **extra_usage_info):
usage_info = { usage_info = {
'tenant_id': snapshot_ref['project_id'], 'tenant_id': snapshot.project_id,
'user_id': snapshot_ref['user_id'], 'user_id': snapshot.user_id,
'availability_zone': snapshot_ref['volume']['availability_zone'], 'availability_zone': snapshot.volume['availability_zone'],
'volume_id': snapshot_ref['volume_id'], 'volume_id': snapshot.volume_id,
'volume_size': snapshot_ref['volume_size'], 'volume_size': snapshot.volume_size,
'snapshot_id': snapshot_ref['id'], 'snapshot_id': snapshot.id,
'display_name': snapshot_ref['display_name'], 'display_name': snapshot.display_name,
'created_at': str(snapshot_ref['created_at']), 'created_at': str(snapshot.created_at),
'status': snapshot_ref['status'], 'status': snapshot.status,
'deleted': null_safe_str(snapshot_ref['deleted']), 'deleted': null_safe_str(snapshot.deleted),
'metadata': null_safe_str(snapshot_ref.get('metadata')), 'metadata': null_safe_str(snapshot.metadata),
} }
usage_info.update(extra_usage_info) usage_info.update(extra_usage_info)