]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
CGSnapshot Object
authorroot <daniel.tadrzak@intel.com>
Wed, 24 Jun 2015 10:32:29 +0000 (12:32 +0200)
committerSzymon Wroblewski <szymon.wroblewski@intel.com>
Mon, 19 Oct 2015 12:37:39 +0000 (14:37 +0200)
This patch adds VersionedObjects abstraction layer to CGSnapshots.

Co-Authored-By: Szymon Wroblewski <szymon.wroblewski@intel.com>
Co-Authored-By: Michal Dulko <michal.dulko@intel.com>
Partial-Implements: blueprint cinder-objects
Change-Id: Ie4cdd1ffae15a93bff756ad278ca680f9f420748

13 files changed:
cinder/api/contrib/cgsnapshots.py
cinder/api/views/cgsnapshots.py
cinder/consistencygroup/api.py
cinder/objects/__init__.py
cinder/objects/cgsnapshot.py [new file with mode: 0644]
cinder/tests/unit/objects/test_cgsnapshot.py [new file with mode: 0644]
cinder/tests/unit/test_volume.py
cinder/tests/unit/test_volume_rpcapi.py
cinder/tests/unit/utils.py
cinder/volume/manager.py
cinder/volume/rpcapi.py
cinder/volume/utils.py
tools/lintstack.py

index 16ebf991790b84bcd226158740091329504537b3..752f5e4b19839552d7bd1c16bf63b46a5cbc6315 100644 (file)
@@ -187,9 +187,7 @@ class CgsnapshotsController(wsgi.Controller):
         except exception.CgSnapshotNotFound as error:
             raise exc.HTTPNotFound(explanation=error.msg)
 
-        retval = self._view_builder.summary(
-            req,
-            dict(new_cgsnapshot))
+        retval = self._view_builder.summary(req, new_cgsnapshot)
 
         return retval
 
index b8b7eddceef81d22bb8bd3656ead78136c96a061..d8f92fcb37ae8b96a95538037175842211442777 100644 (file)
@@ -42,8 +42,8 @@ class ViewBuilder(common.ViewBuilder):
         """Generic, non-detailed view of a cgsnapshot."""
         return {
             'cgsnapshot': {
-                'id': cgsnapshot['id'],
-                'name': cgsnapshot['name']
+                'id': cgsnapshot.id,
+                'name': cgsnapshot.name
             }
         }
 
@@ -51,12 +51,12 @@ class ViewBuilder(common.ViewBuilder):
         """Detailed view of a single cgsnapshot."""
         return {
             'cgsnapshot': {
-                'id': cgsnapshot.get('id'),
-                'consistencygroup_id': cgsnapshot.get('consistencygroup_id'),
-                'status': cgsnapshot.get('status'),
-                'created_at': cgsnapshot.get('created_at'),
-                'name': cgsnapshot.get('name'),
-                'description': cgsnapshot.get('description')
+                'id': cgsnapshot.id,
+                'consistencygroup_id': cgsnapshot.consistencygroup_id,
+                'status': cgsnapshot.status,
+                'created_at': cgsnapshot.created_at,
+                'name': cgsnapshot.name,
+                'description': cgsnapshot.description
             }
         }
 
index 5df29bf42d38a84f3d3fdd77561bf884a25aaa6b..3539df8ad2b899f75cf0ba04f3355f91f62cbab1 100644 (file)
@@ -168,15 +168,16 @@ class API(base.Base):
         orig_cg = None
         if cgsnapshot_id:
             try:
-                cgsnapshot = self.db.cgsnapshot_get(context, cgsnapshot_id)
+                cgsnapshot = objects.CGSnapshot.get_by_id(context,
+                                                          cgsnapshot_id)
             except exception.CgSnapshotNotFound:
                 with excutils.save_and_reraise_exception():
                     LOG.error(_LE("CG snapshot %(cgsnap)s not found when "
                                   "creating consistency group %(cg)s from "
                                   "source."),
                               {'cg': name, 'cgsnap': cgsnapshot_id})
-            orig_cg = objects.ConsistencyGroup.get_by_id(
-                context, cgsnapshot['consistencygroup_id'])
+            else:
+                orig_cg = cgsnapshot.consistencygroup
 
         source_cg = None
         if source_cgid:
@@ -238,7 +239,7 @@ class API(base.Base):
     def _create_cg_from_cgsnapshot(self, context, group, cgsnapshot):
         try:
             snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
-                context, cgsnapshot['id'])
+                context, cgsnapshot.id)
 
             if not snapshots:
                 msg = _("Cgsnahost is empty. No consistency group "
@@ -274,7 +275,7 @@ class API(base.Base):
                                       "creating consistency group %(group)s "
                                       "from cgsnapshot %(cgsnap)s."),
                                   {'group': group.id,
-                                   'cgsnap': cgsnapshot['id']})
+                                   'cgsnap': cgsnapshot.id})
         except Exception:
             with excutils.save_and_reraise_exception():
                 try:
@@ -284,7 +285,7 @@ class API(base.Base):
                                   "group %(group)s from cgsnapshot "
                                   "%(cgsnap)s."),
                               {'group': group.id,
-                               'cgsnap': cgsnapshot['id']})
+                               'cgsnap': cgsnapshot.id})
 
         volumes = self.db.volume_get_all_by_group(context,
                                                   group.id)
@@ -444,10 +445,9 @@ class API(base.Base):
                     "but current status is: %s") % group.status
             raise exception.InvalidConsistencyGroup(reason=msg)
 
-        cgsnaps = self.db.cgsnapshot_get_all_by_group(
-            context.elevated(),
-            group.id)
-        if cgsnaps:
+        cgsnapshots = objects.CGSnapshotList.get_all_by_group(
+            context.elevated(), group.id)
+        if cgsnapshots:
             msg = _("Consistency group %s still has dependent "
                     "cgsnapshots.") % group.id
             LOG.error(msg)
@@ -709,14 +709,12 @@ class API(base.Base):
                 context, context.project_id)
         return groups
 
-    def create_cgsnapshot(self, context,
-                          group, name,
-                          description):
+    def create_cgsnapshot(self, context, group, name, description):
         return self._create_cgsnapshot(context, group, name, description)
 
     def _create_cgsnapshot(self, context,
                            group, name, description):
-        options = {'consistencygroup_id': group['id'],
+        options = {'consistencygroup_id': group.id,
                    'user_id': context.user_id,
                    'project_id': context.project_id,
                    'status': "creating",
@@ -724,65 +722,63 @@ class API(base.Base):
                    'description': description}
 
         try:
-            cgsnapshot = self.db.cgsnapshot_create(context, options)
-            cgsnapshot_id = cgsnapshot['id']
+            cgsnapshot = objects.CGSnapshot(context, **options)
+            cgsnapshot.create()
+            cgsnapshot_id = cgsnapshot.id
 
             volumes = self.db.volume_get_all_by_group(
                 context.elevated(),
-                cgsnapshot['consistencygroup_id'])
+                cgsnapshot.consistencygroup_id)
 
             if not volumes:
                 msg = _("Consistency group is empty. No cgsnapshot "
                         "will be created.")
                 raise exception.InvalidConsistencyGroup(reason=msg)
 
