From b3f37476546d6170368138c6fe1e9bb176536ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dulko?= Date: Thu, 22 Oct 2015 18:25:22 +0200 Subject: [PATCH] Add backref relationships to ConsistencyGroup obj ConsistencyGroup object was missing relationships that were defined on the SQLAlchemy model as backrefs. This includes volumes and cgsnapshots fields. This commit adds fields representing these relationships. Change-Id: Ia74997ddfed1e472874b6892c2fcaa208b7a9a3c Partial-Bug: 1509012 --- cinder/objects/__init__.py | 2 +- cinder/objects/consistencygroup.py | 64 ++++++++++++++++++- cinder/tests/unit/fake_consistencygroup.py | 1 + .../unit/objects/test_consistencygroup.py | 61 ++++++++++++++++++ cinder/tests/unit/objects/test_objects.py | 2 +- 5 files changed, 126 insertions(+), 4 deletions(-) diff --git a/cinder/objects/__init__.py b/cinder/objects/__init__.py index f8c2ba4897c..10367843ae1 100644 --- a/cinder/objects/__init__.py +++ b/cinder/objects/__init__.py @@ -25,8 +25,8 @@ def register_all(): # function in order for it to be registered by services that may # need to receive it via RPC. __import__('cinder.objects.backup') - __import__('cinder.objects.consistencygroup') __import__('cinder.objects.cgsnapshot') + __import__('cinder.objects.consistencygroup') __import__('cinder.objects.service') __import__('cinder.objects.snapshot') __import__('cinder.objects.volume') diff --git a/cinder/objects/consistencygroup.py b/cinder/objects/consistencygroup.py index a252c7f880e..1c16fbc6e2f 100644 --- a/cinder/objects/consistencygroup.py +++ b/cinder/objects/consistencygroup.py @@ -19,11 +19,15 @@ from cinder import objects from cinder.objects import base from oslo_versionedobjects import fields +OPTIONAL_FIELDS = ['cgsnapshots', 'volumes'] + @base.CinderObjectRegistry.register class ConsistencyGroup(base.CinderPersistentObject, base.CinderObject, base.CinderObjectDictCompat): - VERSION = '1.0' + # Version 1.0: Initial version + # Version 1.1: Added cgsnapshots and volumes relationships + VERSION = '1.1' fields = { 'id': fields.UUIDField(), @@ -37,14 +41,35 @@ class ConsistencyGroup(base.CinderPersistentObject, base.CinderObject, 'status': fields.StringField(nullable=True), 'cgsnapshot_id': fields.UUIDField(nullable=True), 'source_cgid': fields.UUIDField(nullable=True), + 'cgsnapshots': fields.ObjectField('CGSnapshotList', nullable=True), + 'volumes': fields.ObjectField('VolumeList', nullable=True), } @staticmethod - def _from_db_object(context, consistencygroup, db_consistencygroup): + def _from_db_object(context, consistencygroup, db_consistencygroup, + expected_attrs=None): + if expected_attrs is None: + expected_attrs = [] for name, field in consistencygroup.fields.items(): + if name in OPTIONAL_FIELDS: + continue value = db_consistencygroup.get(name) setattr(consistencygroup, name, value) + if 'cgsnapshots' in expected_attrs: + cgsnapshots = base.obj_make_list( + context, objects.CGSnapshotsList(context), + objects.CGSnapshot, + db_consistencygroup['cgsnapshots']) + consistencygroup.cgsnapshots = cgsnapshots + + if 'volumes' in expected_attrs: + volumes = base.obj_make_list( + context, objects.VolumeList(context), + objects.Volume, + db_consistencygroup['volumes']) + consistencygroup.cgsnapshots = volumes + consistencygroup._context = context consistencygroup.obj_reset_changes() return consistencygroup @@ -55,14 +80,49 @@ class ConsistencyGroup(base.CinderPersistentObject, base.CinderObject, raise exception.ObjectActionError(action='create', reason=_('already_created')) updates = self.cinder_obj_get_changes() + + if 'cgsnapshots' in updates: + raise exception.ObjectActionError(action='create', + reason=_('cgsnapshots assigned')) + + if 'volumes' in updates: + raise exception.ObjectActionError(action='create', + reason=_('volumes assigned')) + db_consistencygroups = db.consistencygroup_create(self._context, updates) self._from_db_object(self._context, self, db_consistencygroups) + def obj_load_attr(self, attrname): + if attrname not in OPTIONAL_FIELDS: + raise exception.ObjectActionError( + action='obj_load_attr', + reason=_('attribute %s not lazy-loadable') % attrname) + if not self._context: + raise exception.OrphanedObjectError(method='obj_load_attr', + objtype=self.obj_name()) + + if attrname == 'cgsnapshots': + self.cgsnapshots = objects.CGSnapshotList.get_all_by_group( + self._context, self.id) + + if attrname == 'volumes': + self.volumes = objects.VolumeList.get_all_by_group(self._context, + self.id) + + self.obj_reset_changes(fields=[attrname]) + @base.remotable def save(self): updates = self.cinder_obj_get_changes() if updates: + if 'cgsnapshots' in updates: + raise exception.ObjectActionError( + action='save', reason=_('cgsnapshots changed')) + if 'volumes' in updates: + raise exception.ObjectActionError( + action='save', reason=_('volumes changed')) + db.consistencygroup_update(self._context, self.id, updates) self.obj_reset_changes() diff --git a/cinder/tests/unit/fake_consistencygroup.py b/cinder/tests/unit/fake_consistencygroup.py index 042321e0a83..280959c308b 100644 --- a/cinder/tests/unit/fake_consistencygroup.py +++ b/cinder/tests/unit/fake_consistencygroup.py @@ -23,6 +23,7 @@ def fake_db_consistencygroup(**updates): 'user_id': '2', 'project_id': '3', 'host': 'FakeHost', + 'volumes': [], } for name, field in objects.ConsistencyGroup.fields.items(): if name in db_values: diff --git a/cinder/tests/unit/objects/test_consistencygroup.py b/cinder/tests/unit/objects/test_consistencygroup.py index 9c66bb9cfaf..d4a5e1ffa12 100644 --- a/cinder/tests/unit/objects/test_consistencygroup.py +++ b/cinder/tests/unit/objects/test_consistencygroup.py @@ -32,6 +32,16 @@ fake_consistencygroup = { 'source_cgid': None, } +fake_cgsnapshot = { + 'id': '1', + 'user_id': 'fake_user_id', + 'project_id': 'fake_project_id', + 'name': 'fake_name', + 'description': 'fake_description', + 'status': 'creating', + 'consistencygroup_id': 'fake_id', +} + class TestConsistencyGroup(test_objects.BaseObjectsTestCase): @@ -74,6 +84,57 @@ class TestConsistencyGroup(test_objects.BaseObjectsTestCase): consistencygroup.id, {'status': 'active'}) + def test_save_with_cgsnapshots(self): + consistencygroup = objects.ConsistencyGroup._from_db_object( + self.context, objects.ConsistencyGroup(), fake_consistencygroup) + cgsnapshots_objs = [objects.CGSnapshot(context=self.context, id=i) + for i in [3, 4, 5]] + cgsnapshots = objects.CGSnapshotList(objects=cgsnapshots_objs) + consistencygroup.name = 'foobar' + consistencygroup.cgsnapshots = cgsnapshots + self.assertEqual({'name': 'foobar', + 'cgsnapshots': cgsnapshots}, + consistencygroup.obj_get_changes()) + self.assertRaises(exception.ObjectActionError, consistencygroup.save) + + def test_save_with_volumes(self): + consistencygroup = objects.ConsistencyGroup._from_db_object( + self.context, objects.ConsistencyGroup(), fake_consistencygroup) + volumes_objs = [objects.Volume(context=self.context, id=i) + for i in [3, 4, 5]] + volumes = objects.VolumeList(objects=volumes_objs) + consistencygroup.name = 'foobar' + consistencygroup.volumes = volumes + self.assertEqual({'name': 'foobar', + 'volumes': volumes}, + consistencygroup.obj_get_changes()) + self.assertRaises(exception.ObjectActionError, consistencygroup.save) + + @mock.patch('cinder.objects.cgsnapshot.CGSnapshotList.get_all_by_group') + @mock.patch('cinder.objects.volume.VolumeList.get_all_by_group') + def test_obj_load_attr(self, mock_vol_get_all_by_group, + mock_cgsnap_get_all_by_group): + consistencygroup = objects.ConsistencyGroup._from_db_object( + self.context, objects.ConsistencyGroup(), fake_consistencygroup) + # Test cgsnapshots lazy-loaded field + cgsnapshots_objs = [objects.CGSnapshot(context=self.context, id=i) + for i in [3, 4, 5]] + cgsnapshots = objects.CGSnapshotList(context=self.context, + objects=cgsnapshots_objs) + mock_cgsnap_get_all_by_group.return_value = cgsnapshots + self.assertEqual(cgsnapshots, consistencygroup.cgsnapshots) + mock_cgsnap_get_all_by_group.assert_called_once_with( + self.context, consistencygroup.id) + + # Test volumes lazy-loaded field + volume_objs = [objects.Volume(context=self.context, id=i) + for i in [3, 4, 5]] + volumes = objects.VolumeList(context=self.context, objects=volume_objs) + mock_vol_get_all_by_group.return_value = volumes + self.assertEqual(volumes, consistencygroup.volumes) + 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): consistencygroup = objects.ConsistencyGroup(context=self.context, diff --git a/cinder/tests/unit/objects/test_objects.py b/cinder/tests/unit/objects/test_objects.py index 1348cb633d6..bf58eaf68f0 100644 --- a/cinder/tests/unit/objects/test_objects.py +++ b/cinder/tests/unit/objects/test_objects.py @@ -26,7 +26,7 @@ object_data = { 'BackupList': '1.0-24591dabe26d920ce0756fe64cd5f3aa', 'CGSnapshot': '1.0-190da2a2aa9457edc771d888f7d225c4', 'CGSnapshotList': '1.0-e8c3f4078cd0ee23487b34d173eec776', - 'ConsistencyGroup': '1.0-b9bad093daee0b259edddb3993c60c31', + 'ConsistencyGroup': '1.1-8d8b867a67c1bd6e9f840bcf5e375dbb', 'ConsistencyGroupList': '1.0-09d0aad5491e762ecfdf66bef02ceb8d', 'Service': '1.0-64baeb4911dbab1153064dd1c87edb9f', 'ServiceList': '1.0-d242d3384b68e5a5a534e090ff1d5161',