-            snap_name = cgsnapshot['name']
-            snap_desc = cgsnapshot['description']
+            snap_name = cgsnapshot.name
+            snap_desc = cgsnapshot.description
             self.volume_api.create_snapshots_in_db(
                 context, volumes, snap_name, snap_desc, True, cgsnapshot_id)
 
         except Exception:
             with excutils.save_and_reraise_exception():
                 try:
-                    self.db.cgsnapshot_destroy(context, cgsnapshot_id)
+                    cgsnapshot.destroy()
                 finally:
                     LOG.error(_LE("Error occurred when creating cgsnapshot"
                                   " %s."), cgsnapshot_id)
 
-        self.volume_rpcapi.create_cgsnapshot(context, group, cgsnapshot)
+        self.volume_rpcapi.create_cgsnapshot(context, cgsnapshot)
 
         return cgsnapshot
 
     def delete_cgsnapshot(self, context, cgsnapshot, force=False):
-        if cgsnapshot['status'] not in ["available", "error"]:
+        if cgsnapshot.status not in ["available", "error"]:
             msg = _("Cgsnapshot status must be available or error")
             raise exception.InvalidCgSnapshot(reason=msg)
-        self.db.cgsnapshot_update(context, cgsnapshot['id'],
-                                  {'status': 'deleting'})
-        group = objects.ConsistencyGroup.get_by_id(context, cgsnapshot[
-            'consistencygroup_id'])
-        self.volume_rpcapi.delete_cgsnapshot(context.elevated(), cgsnapshot,
-                                             group.host)
+        cgsnapshot.update({'status': 'deleting'})
+        cgsnapshot.save()
+        self.volume_rpcapi.delete_cgsnapshot(context.elevated(), cgsnapshot)
 
     def update_cgsnapshot(self, context, cgsnapshot, fields):
-        self.db.cgsnapshot_update(context, cgsnapshot['id'], fields)
+        cgsnapshot.update(fields)
+        cgsnapshot.save()
 
     def get_cgsnapshot(self, context, cgsnapshot_id):
         check_policy(context, 'get_cgsnapshot')
-        rv = self.db.cgsnapshot_get(context, cgsnapshot_id)
-        return dict(rv)
+        cgsnapshots = objects.CGSnapshot.get_by_id(context, cgsnapshot_id)
+        return cgsnapshots
 
     def get_all_cgsnapshots(self, context, search_opts=None):
         check_policy(context, 'get_all_cgsnapshots')
 
         search_opts = search_opts or {}
 
-        if (context.is_admin and 'all_tenants' in search_opts):
+        if context.is_admin and 'all_tenants' in search_opts:
             # Need to remove all_tenants to pass the filtering below.
             del search_opts['all_tenants']
-            cgsnapshots = self.db.cgsnapshot_get_all(context, search_opts)
+            cgsnapshots = objects.CGSnapshotList.get_all(context, search_opts)
         else:
-            cgsnapshots = self.db.cgsnapshot_get_all_by_project(
+            cgsnapshots = objects.CGSnapshotList.get_all_by_project(
                 context.elevated(), context.project_id, search_opts)
-
         return cgsnapshots
index b0b82323bd281bce46a21022b5c6dadaa95d5e46..f8c2ba4897cbd6844a5f8f485e2c16233804ffe2 100644 (file)
@@ -26,6 +26,7 @@ def register_all():
     # need to receive it via RPC.
     __import__('cinder.objects.backup')
     __import__('cinder.objects.consistencygroup')
+    __import__('cinder.objects.cgsnapshot')
     __import__('cinder.objects.service')
     __import__('cinder.objects.snapshot')
     __import__('cinder.objects.volume')
diff --git a/cinder/objects/cgsnapshot.py b/cinder/objects/cgsnapshot.py
new file mode 100644 (file)
index 0000000..1defc31
--- /dev/null
@@ -0,0 +1,158 @@
+#    Copyright 2015 Intel Corporation
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from cinder import db
+from cinder import exception
+from cinder.i18n import _
+from cinder import objects
+from cinder.objects import base
+from oslo_versionedobjects import fields
+
+OPTIONAL_FIELDS = ['consistencygroup', 'snapshots']
+
+
+@base.CinderObjectRegistry.register
+class CGSnapshot(base.CinderPersistentObject, base.CinderObject,
+                 base.CinderObjectDictCompat):
+    VERSION = '1.0'
+
+    fields = {
+        'id': fields.UUIDField(),
+        'consistencygroup_id': fields.UUIDField(nullable=True),
+        'project_id': fields.UUIDField(),
+        'user_id': fields.UUIDField(),
+        'name': fields.StringField(nullable=True),
+        'description': fields.StringField(nullable=True),
+        'status': fields.StringField(nullable=True),
+        'consistencygroup': fields.ObjectField('ConsistencyGroup',
+                                               nullable=True),
+        'snapshots': fields.ObjectField('SnapshotList', nullable=True),
+    }
+
+    @staticmethod
+    def _from_db_object(context, cgsnapshot, db_cgsnapshots,
+                        expected_attrs=None):
+        expected_attrs = expected_attrs or []
+        for name, field in cgsnapshot.fields.items():
+            if name in OPTIONAL_FIELDS:
+                continue
+            value = db_cgsnapshots.get(name)
+            setattr(cgsnapshot, name, value)
+
+        if 'consistencygroup' in expected_attrs:
+            consistencygroup = objects.ConsistencyGroup(context)
+            consistencygroup._from_db_object(context, consistencygroup,
+                                             db_cgsnapshots[
+                                                 'consistencygroup'])
+            cgsnapshot.consistencygroup = consistencygroup
+
+        if 'snapshots' in expected_attrs:
+            snapshots = base.obj_make_list(
+                context, objects.SnapshotsList(context),
+                objects.Snapshots,
+                db_cgsnapshots['snapshots'])
+            cgsnapshot.snapshots = snapshots
+
+        cgsnapshot._context = context
+        cgsnapshot.obj_reset_changes()
+        return cgsnapshot
+
+    @base.remotable_classmethod
+    def get_by_id(cls, context, id):
+        db_cgsnapshots = db.cgsnapshot_get(context, id)
+        return cls._from_db_object(context, cls(context), db_cgsnapshots)
+
+    @base.remotable
+    def create(self):
+        if self.obj_attr_is_set('id'):
+            raise exception.ObjectActionError(action='create',
+                                              reason=_('already_created'))
+        updates = self.cinder_obj_get_changes()
+
+        if 'consistencygroup' in updates:
+            raise exception.ObjectActionError(
+                action='create', reason=_('consistencygroup assigned'))
+
+        db_cgsnapshots = db.cgsnapshot_create(self._context, updates)
+        self._from_db_object(self._context, self, db_cgsnapshots)
+
+    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 == 'consistencygroup':
+            self.consistencygroup = objects.ConsistencyGroup.get_by_id(
+                self._context, self.consistencygroup_id)
+
+        if attrname == 'snapshots':
+            self.snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
+                self._context, self.id)
+
+        self.obj_reset_changes(fields=[attrname])
+
+    @base.remotable
+    def save(self):
+        updates = self.cinder_obj_get_changes()
+        if updates:
+            if 'consistencygroup' in updates:
+                raise exception.ObjectActionError(
+                    action='save', reason=_('consistencygroup changed'))
+            if 'snapshots' in updates:
+                raise exception.ObjectActionError(
+                    action='save', reason=_('snapshots changed'))
+            db.cgsnapshot_update(self._context, self.id, updates)
+            self.obj_reset_changes()
+
+    @base.remotable
+    def destroy(self):
+        with self.obj_as_admin():
+            db.cgsnapshot_destroy(self._context, self.id)
+
+
+@base.CinderObjectRegistry.register
+class CGSnapshotList(base.ObjectListBase, base.CinderObject):
+    VERSION = '1.0'
+
+    fields = {
+        'objects': fields.ListOfObjectsField('CGSnapshot')
+    }
+    child_version = {
+        '1.0': '1.0'
+    }
+
+    @base.remotable_classmethod
+    def get_all(cls, context, filters=None):
+        cgsnapshots = db.cgsnapshot_get_all(context, filters)
+        return base.obj_make_list(context, cls(context), objects.CGSnapshot,
+                                  cgsnapshots)
+
+    @base.remotable_classmethod
+    def get_all_by_project(cls, context, project_id, filters=None):
+        cgsnapshots = db.cgsnapshot_get_all_by_project(context, project_id,
+                                                       filters)
+        return base.obj_make_list(context, cls(context), objects.CGSnapshot,
+                                  cgsnapshots)
+
+    @base.remotable_classmethod
+    def get_all_by_group(cls, context, group_id, filters=None):
+        cgsnapshots = db.cgsnapshot_get_all_by_group(context, group_id,
+                                                     filters)
+        return base.obj_make_list(context, cls(context),
+                                  objects.CGSnapshot,
+                                  cgsnapshots)
diff --git a/cinder/tests/unit/objects/test_cgsnapshot.py b/cinder/tests/unit/objects/test_cgsnapshot.py
new file mode 100644 (file)
index 0000000..d722250
--- /dev/null
@@ -0,0 +1,148 @@
+#    Copyright 2015 Intel Corporation
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import mock
+
+from cinder import context
+from cinder import exception
+from cinder import objects
+from cinder.tests.unit import objects as test_objects
+from cinder.tests.unit.objects.test_consistencygroup import \
+    fake_consistencygroup
+
+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 TestCGSnapshot(test_objects.BaseObjectsTestCase):
+    def setUp(self):
+        super(TestCGSnapshot, self).setUp()
+        # NOTE (e0ne): base tests contains original RequestContext from
+        # oslo_context. We change it to our RequestContext implementation
+        # to have 'elevated' method
+        self.user_id = 123
+        self.project_id = 456
+        self.context = context.RequestContext(self.user_id, self.project_id,
+                                              is_admin=False)
+
+    @staticmethod
+    def _compare(test, db, obj):
+        for field, value in db.items():
+            test.assertEqual(db[field], getattr(obj, field))
+
+    @mock.patch('cinder.db.cgsnapshot_get',
+                return_value=fake_cgsnapshot)
+    def test_get_by_id(self, cgsnapshot_get):
+        cgsnapshot = objects.CGSnapshot.get_by_id(self.context, 1)
+        self._compare(self, fake_cgsnapshot, cgsnapshot)
+
+    @mock.patch('cinder.db.cgsnapshot_create',
+                return_value=fake_cgsnapshot)
+    def test_create(self, cgsnapshot_create):
+        fake_cgsnap = fake_cgsnapshot.copy()
+        del fake_cgsnap['id']
+        cgsnapshot = objects.CGSnapshot(context=self.context, **fake_cgsnap)
+        cgsnapshot.create()
+        self._compare(self, fake_cgsnapshot, cgsnapshot)
+
+    def test_create_with_id_except_exception(self):
+        cgsnapshot = objects.CGSnapshot(context=self.context, **{'id': 2})
+        self.assertRaises(exception.ObjectActionError, cgsnapshot.create)
+
+    @mock.patch('cinder.db.cgsnapshot_update')
+    def test_save(self, cgsnapshot_update):
+        cgsnapshot = objects.CGSnapshot._from_db_object(
+            self.context, objects.CGSnapshot(), fake_cgsnapshot)
+        cgsnapshot.status = 'active'
+        cgsnapshot.save()
+        cgsnapshot_update.assert_called_once_with(self.context, cgsnapshot.id,
+                                                  {'status': 'active'})
+
+    @mock.patch('cinder.db.consistencygroup_update',
+                return_value=fake_consistencygroup)
+    @mock.patch('cinder.db.cgsnapshot_update')
+    def test_save_with_consistencygroup(self, cgsnapshot_update,
+                                        cgsnapshot_cg_update):
+        consistencygroup = objects.ConsistencyGroup._from_db_object(
+            self.context, objects.ConsistencyGroup(), fake_consistencygroup)
+        cgsnapshot = objects.CGSnapshot._from_db_object(
+            self.context, objects.CGSnapshot(), fake_cgsnapshot)
+        cgsnapshot.name = 'foobar'
+        cgsnapshot.consistencygroup = consistencygroup
+        self.assertEqual({'name': 'foobar',
+                          'consistencygroup': consistencygroup},
+                         cgsnapshot.obj_get_changes())
+        self.assertRaises(exception.ObjectActionError, cgsnapshot.save)
+
+    @mock.patch('cinder.db.cgsnapshot_destroy')
+    def test_destroy(self, cgsnapshot_destroy):
+        cgsnapshot = objects.CGSnapshot(context=self.context, id=1)
+        cgsnapshot.destroy()
+        self.assertTrue(cgsnapshot_destroy.called)
+        admin_context = cgsnapshot_destroy.call_args[0][0]
+        self.assertTrue(admin_context.is_admin)
+
+    @mock.patch('cinder.objects.consistencygroup.ConsistencyGroup.get_by_id')
+    @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
+    def test_obj_load_attr(self, snapshotlist_get_for_cgs,
+                           consistencygroup_get_by_id):
+        cgsnapshot = objects.CGSnapshot._from_db_object(
+            self.context, objects.CGSnapshot(), fake_cgsnapshot)
+        # Test consistencygroup lazy-loaded field
+        consistencygroup = objects.ConsistencyGroup(context=self.context, id=2)
+        consistencygroup_get_by_id.return_value = consistencygroup
+        self.assertEqual(consistencygroup, cgsnapshot.consistencygroup)
+        consistencygroup_get_by_id.assert_called_once_with(
+            self.context, cgsnapshot.consistencygroup_id)
+        # Test snapshots lazy-loaded field
+        snapshots_objs = [objects.Snapshot(context=self.context, id=i)
+                          for i in [3, 4, 5]]
+        snapshots = objects.SnapshotList(context=self.context,
+                                         objects=snapshots_objs)
+        snapshotlist_get_for_cgs.return_value = snapshots
+        self.assertEqual(snapshots, cgsnapshot.snapshots)
+        snapshotlist_get_for_cgs.assert_called_once_with(
+            self.context, cgsnapshot.id)
+
+
+class TestCGSnapshotList(test_objects.BaseObjectsTestCase):
+    @mock.patch('cinder.db.cgsnapshot_get_all',
+                return_value=[fake_cgsnapshot])
+    def test_get_all(self, cgsnapshot_get_all):
+        cgsnapshots = objects.CGSnapshotList.get_all(self.context)
+        self.assertEqual(1, len(cgsnapshots))
+        TestCGSnapshot._compare(self, fake_cgsnapshot, cgsnapshots[0])
+
+    @mock.patch('cinder.db.cgsnapshot_get_all_by_project',
+                return_value=[fake_cgsnapshot])
+    def test_get_all_by_project(self, cgsnapshot_get_all_by_project):
+        cgsnapshots = objects.CGSnapshotList.get_all_by_project(
+            self.context, self.project_id)
+        self.assertEqual(1, len(cgsnapshots))
+        TestCGSnapshot._compare(self, fake_cgsnapshot, cgsnapshots[0])
+
+    @mock.patch('cinder.db.cgsnapshot_get_all_by_group',
+                return_value=[fake_cgsnapshot])
+    def test_get_all_by_group(self, cgsnapshot_get_all_by_group):
+        cgsnapshots = objects.CGSnapshotList.get_all_by_group(
+            self.context, self.project_id)
+        self.assertEqual(1, len(cgsnapshots))
+        TestCGSnapshot._compare(self, fake_cgsnapshot, cgsnapshots[0])
index fa10f492814c915ea04bd9d709d96cb1238672f6..bbc43abab07cc5b945441fb1b73b8c450bf9df19 100644 (file)
@@ -5083,7 +5083,7 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
             size=1)
         volume_id = volume['id']
         cgsnapshot_returns = self._create_cgsnapshot(group.id, volume_id)
-        cgsnapshot_id = cgsnapshot_returns[0]['id']
+        cgsnapshot = cgsnapshot_returns[0]
         snapshot_id = cgsnapshot_returns[1]['id']
 
         # Create CG from source CG snapshot.
@@ -5091,7 +5091,8 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
             self.context,
             availability_zone=CONF.storage_availability_zone,
             volume_type='type1,type2',
-            cgsnapshot_id=cgsnapshot_id)
+            cgsnapshot_id=cgsnapshot.id)
+        group2 = objects.ConsistencyGroup.get_by_id(self.context, group2.id)
         volume2 = tests_utils.create_volume(
             self.context,
             consistencygroup_id=group2.id,
@@ -5100,7 +5101,7 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         volume2_id = volume2['id']
         self.volume.create_volume(self.context, volume2_id)
         self.volume.create_consistencygroup_from_src(
-            self.context, group2, cgsnapshot_id=cgsnapshot_id)
+            self.context, group2, cgsnapshot=cgsnapshot)
         cg2 = objects.ConsistencyGroup.get_by_id(self.context, group2.id)
         expected = {
             'status': 'available',
@@ -5113,7 +5114,7 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         }
         self.assertEqual('available', cg2.status)
         self.assertEqual(group2.id, cg2['id'])
-        self.assertEqual(cgsnapshot_id, cg2['cgsnapshot_id'])
+        self.assertEqual(cgsnapshot.id, cg2['cgsnapshot_id'])
         self.assertIsNone(cg2['source_cgid'])
 
         msg = self.notifier.notifications[2]
@@ -5177,9 +5178,9 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         self.assertEqual(group.id, cg3.source_cgid)
         self.assertIsNone(cg3.cgsnapshot_id)
 
-        self.volume.delete_cgsnapshot(self.context, cgsnapshot_id)
+        self.volume.delete_cgsnapshot(self.context, cgsnapshot)
+
         self.volume.delete_consistencygroup(self.context, group)
-        self.volume.delete_consistencygroup(self.context, group3)
 
     def test_sort_snapshots(self):
         vol1 = {'id': '1', 'name': 'volume 1',
@@ -5274,15 +5275,14 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
                           self.volume._sort_source_vols,
                           volumes, [])
 
-    @staticmethod
-    def _create_cgsnapshot(group_id, volume_id, size='0'):
+    def _create_cgsnapshot(self, group_id, volume_id, size='0'):
         """Create a cgsnapshot object."""
-        cgsnap = {}
-        cgsnap['user_id'] = 'fake'
-        cgsnap['project_id'] = 'fake'
-        cgsnap['consistencygroup_id'] = group_id
-        cgsnap['status'] = "creating"
-        cgsnapshot = db.cgsnapshot_create(context.get_admin_context(), cgsnap)
+        cgsnap = objects.CGSnapshot(self.context)
+        cgsnap.user_id = 'fake'
+        cgsnap.project_id = 'fake'
+        cgsnap.consistencygroup_id = group_id
+        cgsnap.status = "creating"
+        cgsnap.create()
 
         # Create a snapshot object
         snap = objects.Snapshot(context.get_admin_context())
@@ -5291,10 +5291,10 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         snap.project_id = 'fake'
         snap.volume_id = volume_id
         snap.status = "available"
-        snap.cgsnapshot_id = cgsnapshot['id']
+        snap.cgsnapshot_id = cgsnap.id
         snap.create()
 
-        return cgsnapshot, snap
+        return cgsnap, snap
 
     @mock.patch('cinder.volume.driver.VolumeDriver.create_consistencygroup',
                 autospec=True,
@@ -5331,11 +5331,12 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
                          self.notifier.notifications)
 
         cgsnapshot_returns = self._create_cgsnapshot(group.id, volume_id)
-        cgsnapshot_id = cgsnapshot_returns[0]['id']
-        self.volume.create_cgsnapshot(self.context, group.id, cgsnapshot_id)
-        self.assertEqual(cgsnapshot_id,
-                         db.cgsnapshot_get(context.get_admin_context(),
-                                           cgsnapshot_id).id)
+        cgsnapshot = cgsnapshot_returns[0]
+        self.volume.create_cgsnapshot(self.context, cgsnapshot)
+        self.assertEqual(cgsnapshot.id,
+                         objects.CGSnapshot.get_by_id(
+                             context.get_admin_context(),
+                             cgsnapshot.id).id)
 
         if len(self.notifier.notifications) > 6:
             self.assertFalse(self.notifier.notifications[6],
@@ -5346,7 +5347,7 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         expected = {
             'created_at': 'DONTCARE',
             'name': None,
-            'cgsnapshot_id': cgsnapshot_id,
+            'cgsnapshot_id': cgsnapshot.id,
             'status': 'creating',
             'tenant_id': 'fake',
             'user_id': 'fake',
@@ -5356,6 +5357,7 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         msg = self.notifier.notifications[3]
         self.assertEqual('snapshot.create.start', msg['event_type'])
         msg = self.notifier.notifications[4]
+        expected['status'] = 'available'
         self.assertEqual('cgsnapshot.create.end', msg['event_type'])
         self.assertDictMatch(expected, msg['payload'])
         msg = self.notifier.notifications[5]
@@ -5364,7 +5366,7 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         self.assertEqual(6, len(self.notifier.notifications),
                          self.notifier.notifications)
 
-        self.volume.delete_cgsnapshot(self.context, cgsnapshot_id)
+        self.volume.delete_cgsnapshot(self.context, cgsnapshot)
 
         if len(self.notifier.notifications) > 10:
             self.assertFalse(self.notifier.notifications[10],
@@ -5376,19 +5378,20 @@ class ConsistencyGroupTestCase(BaseVolumeTestCase):
         self.assertDictMatch(expected, msg['payload'])
         msg = self.notifier.notifications[8]
         self.assertEqual('cgsnapshot.delete.end', msg['event_type'])
+        expected['status'] = 'deleted'
         self.assertDictMatch(expected, msg['payload'])
 
         self.assertEqual(10, len(self.notifier.notifications),
                          self.notifier.notifications)
 
-        cgsnap = db.cgsnapshot_get(
+        cgsnap = objects.CGSnapshot.get_by_id(
             context.get_admin_context(read_deleted='yes'),
-            cgsnapshot_id)
-        self.assertEqual('deleted', cgsnap['status'])
+            cgsnapshot.id)
+        self.assertEqual('deleted', cgsnap.status)
         self.assertRaises(exception.NotFound,
-                          db.cgsnapshot_get,
+                          objects.CGSnapshot.get_by_id,
                           self.context,
-                          cgsnapshot_id)
+                          cgsnapshot.id)
 
         self.volume.delete_consistencygroup(self.context, group)
 
index b9c57166bad23f4376d6a6279d00ec939e694a25..60adbe8b325f2320a5183d927768b4f1e75d25be 100644 (file)
@@ -64,24 +64,25 @@ class VolumeRpcAPITestCase(test.TestCase):
 
         cgsnapshot = tests_utils.create_cgsnapshot(
             self.context,
-            consistencygroup_id=source_group['id'])
+            consistencygroup_id=source_group.id)
 
         group = tests_utils.create_consistencygroup(
             self.context,
             availability_zone=CONF.storage_availability_zone,
             volume_type='type1,type2',
             host='fakehost@fakedrv#fakepool',
-            cgsnapshot_id=cgsnapshot['id'])
+            cgsnapshot_id=cgsnapshot.id)
 
         group2 = tests_utils.create_consistencygroup(
             self.context,
             availability_zone=CONF.storage_availability_zone,
             volume_type='type1,type2',
             host='fakehost@fakedrv#fakepool',
-            source_cgid=source_group['id'])
+            source_cgid=source_group.id)
 
         group = objects.ConsistencyGroup.get_by_id(self.context, group.id)
         group2 = objects.ConsistencyGroup.get_by_id(self.context, group2.id)
+        cgsnapshot = objects.CGSnapshot.get_by_id(self.context, cgsnapshot.id)
         self.fake_volume = jsonutils.to_primitive(volume)
         self.fake_volume_metadata = volume["volume_metadata"]
         self.fake_snapshot = snapshot
@@ -89,7 +90,7 @@ class VolumeRpcAPITestCase(test.TestCase):
         self.fake_cg = group
         self.fake_cg2 = group2
         self.fake_src_cg = jsonutils.to_primitive(source_group)
-        self.fake_cgsnap = jsonutils.to_primitive(cgsnapshot)
+        self.fake_cgsnap = cgsnapshot
 
     def test_serialized_volume_has_id(self):
         self.assertIn('id', self.fake_volume)
@@ -123,6 +124,11 @@ class VolumeRpcAPITestCase(test.TestCase):
             del expected_msg['snapshot']
             expected_msg['snapshot_id'] = snapshot.id
             expected_msg['snapshot'] = snapshot
+        if 'cgsnapshot' in expected_msg:
+            cgsnapshot = expected_msg['cgsnapshot']
+            if cgsnapshot:
+                cgsnapshot.consistencygroup
+                kwargs['cgsnapshot'].consistencygroup
         if 'host' in expected_msg:
             del expected_msg['host']
         if 'dest_host' in expected_msg:
@@ -136,22 +142,16 @@ class VolumeRpcAPITestCase(test.TestCase):
             del expected_msg['new_volume']
             expected_msg['new_volume_id'] = volume['id']
 
-        if 'cgsnapshot' in expected_msg:
-            cgsnapshot = expected_msg['cgsnapshot']
-            if cgsnapshot:
-                del expected_msg['cgsnapshot']
-                expected_msg['cgsnapshot_id'] = cgsnapshot['id']
-            else:
-                expected_msg['cgsnapshot_id'] = None
-
         if 'host' in kwargs:
             host = kwargs['host']
         elif 'group' in kwargs:
             host = kwargs['group']['host']
-        elif 'volume' not in kwargs and 'snapshot' in kwargs:
-            host = 'fake_host'
-        else:
+        elif 'volume' in kwargs:
             host = kwargs['volume']['host']
+        elif 'snapshot' in kwargs:
+            host = 'fake_host'
+        elif 'cgsnapshot' in kwargs:
+            host = kwargs['cgsnapshot'].consistencygroup.host
 
         target['server'] = utils.extract_host(host)
         target['topic'] = '%s.%s' % (CONF.volume_topic, host)
@@ -190,6 +190,10 @@ class VolumeRpcAPITestCase(test.TestCase):
                 expected_cg = expected_msg[kwarg].obj_to_primitive()
                 cg = value.obj_to_primitive()
                 self.assertEqual(expected_cg, cg)
+            elif isinstance(value, objects.CGSnapshot):
+                expected_cgsnapshot = expected_msg[kwarg].obj_to_primitive()
+                cgsnapshot = value.obj_to_primitive()
+                self.assertEqual(expected_cgsnapshot, cgsnapshot)
             else:
                 self.assertEqual(expected_msg[kwarg], value)
 
@@ -209,13 +213,11 @@ class VolumeRpcAPITestCase(test.TestCase):
 
     def test_create_cgsnapshot(self):
         self._test_volume_api('create_cgsnapshot', rpc_method='cast',
-                              group=self.fake_cg,
-                              cgsnapshot=self.fake_cgsnap, version='1.26')
+                              cgsnapshot=self.fake_cgsnap, version='1.31')
 
     def test_delete_cgsnapshot(self):
         self._test_volume_api('delete_cgsnapshot', rpc_method='cast',
-                              cgsnapshot=self.fake_cgsnap, host='fake_host1',
-                              version='1.18')
+                              cgsnapshot=self.fake_cgsnap, version='1.31')
 
     def test_create_volume(self):
         self._test_volume_api('create_volume',
@@ -414,7 +416,7 @@ class VolumeRpcAPITestCase(test.TestCase):
                               group=self.fake_cg,
                               cgsnapshot=self.fake_cgsnap,
                               source_cg=None,
-                              version='1.26')
+                              version='1.31')
 
     def test_create_consistencygroup_from_src_cg(self):
         self._test_volume_api('create_consistencygroup_from_src',
@@ -422,7 +424,7 @@ class VolumeRpcAPITestCase(test.TestCase):
                               group=self.fake_cg2,
                               cgsnapshot=None,
                               source_cg=self.fake_src_cg,
-                              version='1.26')
+                              version='1.31')
 
     def test_get_capabilities(self):
         self._test_volume_api('get_capabilities',
index e30455fcd5487c9eb02a4c49f589e05a0e1f25c7..6b008d9ae7e0518cfeb3dda9fd2552d7e5d269ae 100644 (file)
@@ -139,22 +139,23 @@ def create_consistencygroup(ctxt,
 
 
 def create_cgsnapshot(ctxt,
-                      name='test_cgsnap',
-                      description='this is a test cgsnap',
-                      status='available',
-                      consistencygroup_id=None,
+                      consistencygroup_id,
+                      name='test_cgsnapshot',
+                      description='this is a test cgsnapshot',
+                      status='creating',
                       **kwargs):
     """Create a cgsnapshot object in the DB."""
-    cgsnap = {}
-    cgsnap['user_id'] = ctxt.user_id
-    cgsnap['project_id'] = ctxt.project_id
-    cgsnap['status'] = status
-    cgsnap['name'] = name
-    cgsnap['description'] = description
-    cgsnap['consistencygroup_id'] = consistencygroup_id
+    cgsnap = objects.CGSnapshot(ctxt)
+    cgsnap.user_id = ctxt.user_id or 'fake_user_id'
+    cgsnap.project_id = ctxt.project_id or 'fake_project_id'
+    cgsnap.status = status
+    cgsnap.name = name
+    cgsnap.description = description
+    cgsnap.consistencygroup_id = consistencygroup_id
     for key in kwargs:
-        cgsnap[key] = kwargs[key]
-    return db.cgsnapshot_create(ctxt, cgsnap)
+        setattr(cgsnap, key, kwargs[key])
+    cgsnap.create()
+    return cgsnap
 
 
 def create_backup(ctxt,
index 75369c8f7136e41866f0fd4786436346a0dbb5af..31a2b29d6454479f4fc9b4227539cf144ab2737e 100644 (file)
@@ -191,7 +191,7 @@ def locked_snapshot_operation(f):
 class VolumeManager(manager.SchedulerDependentManager):
     """Manages attachable block storage devices."""
 
-    RPC_API_VERSION = '1.30'
+    RPC_API_VERSION = '1.31'
 
     target = messaging.Target(version=RPC_API_VERSION)
 
@@ -1966,7 +1966,7 @@ class VolumeManager(manager.SchedulerDependentManager):
 
         if not snapshots:
             snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
-                context, cgsnapshot['id'])
+                context, cgsnapshot.id)
         if snapshots:
             for snapshot in snapshots:
                 vol_utils.notify_about_snapshot_usage(
@@ -2335,41 +2335,45 @@ class VolumeManager(manager.SchedulerDependentManager):
         return group
 
     def create_consistencygroup_from_src(self, context, group,
-                                         cgsnapshot_id=None, source_cg=None):
+                                         cgsnapshot=None, source_cg=None):
         """Creates the consistency group from source.
 
         The source can be a CG snapshot or a source CG.
         """
+        source_name = None
+        snapshots = None
+        source_vols = None
         try:
             volumes = self.db.volume_get_all_by_group(context, group.id)
 
-            cgsnapshot = None
-            snapshots = None
-            if cgsnapshot_id:
+            if cgsnapshot:
                 try:
-                    cgsnapshot = self.db.cgsnapshot_get(context, cgsnapshot_id)
+                    # Check if cgsnapshot still exists
+                    cgsnapshot = objects.CGSnapshot.get_by_id(
+                        context, cgsnapshot.id)
                 except exception.CgSnapshotNotFound:
                     LOG.error(_LE("Create consistency group "
                                   "from snapshot-%(snap)s failed: "
                                   "SnapshotNotFound."),
-                              {'snap': cgsnapshot_id},
+                              {'snap': cgsnapshot.id},
                               resource={'type': 'consistency_group',
                                         'id': group.id})
                     raise
-                if cgsnapshot:
-                    snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
-                        context, cgsnapshot_id)
-                    for snap in snapshots:
-                        if (snap.status not in
-                                VALID_CREATE_CG_SRC_SNAP_STATUS):
-                            msg = (_("Cannot create consistency group "
-                                     "%(group)s because snapshot %(snap)s is "
-                                     "not in a valid state. Valid states are: "
-                                     "%(valid)s.") %
-                                   {'group': group.id,
-                                    'snap': snap['id'],
-                                    'valid': VALID_CREATE_CG_SRC_SNAP_STATUS})
-                            raise exception.InvalidConsistencyGroup(reason=msg)
+
+                source_name = _("snapshot-%s") % cgsnapshot.id
+                snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
+                    context, cgsnapshot.id)
+                for snap in snapshots:
+                    if (snap.status not in
+                            VALID_CREATE_CG_SRC_SNAP_STATUS):
+                        msg = (_("Cannot create consistency group "
+                                 "%(group)s because snapshot %(snap)s is "
+                                 "not in a valid state. Valid states are: "
+                                 "%(valid)s.") %
+                               {'group': group.id,
+                                'snap': snap['id'],
+                                'valid': VALID_CREATE_CG_SRC_SNAP_STATUS})
+                        raise exception.InvalidConsistencyGroup(reason=msg)
 
             if source_cg:
                 try:
@@ -2383,21 +2387,22 @@ class VolumeManager(manager.SchedulerDependentManager):
                               resource={'type': 'consistency_group',
                                         'id': group.id})
                     raise
-                if source_cg:
-                    source_vols = self.db.volume_get_all_by_group(
-                        context, source_cg.id)
-                    for source_vol in source_vols:
-                        if (source_vol['status'] not in
-                                VALID_CREATE_CG_SRC_CG_STATUS):
-                            msg = (_("Cannot create consistency group "
-                                     "%(group)s because source volume "
-                                     "%(source_vol)s is not in a valid "
-                                     "state. Valid states are: "
-                                     "%(valid)s.") %
-                                   {'group': group.id,
-                                    'source_vol': source_vol['id'],
-                                    'valid': VALID_CREATE_CG_SRC_CG_STATUS})
-                            raise exception.InvalidConsistencyGroup(reason=msg)
+
+                source_name = _("cg-%s") % source_cg.id
+                source_vols = self.db.volume_get_all_by_group(
+                    context, source_cg.id)
+                for source_vol in source_vols:
+                    if (source_vol['status'] not in
+                            VALID_CREATE_CG_SRC_CG_STATUS):
+                        msg = (_("Cannot create consistency group "
+                                 "%(group)s because source volume "
+                                 "%(source_vol)s is not in a valid "
+                                 "state. Valid states are: "
+                                 "%(valid)s.") %
+                               {'group': group.id,
+                                'source_vol': source_vol['id'],
+                                'valid': VALID_CREATE_CG_SRC_CG_STATUS})
+                        raise exception.InvalidConsistencyGroup(reason=msg)
 
             # Sort source snapshots so that they are in the same order as their
             # corresponding target volumes.
@@ -2434,15 +2439,9 @@ class VolumeManager(manager.SchedulerDependentManager):
             with excutils.save_and_reraise_exception():
                 group.status = 'error'
                 group.save()
-                if cgsnapshot_id:
-                    source = _("snapshot-%s") % cgsnapshot_id
-                elif source_cg:
-                    source = _("cg-%s") % source_cg.id
-                else:
-                    source = None
                 LOG.error(_LE("Create consistency group "
                               "from source %(source)s failed."),
-                          {'source': source},
+                          {'source': source_name},
                           resource={'type': 'consistency_group',
                                     'id': group.id})
                 # Update volume status to 'error' as well.
@@ -2463,10 +2462,9 @@ class VolumeManager(manager.SchedulerDependentManager):
 
         self._notify_about_consistencygroup_usage(
             context, group, "create.end")
-
         LOG.info(_LI("Create consistency group "
-                     "from snapshot-%(snap)s completed successfully."),
-                 {'snap': cgsnapshot_id},
+                     "from source-%(source)s completed successfully."),
+                 {'source': source_name},
                  resource={'type': 'consistency_group',
                            'id': group.id})
         return group
@@ -2833,33 +2831,33 @@ class VolumeManager(manager.SchedulerDependentManager):
 
         return True
 
-    def create_cgsnapshot(self, context, group, cgsnapshot_id):
+    def create_cgsnapshot(self, context, cgsnapshot):
         """Creates the cgsnapshot."""
         caller_context = context
         context = context.elevated()
-        cgsnapshot_ref = self.db.cgsnapshot_get(context, cgsnapshot_id)
-        LOG.info(_LI("Cgsnapshot %s: creating."), cgsnapshot_ref['id'])
+
+        LOG.info(_LI("Cgsnapshot %s: creating."), cgsnapshot.id)
 
         snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
-            context, cgsnapshot_id)
+            context, cgsnapshot.id)
 
         self._notify_about_cgsnapshot_usage(
-            context, cgsnapshot_ref, "create.start")
+            context, cgsnapshot, "create.start")
 
         try:
             utils.require_driver_initialized(self.driver)
 
             LOG.debug("Cgsnapshot %(cgsnap_id)s: creating.",
-                      {'cgsnap_id': cgsnapshot_id})
+                      {'cgsnap_id': cgsnapshot.id})
 
             # Pass context so that drivers that want to use it, can,
             # but it is not a requirement for all drivers.
-            cgsnapshot_ref['context'] = caller_context
+            cgsnapshot.context = caller_context
             for snapshot in snapshots:
                 snapshot.context = caller_context
 
             model_update, snapshots = \
-                self.driver.create_cgsnapshot(context, cgsnapshot_ref)
+                self.driver.create_cgsnapshot(context, cgsnapshot)
 
             if snapshots:
                 for snapshot in snapshots:
@@ -2868,7 +2866,7 @@ class VolumeManager(manager.SchedulerDependentManager):
                         update = {'status': snapshot['status']}
 
                         # TODO(thangp): Switch over to use snapshot.update()
-                        # after cgsnapshot has been switched over to objects
+                        # after cgsnapshot-objects bugs are fixed
                         self.db.snapshot_update(context, snapshot['id'],
                                                 update)
                         # If status for one snapshot is error, make sure
@@ -2879,15 +2877,14 @@ class VolumeManager(manager.SchedulerDependentManager):
             if model_update:
                 if model_update['status'] == 'error':
                     msg = (_('Error occurred when creating cgsnapshot '
-                             '%s.') % cgsnapshot_ref['id'])
+                             '%s.') % cgsnapshot.id)
                     LOG.error(msg)
                     raise exception.VolumeDriverException(message=msg)
 
         except Exception:
             with excutils.save_and_reraise_exception():
-                self.db.cgsnapshot_update(context,
-                                          cgsnapshot_ref['id'],
-                                          {'status': 'error'})
+                cgsnapshot.status = 'error'
+                cgsnapshot.save()
 
         for snapshot in snapshots:
             volume_id = snapshot['volume_id']
@@ -2905,9 +2902,8 @@ class VolumeManager(manager.SchedulerDependentManager):
                                'snapshot_id': snapshot_id})
 
                     # TODO(thangp): Switch over to use snapshot.update()
-                    # after cgsnapshot has been switched over to objects
-                    self.db.snapshot_update(context,
-                                            snapshot_id,
+                    # after cgsnapshot-objects bugs are fixed
+                    self.db.snapshot_update(context, snapshot_id,
                                             {'status': 'error'})
                     raise exception.MetadataCopyFailure(
                         reason=six.text_type(ex))
@@ -2916,52 +2912,50 @@ class VolumeManager(manager.SchedulerDependentManager):
                                     snapshot['id'], {'status': 'available',
                                                      'progress': '100%'})
 
-        self.db.cgsnapshot_update(context,
-                                  cgsnapshot_ref['id'],
-                                  {'status': 'available'})
+        cgsnapshot.status = 'available'
+        cgsnapshot.save()
 
         LOG.info(_LI("cgsnapshot %s: created successfully"),
-                 cgsnapshot_ref['id'])
+                 cgsnapshot.id)
         self._notify_about_cgsnapshot_usage(
-            context, cgsnapshot_ref, "create.end")
-        return cgsnapshot_id
+            context, cgsnapshot, "create.end")
+        return cgsnapshot
 
-    def delete_cgsnapshot(self, context, cgsnapshot_id):
+    def delete_cgsnapshot(self, context, cgsnapshot):
         """Deletes cgsnapshot."""
         caller_context = context
         context = context.elevated()
-        cgsnapshot_ref = self.db.cgsnapshot_get(context, cgsnapshot_id)
-        project_id = cgsnapshot_ref['project_id']
+        project_id = cgsnapshot.project_id
 
-        LOG.info(_LI("cgsnapshot %s: deleting"), cgsnapshot_ref['id'])
+        LOG.info(_LI("cgsnapshot %s: deleting"), cgsnapshot.id)
 
         snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
-            context, cgsnapshot_id)
+            context, cgsnapshot.id)
 
         self._notify_about_cgsnapshot_usage(
-            context, cgsnapshot_ref, "delete.start")
+            context, cgsnapshot, "delete.start")
 
         try:
             utils.require_driver_initialized(self.driver)
 
             LOG.debug("cgsnapshot %(cgsnap_id)s: deleting",
-                      {'cgsnap_id': cgsnapshot_id})
+                      {'cgsnap_id': cgsnapshot.id})
 
             # Pass context so that drivers that want to use it, can,
             # but it is not a requirement for all drivers.
-            cgsnapshot_ref['context'] = caller_context
+            cgsnapshot.context = caller_context
             for snapshot in snapshots:
                 snapshot['context'] = caller_context
 
             model_update, snapshots = \
-                self.driver.delete_cgsnapshot(context, cgsnapshot_ref)
+                self.driver.delete_cgsnapshot(context, cgsnapshot)
 
             if snapshots:
                 for snapshot in snapshots:
                     update = {'status': snapshot['status']}
 
                     # TODO(thangp): Switch over to use snapshot.update()
-                    # after cgsnapshot has been switched over to objects
+                    # after cgsnapshot-objects bugs are fixed
                     self.db.snapshot_update(context, snapshot['id'],
                                             update)
                     if snapshot['status'] in ['error_deleting', 'error'] and \
@@ -2972,18 +2966,17 @@ class VolumeManager(manager.SchedulerDependentManager):
             if model_update:
                 if model_update['status'] in ['error_deleting', 'error']:
                     msg = (_('Error occurred when deleting cgsnapshot '
-                             '%s.') % cgsnapshot_ref['id'])
+                             '%s.') % cgsnapshot.id)
                     LOG.error(msg)
                     raise exception.VolumeDriverException(message=msg)
                 else:
-                    self.db.cgsnapshot_update(context, cgsnapshot_ref['id'],
-                                              model_update)
+                    cgsnapshot.update(model_update)
+                    cgsnapshot.save()
 
         except Exception:
             with excutils.save_and_reraise_exception():
-                self.db.cgsnapshot_update(context,
-                                          cgsnapshot_ref['id'],
-                                          {'status': 'error_deleting'})
+                cgsnapshot.status = 'error_deleting'
+                cgsnapshot.save()
 
         for snapshot in snapshots:
             # Get reservations
@@ -3010,19 +3003,18 @@ class VolumeManager(manager.SchedulerDependentManager):
             self.db.volume_glance_metadata_delete_by_snapshot(context,
                                                               snapshot['id'])
 
-            # TODO(thangp): Switch over to use snapshot.destroy()
-            # after cgsnapshot has been switched over to objects
+            # TODO(thangp): Switch over to use snapshot.delete()
+            # after cgsnapshot-objects bugs are fixed
             self.db.snapshot_destroy(context, snapshot['id'])
 
             # Commit the reservations
             if reservations:
                 QUOTAS.commit(context, reservations, project_id=project_id)
 
-        self.db.cgsnapshot_destroy(context, cgsnapshot_id)
-        LOG.info(_LI("cgsnapshot %s: deleted successfully"),
-                 cgsnapshot_ref['id'])
-        self._notify_about_cgsnapshot_usage(
-            context, cgsnapshot_ref, "delete.end", snapshots)
+        cgsnapshot.destroy()
+        LOG.info(_LI("cgsnapshot %s: deleted successfully"), cgsnapshot.id)
+        self._notify_about_cgsnapshot_usage(context, cgsnapshot, "delete.end",
+                                            snapshots)
 
         return True
 
index 7a5c858af9e6c4466390716a1b54795685ea11a0..c79ebb57cb8c9bade03a83f8abcc3ebd6aa28505 100644 (file)
@@ -76,6 +76,9 @@ class VolumeAPI(object):
         1.28 - Adds manage_existing_snapshot
         1.29 - Adds get_capabilities.
         1.30 - Adds remove_export
+        1.31 - Updated: create_consistencygroup_from_src(), create_cgsnapshot()
+               and delete_cgsnapshot() to cast method only with necessary
+               args. Forwarding CGSnapshot object instead of CGSnapshot_id.
     """
 
     BASE_RPC_API_VERSION = '1.0'
@@ -85,7 +88,7 @@ class VolumeAPI(object):
         target = messaging.Target(topic=CONF.volume_topic,
                                   version=self.BASE_RPC_API_VERSION)
         serializer = objects_base.CinderObjectSerializer()
-        self.client = rpc.get_client(target, '1.30', serializer=serializer)
+        self.client = rpc.get_client(target, '1.31', serializer=serializer)
 
     def create_consistencygroup(self, ctxt, group, host):
         new_host = utils.extract_host(host)
@@ -111,25 +114,21 @@ class VolumeAPI(object):
     def create_consistencygroup_from_src(self, ctxt, group, cgsnapshot=None,
                                          source_cg=None):
         new_host = utils.extract_host(group.host)
-        cctxt = self.client.prepare(server=new_host, version='1.26')
+        cctxt = self.client.prepare(server=new_host, version='1.31')
         cctxt.cast(ctxt, 'create_consistencygroup_from_src',
                    group=group,
-                   cgsnapshot_id=cgsnapshot['id'] if cgsnapshot else None,
+                   cgsnapshot=cgsnapshot,
                    source_cg=source_cg)
 
-    def create_cgsnapshot(self, ctxt, group, cgsnapshot):
+    def create_cgsnapshot(self, ctxt, cgsnapshot):
+        host = utils.extract_host(cgsnapshot.consistencygroup.host)
+        cctxt = self.client.prepare(server=host, version='1.31')
+        cctxt.cast(ctxt, 'create_cgsnapshot', cgsnapshot=cgsnapshot)
 
-        host = utils.extract_host(group['host'])
-        cctxt = self.client.prepare(server=host, version='1.26')
-        cctxt.cast(ctxt, 'create_cgsnapshot',
-                   group=group,
-                   cgsnapshot_id=cgsnapshot['id'])
-
-    def delete_cgsnapshot(self, ctxt, cgsnapshot, host):
-        new_host = utils.extract_host(host)
-        cctxt = self.client.prepare(server=new_host, version='1.18')
-        cctxt.cast(ctxt, 'delete_cgsnapshot',
-                   cgsnapshot_id=cgsnapshot['id'])
+    def delete_cgsnapshot(self, ctxt, cgsnapshot):
+        new_host = utils.extract_host(cgsnapshot.consistencygroup.host)
+        cctxt = self.client.prepare(server=new_host, version='1.31')
+        cctxt.cast(ctxt, 'delete_cgsnapshot', cgsnapshot=cgsnapshot)
 
     def create_volume(self, ctxt, volume, host, request_spec,
                       filter_properties, allow_reschedule=True):
index 9e1e2c72fbdf5e8b178b9032ba495e02547a810e..e94ac20ecdcc8aaad87c078e3e246e63825bbfca 100644 (file)
@@ -239,15 +239,15 @@ def notify_about_consistencygroup_usage(context, group, event_suffix,
         usage_info)
 
 
-def _usage_from_cgsnapshot(cgsnapshot_ref, **kw):
+def _usage_from_cgsnapshot(cgsnapshot, **kw):
     usage_info = dict(
-        tenant_id=cgsnapshot_ref['project_id'],
-        user_id=cgsnapshot_ref['user_id'],
-        cgsnapshot_id=cgsnapshot_ref['id'],
-        name=cgsnapshot_ref['name'],
-        consistencygroup_id=cgsnapshot_ref['consistencygroup_id'],
-        created_at=cgsnapshot_ref['created_at'].isoformat(),
-        status=cgsnapshot_ref['status'])
+        tenant_id=cgsnapshot.project_id,
+        user_id=cgsnapshot.user_id,
+        cgsnapshot_id=cgsnapshot.id,
+        name=cgsnapshot.name,
+        consistencygroup_id=cgsnapshot.consistencygroup_id,
+        created_at=cgsnapshot.created_at.isoformat(),
+        status=cgsnapshot.status)
 
     usage_info.update(kw)
     return usage_info
index b181b08fc7f9bfffc7e01f0357e2a767a0dc5be6..e9a90496c4d62215413d80e6e4d3826f050672f8 100755 (executable)
@@ -65,15 +65,17 @@ objects_ignore_codes = ["E0213", "E1101", "E1102"]
 # member is created dynamically.
 objects_ignore_messages = [
     "No value passed for parameter 'id' in function call",
-    "Module 'cinder.objects' has no 'Snapshot' member",
-    "Module 'cinder.objects' has no 'SnapshotList' member",
     "Module 'cinder.objects' has no 'Backup' member",
-    "Module 'cinder.objects' has no 'BackupList' member",
-    "Module 'cinder.objects' has no 'Service' member",
-    "Module 'cinder.objects' has no 'ServiceList' member",
     "Module 'cinder.objects' has no 'BackupImport' member",
+    "Module 'cinder.objects' has no 'BackupList' member",
+    "Module 'cinder.objects' has no 'CGSnapshot' member",
+    "Module 'cinder.objects' has no 'CGSnapshotList' member",
     "Module 'cinder.objects' has no 'ConsistencyGroup' member",
     "Module 'cinder.objects' has no 'ConsistencyGroupList' member",
+    "Module 'cinder.objects' has no 'Service' member",
+    "Module 'cinder.objects' has no 'ServiceList' member",
+    "Module 'cinder.objects' has no 'Snapshot' member",
+    "Module 'cinder.objects' has no 'SnapshotList' member",
 ]
 objects_ignore_modules = ["cinder/objects/"]