]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
CG driver function should not access db
authorXing Yang <xing.yang@emc.com>
Tue, 25 Aug 2015 04:46:53 +0000 (00:46 -0400)
committerXing Yang <xing.yang@emc.com>
Wed, 11 Nov 2015 11:38:40 +0000 (06:38 -0500)
Currently the following CG driver interfaces don't pass in volumes
or snapshots to the driver. As a result, drivers have to retrieve info
from db. In this patch, these interfaces are changed so that drivers
don't have to access db.

Removing the access to db from driver CG functions will be handled by
separate patches.

* create_consistencygroup
* delete_consistencygroup
* create_cgsnapshot
* delete_cgsnapshot

Change-Id: I63287fd43927fc09dad77292ecfe561917f7bda5
Closes-Bug: #1501466

28 files changed:
cinder/tests/unit/test_dellsc.py
cinder/tests/unit/test_emc_vmax.py
cinder/tests/unit/test_emc_vnxdirect.py
cinder/tests/unit/test_emc_xtremio.py
cinder/tests/unit/test_gpfs.py
cinder/tests/unit/test_hp3par.py
cinder/tests/unit/test_hplefthand.py
cinder/tests/unit/test_ibm_xiv_ds8k.py
cinder/tests/unit/test_prophetstor_dpl.py
cinder/tests/unit/test_pure.py
cinder/tests/unit/test_storwize_svc.py
cinder/tests/unit/volume/drivers/emc/scaleio/mocks.py
cinder/volume/driver.py
cinder/volume/drivers/dell/dell_storagecenter_common.py
cinder/volume/drivers/emc/emc_cli_fc.py
cinder/volume/drivers/emc/emc_cli_iscsi.py
cinder/volume/drivers/emc/emc_vmax_fc.py
cinder/volume/drivers/emc/emc_vmax_iscsi.py
cinder/volume/drivers/emc/xtremio.py
cinder/volume/drivers/ibm/gpfs.py
cinder/volume/drivers/ibm/storwize_svc/__init__.py
cinder/volume/drivers/ibm/xiv_ds8k.py
cinder/volume/drivers/prophetstor/dplcommon.py
cinder/volume/drivers/pure.py
cinder/volume/drivers/san/hp/hp_3par_fc.py
cinder/volume/drivers/san/hp/hp_3par_iscsi.py
cinder/volume/drivers/san/hp/hp_lefthand_iscsi.py
cinder/volume/manager.py

index 10fb791d3f93d0817f4f727bb8ab467cb823a1f8..3f27de76b7232105d0acda3644f114c035628321 100644 (file)
@@ -1281,7 +1281,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
         group = {'id': 'fc8f2fec-fab2-4e34-9148-c094c913b9a3',
                  'status': 'deleted'}
         model_update, volumes = self.driver.delete_consistencygroup(context,
-                                                                    group)
+                                                                    group,
+                                                                    [])
         mock_find_replay_profile.assert_called_once_with(group['id'])
         mock_delete_replay_profile.assert_called_once_with(self.SCRPLAYPROFILE)
         mock_delete_volume.assert_called_once_with(mock_volume)
@@ -1310,7 +1311,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
         group = {'id': 'fc8f2fec-fab2-4e34-9148-c094c913b9a3',
                  'status': 'deleted'}
         model_update, volumes = self.driver.delete_consistencygroup(context,
-                                                                    group)
+                                                                    group,
+                                                                    [])
         mock_find_replay_profile.assert_called_once_with(group['id'])
         self.assertFalse(mock_delete_replay_profile.called)
         mock_delete_volume.assert_called_once_with(mock_volume)
@@ -1413,7 +1415,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
         context = {}
         cggrp = {'consistencygroup_id': 'fc8f2fec-fab2-4e34-9148-c094c913b9a3',
                  'id': '100'}
-        model_update, snapshots = self.driver.create_cgsnapshot(context, cggrp)
+        model_update, snapshots = self.driver.create_cgsnapshot(context, cggrp,
+                                                                [])
         mock_find_replay_profile.assert_called_once_with(
             cggrp['consistencygroup_id'])
         mock_snap_cg_replay.assert_called_once_with(self.SCRPLAYPROFILE,
@@ -1436,7 +1439,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.create_cgsnapshot,
                           context,
-                          cggrp)
+                          cggrp,
+                          [])
         mock_find_replay_profile.assert_called_once_with(
             cggrp['consistencygroup_id'])
 
@@ -1458,7 +1462,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.create_cgsnapshot,
                           context,
-                          cggrp)
+                          cggrp,
+                          [])
         mock_find_replay_profile.assert_called_once_with(
             cggrp['consistencygroup_id'])
         mock_snap_cg_replay.assert_called_once_with(self.SCRPLAYPROFILE,
@@ -1488,7 +1493,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
                   'id': '100',
                   'status': 'deleted'}
         model_update, snapshots = self.driver.delete_cgsnapshot(context,
-                                                                cgsnap)
+                                                                cgsnap,
+                                                                [])
         mock_find_replay_profile.assert_called_once_with(
             cgsnap['consistencygroup_id'])
         mock_delete_cg_replay.assert_called_once_with(self.SCRPLAYPROFILE,
@@ -1518,7 +1524,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
                   'id': '100',
                   'status': 'deleted'}
         model_update, snapshots = self.driver.delete_cgsnapshot(context,
-                                                                cgsnap)
+                                                                cgsnap,
+                                                                [])
         mock_find_replay_profile.assert_called_once_with(
             cgsnap['consistencygroup_id'])
 
@@ -1546,7 +1553,8 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.delete_cgsnapshot,
                           context,
-                          cgsnap)
+                          cgsnap,
+                          [])
         mock_find_replay_profile.assert_called_once_with(
             cgsnap['consistencygroup_id'])
         mock_delete_cg_replay.assert_called_once_with(self.SCRPLAYPROFILE,
index 2050375e83dab704f2c794cf918593123380dd60..021e57a75be9e52a80d8e35cb4442cb47eb3bd0a 100644 (file)
@@ -3124,7 +3124,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -3137,7 +3137,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
     def test_delete_CG_with_volumes_no_fast_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -3163,7 +3163,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage, _mock_cg, _mock_members,
             _mock_rg):
         self.driver.create_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -3176,7 +3176,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
     def test_delete_snapshot_for_CG_no_fast_success(
             self, _mock_volume_type, _mock_storage):
         self.driver.delete_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -3991,7 +3991,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -4004,7 +4004,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
     def test_delete_CG_with_volumes_fast_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -4030,7 +4030,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage, _mock_cg, _mock_members,
             _mock_rg):
         self.driver.create_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -4043,7 +4043,7 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
     def test_delete_snapshot_for_CG_no_fast_success(
             self, _mock_volume_type, _mock_storage):
         self.driver.delete_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -4464,7 +4464,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -4477,7 +4477,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
     def test_delete_CG_with_volumes_no_fast_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -4503,7 +4503,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage, _mock_cg, _mock_members,
             _mock_rg):
         self.driver.create_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -4516,7 +4516,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
     def test_delete_snapshot_for_CG_no_fast_success(
             self, _mock_volume_type, _mock_storage):
         self.driver.delete_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     def test_manage_existing_get_size(self):
         volume = {}
@@ -5215,7 +5215,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -5228,7 +5228,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
     def test_delete_CG_with_volumes_fast_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_utils.EMCVMAXUtils,
@@ -5254,7 +5254,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage, _mock_cg, _mock_members,
             _mock_rg):
         self.driver.create_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -5267,7 +5267,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
     def test_delete_snapshot_for_CG_no_fast_success(
             self, _mock_volume_type, _mock_storage):
         self.driver.delete_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     # Bug 1385450
     def test_create_clone_without_license(self):
@@ -5621,7 +5621,7 @@ class EMCV3DriverTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -5634,7 +5634,7 @@ class EMCV3DriverTestCase(test.TestCase):
     def test_delete_CG_with_volumes_v3_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         volume_types,
@@ -5713,7 +5713,7 @@ class EMCV3DriverTestCase(test.TestCase):
         provisionv3 = self.driver.common.provisionv3
         provisionv3.create_group_replica = mock.Mock(return_value=(0, None))
         self.driver.create_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
         repServ = self.conn.EnumerateInstanceNames("EMC_ReplicationService")[0]
         provisionv3.create_group_replica.assert_called_once_with(
             self.conn, repServ,
@@ -5732,7 +5732,7 @@ class EMCV3DriverTestCase(test.TestCase):
     def test_delete_cgsnapshot_v3_success(
             self, _mock_volume_type, _mock_storage):
         self.driver.delete_cgsnapshot(
-            self.data.test_ctxt, self.data.test_CG_snapshot)
+            self.data.test_ctxt, self.data.test_CG_snapshot, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -6206,7 +6206,7 @@ class EMCV2MultiPoolDriverTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -6219,7 +6219,7 @@ class EMCV2MultiPoolDriverTestCase(test.TestCase):
     def test_delete_CG_with_volumes_multi_pool_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     def _cleanup(self):
         bExists = os.path.exists(self.config_file_path)
@@ -6511,7 +6511,7 @@ class EMCV3MultiSloDriverTestCase(test.TestCase):
             self, _mock_volume_type, _mock_storage_system,
             _mock_db_volumes, _mock_members):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
@@ -6524,7 +6524,7 @@ class EMCV3MultiSloDriverTestCase(test.TestCase):
     def test_delete_CG_with_volumes_multi_slo_success(
             self, _mock_volume_type, _mock_storage_system):
         self.driver.delete_consistencygroup(
-            self.data.test_ctxt, self.data.test_CG)
+            self.data.test_ctxt, self.data.test_CG, [])
 
     def _cleanup(self):
         bExists = os.path.exists(self.config_file_path)
@@ -6804,7 +6804,8 @@ class EMCV2MultiPoolDriverMultipleEcomsTestCase(test.TestCase):
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.delete_consistencygroup,
                           self.data.test_ctxt,
-                          self.data.test_CG)
+                          self.data.test_CG,
+                          [])
 
     @mock.patch.object(
         emc_vmax_common.EMCVMAXCommon,
index cf37e66d01068dc1cc560ff9860e083d65a14026..6a8d0a677c7520c1afeb08151d5fe80031f5d600 100644 (file)
@@ -3695,7 +3695,8 @@ Time Remaining:  0 second(s)
         self.driver.db.volume_get_all_by_group.return_value =\
             self.testData.CONSISTENCY_GROUP_VOLUMES()
         self.driver.delete_consistencygroup(None,
-                                            self.testData.test_cg)
+                                            self.testData.test_cg,
+                                            [])
         expect_cmd = [
             mock.call(
                 *self.testData.DELETE_CONSISTENCYGROUP_CMD(
@@ -3716,7 +3717,7 @@ Time Remaining:  0 second(s)
             self.testData.SNAPS_IN_SNAP_GROUP())
         snapshot_obj.consistencygroup_id = cg_name
         get_all_for_cgsnapshot.return_value = [snapshot_obj]
-        self.driver.create_cgsnapshot(None, self.testData.test_cgsnapshot)
+        self.driver.create_cgsnapshot(None, self.testData.test_cgsnapshot, [])
         expect_cmd = [
             mock.call(
                 *self.testData.CREATE_CG_SNAPSHOT(
@@ -3736,7 +3737,8 @@ Time Remaining:  0 second(s)
         snapshot_obj.consistencygroup_id = cg_name
         get_all_for_cgsnapshot.return_value = [snapshot_obj]
         self.driver.delete_cgsnapshot(None,
-                                      self.testData.test_cgsnapshot)
+                                      self.testData.test_cgsnapshot,
+                                      [])
         expect_cmd = [
             mock.call(
                 *self.testData.DELETE_CG_SNAPSHOT(
index 2486843c97ca884e0e8ed29e5c62f2540a0e7bcb..f90a93c235f16ee6f1f16429be4182dc49764c23 100644 (file)
@@ -466,7 +466,7 @@ class EMCXIODriverISCSITestCase(test.TestCase):
         self.driver.db = mock.Mock()
         (self.driver.db.
          volume_get_all_by_group.return_value) = [mock.MagicMock()]
-        self.driver.create_cgsnapshot(d.context, d.cgsnapshot)
+        self.driver.create_cgsnapshot(d.context, d.cgsnapshot, [])
         snapset_name = self.driver._get_cgsnap_name(d.cgsnapshot)
         self.assertEqual(snapset_name,
                          '192eb39b6c2f420cbae33cfd117f0345192eb39b6c2f420cbae'
@@ -476,8 +476,8 @@ class EMCXIODriverISCSITestCase(test.TestCase):
                     'name': snapset_name,
                     'index': 1}
         xms_data['snapshot-sets'] = {snapset_name: snapset1, 1: snapset1}
-        self.driver.delete_cgsnapshot(d.context, d.cgsnapshot)
-        self.driver.delete_consistencygroup(d.context, d.group)
+        self.driver.delete_cgsnapshot(d.context, d.cgsnapshot, [])
+        self.driver.delete_consistencygroup(d.context, d.group, [])
         xms_data['snapshot-sets'] = {}
 
     @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
@@ -496,7 +496,7 @@ class EMCXIODriverISCSITestCase(test.TestCase):
 
         self.driver.create_consistencygroup(d.context, d.group)
         self.driver.create_volume(d.test_volume)
-        self.driver.create_cgsnapshot(d.context, d.cgsnapshot)
+        self.driver.create_cgsnapshot(d.context, d.cgsnapshot, [])
         xms_data['volumes'][2]['ancestor-vol-id'] = (xms_data['volumes'][1]
                                                      ['vol-id'])
         snapset_name = self.driver._get_cgsnap_name(d.cgsnapshot)
index e47ef0ead7597a8a2f9dea148b3b20da0a4caa21..e7de73e9af73fd64555094b743d8b2c757474152 100644 (file)
@@ -1672,7 +1672,7 @@ class GPFSDriverTestCase(test.TestCase):
         self.driver.db.volume_get_all_by_group = mock.Mock()
         self.driver.db.volume_get_all_by_group.return_value = volumes
 
-        self.driver.delete_consistencygroup(ctxt, group)
+        self.driver.delete_consistencygroup(ctxt, group, [])
         fsdev = self.driver._gpfs_device
         cgname = "consisgroup-%s" % group['id']
         cmd = ['mmunlinkfileset', fsdev, cgname, '-f']
@@ -1692,7 +1692,7 @@ class GPFSDriverTestCase(test.TestCase):
         mock_exec.side_effect = (
             processutils.ProcessExecutionError(stdout='test', stderr='test'))
         self.assertRaises(exception.VolumeBackendAPIException,
-                          self.driver.delete_consistencygroup, ctxt, group)
+                          self.driver.delete_consistencygroup, ctxt, group, [])
 
     @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.create_snapshot')
     def test_create_cgsnapshot(self, mock_create_snap):
@@ -1703,7 +1703,8 @@ class GPFSDriverTestCase(test.TestCase):
         snapshot1 = self._fake_snapshot()
         snapshots = [snapshot1]
         self.driver.db.snapshot_get_all_for_cgsnapshot.return_value = snapshots
-        model_update, snapshots = self.driver.create_cgsnapshot(ctxt, cgsnap)
+        model_update, snapshots = self.driver.create_cgsnapshot(ctxt, cgsnap,
+                                                                [])
         self.driver.create_snapshot.assert_called_once_with(snapshot1)
         self.assertEqual({'status': cgsnap['status']}, model_update)
         self.assertEqual('available', snapshot1['status'])
@@ -1718,7 +1719,8 @@ class GPFSDriverTestCase(test.TestCase):
         self.driver.db.snapshot_get_all_for_cgsnapshot = mock.Mock()
         snapshots = []
         self.driver.db.snapshot_get_all_for_cgsnapshot.return_value = snapshots
-        model_update, snapshots = self.driver.create_cgsnapshot(ctxt, cgsnap)
+        model_update, snapshots = self.driver.create_cgsnapshot(ctxt, cgsnap,
+                                                                [])
         self.assertFalse(self.driver.create_snapshot.called)
         self.assertEqual({'status': cgsnap['status']}, model_update)
         self.driver.db.snapshot_get_all_for_cgsnapshot.\
@@ -1733,7 +1735,8 @@ class GPFSDriverTestCase(test.TestCase):
         snapshot1 = self._fake_snapshot()
         snapshots = [snapshot1]
         self.driver.db.snapshot_get_all_for_cgsnapshot.return_value = snapshots
-        model_update, snapshots = self.driver.delete_cgsnapshot(ctxt, cgsnap)
+        model_update, snapshots = self.driver.delete_cgsnapshot(ctxt, cgsnap,
+                                                                [])
         self.driver.delete_snapshot.assert_called_once_with(snapshot1)
         self.assertEqual({'status': cgsnap['status']}, model_update)
         self.assertEqual('deleted', snapshot1['status'])
@@ -1748,7 +1751,8 @@ class GPFSDriverTestCase(test.TestCase):
         self.driver.db.snapshot_get_all_for_cgsnapshot = mock.Mock()
         snapshots = []
         self.driver.db.snapshot_get_all_for_cgsnapshot.return_value = snapshots
-        model_update, snapshots = self.driver.delete_cgsnapshot(ctxt, cgsnap)
+        model_update, snapshots = self.driver.delete_cgsnapshot(ctxt, cgsnap,
+                                                                [])
         self.assertFalse(self.driver.delete_snapshot.called)
         self.assertEqual({'status': cgsnap['status']}, model_update)
         self.driver.db.snapshot_get_all_for_cgsnapshot.\
index c80d8b8072964ae1a62e0ce3e06cd7c35c1d6114..5a6c01939dc21b56126f2c26384fb523498ae69d 100644 (file)
@@ -3106,7 +3106,7 @@ class HP3PARBaseDriver(object):
 
             # create a snapshot of the consistency group
             self.driver.create_cgsnapshot(context.get_admin_context(),
-                                          self.cgsnapshot)
+                                          self.cgsnapshot, [])
 
             expected = [
                 mock.call.createSnapshotOfVolumeSet(
@@ -3171,7 +3171,7 @@ class HP3PARBaseDriver(object):
             # remove the consistency group
             group.status = 'deleting'
             self.driver.delete_consistencygroup(context.get_admin_context(),
-                                                group)
+                                                group, [])
 
             expected = [
                 mock.call.deleteVolumeSet(
@@ -3391,7 +3391,7 @@ class HP3PARBaseDriver(object):
 
             # create a snapshot of the consistency group
             self.driver.create_cgsnapshot(context.get_admin_context(),
-                                          self.cgsnapshot)
+                                          self.cgsnapshot, [])
 
             expected = [
                 mock.call.createSnapshotOfVolumeSet(
@@ -3476,7 +3476,7 @@ class HP3PARBaseDriver(object):
 
             # create a snapshot of the consistency group
             self.driver.create_cgsnapshot(context.get_admin_context(),
-                                          cgsnapshot)
+                                          cgsnapshot, [])
 
             expected = [
                 mock.call.createSnapshotOfVolumeSet(
@@ -3487,7 +3487,7 @@ class HP3PARBaseDriver(object):
             # delete the snapshot of the consistency group
             cgsnapshot['status'] = 'deleting'
             self.driver.delete_cgsnapshot(context.get_admin_context(),
-                                          cgsnapshot)
+                                          cgsnapshot, [])
 
             mock_client.assert_has_calls(
                 [mock.call.getWsApiVersion()] +
index 727b1e8d565d3ceb47bab75307ea6f9f57576c7d..e1eee13dd395e222b1681f828ade1aeadf6241a6 100644 (file)
@@ -2186,7 +2186,7 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
 
             # delete the consistency group
             group.status = 'deleting'
-            cg, vols = self.driver.delete_consistencygroup(ctxt, group)
+            cg, vols = self.driver.delete_consistencygroup(ctxt, group, [])
             self.assertEqual('deleting', cg['status'])
 
     @mock.patch('hplefthandclient.version', "1.0.6")
@@ -2228,7 +2228,7 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
 
             # delete the consistency group
             group.status = 'deleting'
-            cg, vols = self.driver.delete_consistencygroup(ctxt, group)
+            cg, vols = self.driver.delete_consistencygroup(ctxt, group, [])
             self.assertEqual('deleting', cg['status'])
 
     @mock.patch('hplefthandclient.version', "1.0.6")
@@ -2274,7 +2274,7 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
 
             # delete the consistency group
             group.status = 'deleting'
-            cg, vols = self.driver.delete_consistencygroup(ctxt, group)
+            cg, vols = self.driver.delete_consistencygroup(ctxt, group, [])
             self.assertEqual('deleting', cg['status'])
 
     @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
@@ -2315,7 +2315,7 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
 
             # create the conistency group snapshot
             cgsnap, snaps = self.driver.create_cgsnapshot(
-                ctxt, self.cgsnapshot)
+                ctxt, self.cgsnapshot, [])
             self.assertEqual('available', cgsnap['status'])
 
     @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
@@ -2357,5 +2357,5 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
             # delete the consistency group snapshot
             self.cgsnapshot['status'] = 'deleting'
             cgsnap, snaps = self.driver.delete_cgsnapshot(
-                ctxt, self.cgsnapshot)
+                ctxt, self.cgsnapshot, [])
             self.assertEqual('deleting', cgsnap['status'])
index de831cb42765f97dd0dcc71a66d4a4cf3fa38987..049bc16e7c4849f145d9f3e214a757c8ceba91a2 100644 (file)
@@ -721,7 +721,7 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
 
         # Delete consistency group
         model_update, volumes = \
-            self.driver.delete_consistencygroup(ctxt, CONSISTGROUP)
+            self.driver.delete_consistencygroup(ctxt, CONSISTGROUP, [])
 
         # Verify the result
         self.assertEqual('deleted',
@@ -751,7 +751,7 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
 
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.delete_consistencygroup,
-                          ctxt, CONSISTGROUP)
+                          ctxt, CONSISTGROUP, [])
 
     def test_create_cgsnapshot(self):
         """Test that create_cgsnapshot return successfully."""
@@ -768,7 +768,7 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
 
         # Create consistency group snapshot
         model_update, snapshots = \
-            self.driver.create_cgsnapshot(ctxt, CG_SNAPSHOT)
+            self.driver.create_cgsnapshot(ctxt, CG_SNAPSHOT, [])
 
         # Verify the result
         self.assertEqual('available',
@@ -779,8 +779,8 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
                              snap['status'])
 
         # Clean the environment
-        self.driver.delete_cgsnapshot(ctxt, CG_SNAPSHOT)
-        self.driver.delete_consistencygroup(ctxt, CONSISTGROUP)
+        self.driver.delete_cgsnapshot(ctxt, CG_SNAPSHOT, [])
+        self.driver.delete_consistencygroup(ctxt, CONSISTGROUP, [])
 
     def test_create_cgsnapshot_fail_on_no_pool_space_left(self):
         """Test that create_cgsnapshot return fail when no pool space left."""
@@ -801,11 +801,11 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
 
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.create_cgsnapshot,
-                          ctxt, CG_SNAPSHOT)
+                          ctxt, CG_SNAPSHOT, [])
 
         # Clean the environment
         self.driver.volumes = None
-        self.driver.delete_consistencygroup(ctxt, CONSISTGROUP)
+        self.driver.delete_consistencygroup(ctxt, CONSISTGROUP, [])
 
     def test_delete_cgsnapshot(self):
         """Test that delete_cgsnapshot return successfully."""
@@ -821,11 +821,11 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
         self.driver.create_volume(VOLUME)
 
         # Create consistency group snapshot
-        self.driver.create_cgsnapshot(ctxt, CG_SNAPSHOT)
+        self.driver.create_cgsnapshot(ctxt, CG_SNAPSHOT, [])
 
         # Delete consistency group snapshot
         model_update, snapshots = \
-            self.driver.delete_cgsnapshot(ctxt, CG_SNAPSHOT)
+            self.driver.delete_cgsnapshot(ctxt, CG_SNAPSHOT, [])
 
         # Verify the result
         self.assertEqual('deleted',
@@ -836,7 +836,7 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
                              snap['status'])
 
         # Clean the environment
-        self.driver.delete_consistencygroup(ctxt, CONSISTGROUP)
+        self.driver.delete_consistencygroup(ctxt, CONSISTGROUP, [])
 
     def test_delete_cgsnapshot_fail_on_snapshot_not_delete(self):
         """Test delete_cgsnapshot when the snapshot cannot be deleted."""
@@ -856,11 +856,11 @@ class XIVDS8KVolumeDriverTest(test.TestCase):
         self.driver.create_volume(volume)
 
         # Create consistency group snapshot
-        self.driver.create_cgsnapshot(ctxt, CG_SNAPSHOT)
+        self.driver.create_cgsnapshot(ctxt, CG_SNAPSHOT, [])
 
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.delete_cgsnapshot,
-                          ctxt, CG_SNAPSHOT)
+                          ctxt, CG_SNAPSHOT, [])
 
     def test_update_consistencygroup_without_volumes(self):
         """Test update_consistencygroup when there are no volumes specified."""
index ada7b8125dea01bf4b21c851f4b0b72ca7dd7659..56c4060d38b0d06f06b3e5bea1b8753687417a40 100644 (file)
@@ -691,7 +691,7 @@ class TestProphetStorDPLDriver(test.TestCase):
         self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT
         self.DPL_MOCK.delete_cg.return_value = DATA_OUTPUT
         model_update, volumes = self.dpldriver.delete_consistencygroup(
-            self.context, DATA_IN_GROUP)
+            self.context, DATA_IN_GROUP, [])
         self.DPL_MOCK.delete_vg.assert_called_once_with(
             self._conver_uuid2hex(DATA_IN_GROUP['id']))
         self.DPL_MOCK.delete_vdev.assert_called_once_with(
@@ -748,7 +748,7 @@ class TestProphetStorDPLDriver(test.TestCase):
         get_all_for_cgsnapshot.return_value = [snapshot_obj]
         self.DPL_MOCK.create_vdev_snapshot.return_value = DATA_OUTPUT
         model_update, snapshots = self.dpldriver.create_cgsnapshot(
-            self.context, snapshot_obj)
+            self.context, snapshot_obj, [])
         self.assertDictMatch({'status': 'available'}, model_update)
 
     @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
@@ -759,7 +759,7 @@ class TestProphetStorDPLDriver(test.TestCase):
         get_all_for_cgsnapshot.return_value = [snapshot_obj]
         self.DPL_MOCK.delete_cgsnapshot.return_value = DATA_OUTPUT
         model_update, snapshots = self.dpldriver.delete_cgsnapshot(
-            self.context, DATA_IN_CG_SNAPSHOT)
+            self.context, DATA_IN_CG_SNAPSHOT, [])
         self.DPL_MOCK.delete_vdev_snapshot.assert_called_once_with(
             self._conver_uuid2hex(DATA_IN_CG_SNAPSHOT['consistencygroup_id']),
             self._conver_uuid2hex(DATA_IN_CG_SNAPSHOT['id']),
index 166907f72c324503aa1fe1117309186d5360fbfc..83d385d624eaba3cee77af5db2e61ecc193bff7c 100644 (file)
@@ -776,7 +776,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         self.driver.db.volume_get_all_by_group.return_value = expected_volumes
 
         model_update, volumes = \
-            self.driver.delete_consistencygroup(mock_context, mock_cgroup)
+            self.driver.delete_consistencygroup(mock_context, mock_cgroup, [])
 
         expected_name = self.driver._get_pgroup_name_from_id(mock_cgroup.id)
         self.array.destroy_pgroup.assert_called_with(expected_name)
@@ -789,7 +789,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
                 code=400,
                 text="Protection group has been destroyed."
             )
-        self.driver.delete_consistencygroup(mock_context, mock_cgroup)
+        self.driver.delete_consistencygroup(mock_context, mock_cgroup, [])
         self.array.destroy_pgroup.assert_called_with(expected_name)
         mock_delete_volume.assert_called_with(self.driver, mock_volume)
 
@@ -798,7 +798,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
                 code=400,
                 text="Protection group does not exist"
             )
-        self.driver.delete_consistencygroup(mock_context, mock_cgroup)
+        self.driver.delete_consistencygroup(mock_context, mock_cgroup, [])
         self.array.destroy_pgroup.assert_called_with(expected_name)
         mock_delete_volume.assert_called_with(self.driver, mock_volume)
 
@@ -810,7 +810,8 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         self.assertRaises(self.purestorage_module.PureHTTPError,
                           self.driver.delete_consistencygroup,
                           mock_context,
-                          mock_volume)
+                          mock_volume,
+                          [])
 
         self.array.destroy_pgroup.side_effect = \
             self.purestorage_module.PureHTTPError(
@@ -820,12 +821,13 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         self.assertRaises(self.purestorage_module.PureHTTPError,
                           self.driver.delete_consistencygroup,
                           mock_context,
-                          mock_volume)
+                          mock_volume,
+                          [])
 
         self.array.destroy_pgroup.side_effect = None
         self.assert_error_propagates(
             [self.array.destroy_pgroup],
-            self.driver.delete_consistencygroup, mock_context, mock_cgroup)
+            self.driver.delete_consistencygroup, mock_context, mock_cgroup, [])
 
     def _create_mock_cg(self):
         mock_group = mock.MagicMock()
@@ -910,7 +912,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         mock_snap_list.return_value = expected_snaps
 
         model_update, snapshots = \
-            self.driver.create_cgsnapshot(mock_context, mock_cgsnap)
+            self.driver.create_cgsnapshot(mock_context, mock_cgsnap, [])
 
         cg_id = mock_cgsnap.consistencygroup_id
         expected_pgroup_name = self.driver._get_pgroup_name_from_id(cg_id)
@@ -924,7 +926,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
 
         self.assert_error_propagates(
             [self.array.create_pgroup_snapshot],
-            self.driver.create_cgsnapshot, mock_context, mock_cgsnap)
+            self.driver.create_cgsnapshot, mock_context, mock_cgsnap, [])
 
     @mock.patch(BASE_DRIVER_OBJ + "._get_pgroup_snap_name",
                 spec=pure.PureBaseVolumeDriver._get_pgroup_snap_name)
@@ -941,7 +943,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         mock_snap_list.return_value = expected_snaps
 
         model_update, snapshots = \
-            self.driver.delete_cgsnapshot(mock_context, mock_cgsnap)
+            self.driver.delete_cgsnapshot(mock_context, mock_cgsnap, [])
 
         self.array.destroy_pgroup.assert_called_with(snap_name)
         self.assertEqual({'status': mock_cgsnap.status}, model_update)
@@ -953,7 +955,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
                 code=400,
                 text="Protection group snapshot has been destroyed."
             )
-        self.driver.delete_cgsnapshot(mock_context, mock_cgsnap)
+        self.driver.delete_cgsnapshot(mock_context, mock_cgsnap, [])
         self.array.destroy_pgroup.assert_called_with(snap_name)
 
         self.array.destroy_pgroup.side_effect = \
@@ -961,7 +963,7 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
                 code=400,
                 text="Protection group snapshot does not exist"
             )
-        self.driver.delete_cgsnapshot(mock_context, mock_cgsnap)
+        self.driver.delete_cgsnapshot(mock_context, mock_cgsnap, [])
         self.array.destroy_pgroup.assert_called_with(snap_name)
 
         self.array.destroy_pgroup.side_effect = \
@@ -972,7 +974,8 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         self.assertRaises(self.purestorage_module.PureHTTPError,
                           self.driver.delete_cgsnapshot,
                           mock_context,
-                          mock_cgsnap)
+                          mock_cgsnap,
+                          [])
 
         self.array.destroy_pgroup.side_effect = \
             self.purestorage_module.PureHTTPError(
@@ -982,13 +985,14 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase):
         self.assertRaises(self.purestorage_module.PureHTTPError,
                           self.driver.delete_cgsnapshot,
                           mock_context,
-                          mock_cgsnap)
+                          mock_cgsnap,
+                          [])
 
         self.array.destroy_pgroup.side_effect = None
 
         self.assert_error_propagates(
             [self.array.destroy_pgroup],
-            self.driver.delete_cgsnapshot, mock_context, mock_cgsnap)
+            self.driver.delete_cgsnapshot, mock_context, mock_cgsnap, [])
 
     def test_manage_existing(self):
         ref_name = 'vol1'
index b85f683aa2dfd86571e5c300d79bb9a7f1d33767..647c536afff93f718b94b557956ee65b447c799e 100644 (file)
@@ -3499,7 +3499,8 @@ class StorwizeSVCDriverTestCase(test.TestCase):
                             consistencygroup_id=cg['id'])
         cg_snapshot = self._create_cgsnapshot_in_db(cg['id'])
 
-        model_update = self.driver.create_cgsnapshot(self.ctxt, cg_snapshot)
+        model_update = self.driver.create_cgsnapshot(self.ctxt, cg_snapshot,
+                                                     [])
         self.assertEqual('available',
                          model_update[0]['status'],
                          "CGSnapshot created failed")
@@ -3507,7 +3508,7 @@ class StorwizeSVCDriverTestCase(test.TestCase):
         for snapshot in model_update[1]:
             self.assertEqual('available', snapshot['status'])
 
-        model_update = self.driver.delete_consistencygroup(self.ctxt, cg)
+        model_update = self.driver.delete_consistencygroup(self.ctxt, cg, [])
 
         self.assertEqual('deleted', model_update[0]['status'])
         for volume in model_update[1]:
index 660ff2287f52016ac665dd915ba91caba484a72b..172e457f667b61f8e4f031f81b574c5793ea4ff5 100644 (file)
@@ -65,7 +65,7 @@ class ScaleIODriver(scaleio.ScaleIODriver):
     def promote_replica(self, context, volume):
         pass
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         pass
 
     def create_consistencygroup_from_src(self, context, group, volumes,
@@ -84,10 +84,10 @@ class ScaleIODriver(scaleio.ScaleIODriver):
     def unmanage(self, volume):
         pass
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         pass
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         pass
 
 
index bb6d08e69e488e38d9a44a4703198d630799594e..ee52fad852364b48fc72bfdd614a249242fcfe1f 100644 (file)
@@ -1484,12 +1484,12 @@ class SnapshotVD(object):
 @six.add_metaclass(abc.ABCMeta)
 class ConsistencyGroupVD(object):
     @abc.abstractmethod
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         return
 
     @abc.abstractmethod
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         return
 
@@ -1499,7 +1499,7 @@ class ConsistencyGroupVD(object):
         return
 
     @abc.abstractmethod
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
         return
 
@@ -2048,7 +2048,24 @@ class VolumeDriver(ConsistencyGroupVD, TransferVD, ManageableVD, ExtendVD,
         """Disallow connection from connector for a snapshot."""
 
     def create_consistencygroup(self, context, group):
-        """Creates a consistencygroup."""
+        """Creates a consistencygroup.
+
+        :param context: the context of the caller.
+        :param group: the dictionary of the consistency group to be created.
+        :return model_update
+
+        model_update will be in this format: {'status': xxx, ......}.
+
+        If the status in model_update is 'error', the manager will throw
+        an exception and it will be caught in the try-except block in the
+        manager. If the driver throws an exception, the manager will also
+        catch it in the try-except block. The group status in the db will
+        be changed to 'error'.
+
+        For a successful operation, the driver can either build the
+        model_update and return it or return None. The group status will
+        be set to 'available'.
+        """
         raise NotImplementedError()
 
     def create_consistencygroup_from_src(self, context, group, volumes,
@@ -2071,8 +2088,8 @@ class VolumeDriver(ConsistencyGroupVD, TransferVD, ManageableVD, ExtendVD,
         cinder.db.sqlalchemy.models.Volume to be precise. It cannot be
         assigned to volumes_model_update. volumes_model_update is a list of
         dictionaries. It has to be built by the driver. An entry will be
-        in this format: ['id': xxx, 'status': xxx, ......]. model_update
-        will be in this format: ['status': xxx, ......].
+        in this format: {'id': xxx, 'status': xxx, ......}. model_update
+        will be in this format: {'status': xxx, ......}.
 
         To be consistent with other volume operations, the manager will
         assume the operation is successful if no exception is thrown by
@@ -2082,8 +2099,48 @@ class VolumeDriver(ConsistencyGroupVD, TransferVD, ManageableVD, ExtendVD,
         """
         raise NotImplementedError()
 
-    def delete_consistencygroup(self, context, group):
-        """Deletes a consistency group."""
+    def delete_consistencygroup(self, context, group, volumes):
+        """Deletes a consistency group.
+
+        :param context: the context of the caller.
+        :param group: the dictionary of the consistency group to be deleted.
+        :param volumes: a list of volume dictionaries in the group.
+        :return model_update, volumes_model_update
+
+        param volumes is retrieved directly from the db. It is a list of
+        cinder.db.sqlalchemy.models.Volume to be precise. It cannot be
+        assigned to volumes_model_update. volumes_model_update is a list of
+        dictionaries. It has to be built by the driver. An entry will be
+        in this format: {'id': xxx, 'status': xxx, ......}. model_update
+        will be in this format: {'status': xxx, ......}.
+
+        The driver should populate volumes_model_update and model_update
+        and return them.
+
+        The manager will check volumes_model_update and update db accordingly
+        for each volume. If the driver successfully deleted some volumes
+        but failed to delete others, it should set statuses of the volumes
+        accordingly so that the manager can update db correctly.
+
+        If the status in any entry of volumes_model_update is 'error_deleting'
+        or 'error', the status in model_update will be set to the same if it
+        is not already 'error_deleting' or 'error'.
+
+        If the status in model_update is 'error_deleting' or 'error', the
+        manager will raise an exception and the status of the group will be
+        set to 'error' in the db. If volumes_model_update is not returned by
+        the driver, the manager will set the status of every volume in the
+        group to 'error' in the except block.
+
+        If the driver raises an exception during the operation, it will be
+        caught by the try-except block in the manager. The statuses of the
+        group and all volumes in it will be set to 'error'.
+
+        For a successful operation, the driver can either build the
+        model_update and volumes_model_update and return them or
+        return None, None. The statuses of the group and all volumes
+        will be set to 'deleted' after the manager deletes them from db.
+        """
         raise NotImplementedError()
 
     def update_consistencygroup(self, context, group,
@@ -2114,12 +2171,92 @@ class VolumeDriver(ConsistencyGroupVD, TransferVD, ManageableVD, ExtendVD,
         """
         raise NotImplementedError()
 
-    def create_cgsnapshot(self, context, cgsnapshot):
-        """Creates a cgsnapshot."""
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
+        """Creates a cgsnapshot.
+
+        :param context: the context of the caller.
+        :param cgsnapshot: the dictionary of the cgsnapshot to be created.
+        :param snapshots: a list of snapshot dictionaries in the cgsnapshot.
+        :return model_update, snapshots_model_update
+
+        param snapshots is retrieved directly from the db. It is a list of
+        cinder.db.sqlalchemy.models.Snapshot to be precise. It cannot be
+        assigned to snapshots_model_update. snapshots_model_update is a list
+        of dictionaries. It has to be built by the driver. An entry will be
+        in this format: {'id': xxx, 'status': xxx, ......}. model_update
+        will be in this format: {'status': xxx, ......}.
+
+        The driver should populate snapshots_model_update and model_update
+        and return them.
+
+        The manager will check snapshots_model_update and update db accordingly
+        for each snapshot. If the driver successfully deleted some snapshots
+        but failed to delete others, it should set statuses of the snapshots
+        accordingly so that the manager can update db correctly.
+
+        If the status in any entry of snapshots_model_update is 'error', the
+        status in model_update will be set to the same if it is not already
+        'error'.
+
+        If the status in model_update is 'error', the manager will raise an
+        exception and the status of cgsnapshot will be set to 'error' in the
+        db. If snapshots_model_update is not returned by the driver, the
+        manager will set the status of every snapshot to 'error' in the except
+        block.
+
+        If the driver raises an exception during the operation, it will be
+        caught by the try-except block in the manager and the statuses of
+        cgsnapshot and all snapshots will be set to 'error'.
+
+        For a successful operation, the driver can either build the
+        model_update and snapshots_model_update and return them or
+        return None, None. The statuses of cgsnapshot and all snapshots
+        will be set to 'available' at the end of the manager function.
+        """
         raise NotImplementedError()
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
-        """Deletes a cgsnapshot."""
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
+        """Deletes a cgsnapshot.
+
+        :param context: the context of the caller.
+        :param cgsnapshot: the dictionary of the cgsnapshot to be deleted.
+        :param snapshots: a list of snapshot dictionaries in the cgsnapshot.
+        :return model_update, snapshots_model_update
+
+        param snapshots is retrieved directly from the db. It is a list of
+        cinder.db.sqlalchemy.models.Snapshot to be precise. It cannot be
+        assigned to snapshots_model_update. snapshots_model_update is a list
+        of dictionaries. It has to be built by the driver. An entry will be
+        in this format: {'id': xxx, 'status': xxx, ......}. model_update
+        will be in this format: {'status': xxx, ......}.
+
+        The driver should populate snapshots_model_update and model_update
+        and return them.
+
+        The manager will check snapshots_model_update and update db accordingly
+        for each snapshot. If the driver successfully deleted some snapshots
+        but failed to delete others, it should set statuses of the snapshots
+        accordingly so that the manager can update db correctly.
+
+        If the status in any entry of snapshots_model_update is
+        'error_deleting' or 'error', the status in model_update will be set to
+        the same if it is not already 'error_deleting' or 'error'.
+
+        If the status in model_update is 'error_deleting' or 'error', the
+        manager will raise an exception and the status of cgsnapshot will be
+        set to 'error' in the db. If snapshots_model_update is not returned by
+        the driver, the manager will set the status of every snapshot to
+        'error' in the except block.
+
+        If the driver raises an exception during the operation, it will be
+        caught by the try-except block in the manager and the statuses of
+        cgsnapshot and all snapshots will be set to 'error'.
+
+        For a successful operation, the driver can either build the
+        model_update and snapshots_model_update and return them or
+        return None, None. The statuses of cgsnapshot and all snapshots
+        will be set to 'deleted' after the manager deletes them from db.
+        """
         raise NotImplementedError()
 
     def clone_image(self, volume, image_location, image_id, image_meta,
index 46299d3470bfdd45e62b7db34173a4dfb5582cd6..4e010a1de94ff4131843e31f438a5249cb1d08cf 100644 (file)
@@ -430,7 +430,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
         raise exception.VolumeBackendAPIException(
             _('Unable to create consistency group %s') % gid)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Delete the Dell SC profile associated with this consistency group.
 
         :param context: the context of the caller.
@@ -497,7 +497,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
         raise exception.VolumeBackendAPIException(
             _('Unable to update consistency group %s') % gid)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Takes a snapshot of the consistency group.
 
         :param context: the context of the caller.
@@ -530,7 +530,7 @@ class DellCommonDriver(driver.ConsistencyGroupVD, driver.ManageableVD,
         raise exception.VolumeBackendAPIException(
             _('Unable to snap Consistency Group %s') % cgid)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot.
 
         If profile isn't found return success.  If failed to delete the
index 95118dc5369086e2dabfdf847d419bd996fc85c3..90e261ba41d37cfad5168a044eb683da1830a2df 100644 (file)
@@ -230,17 +230,17 @@ class EMCCLIFCDriver(driver.FibreChannelDriver):
         """Creates a consistencygroup."""
         return self.cli.create_consistencygroup(context, group)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
         return self.cli.delete_consistencygroup(
             self, context, group)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         return self.cli.create_cgsnapshot(
             self, context, cgsnapshot)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         return self.cli.delete_cgsnapshot(self, context, cgsnapshot)
 
index 7fa8e1c71b7b078c0b950ec2839a72bffeb2b410..379a993ef2af7c86116b7fc8f75e8586f1b51d5f 100644 (file)
@@ -209,17 +209,17 @@ class EMCCLIISCSIDriver(driver.ISCSIDriver):
         """Creates a consistencygroup."""
         return self.cli.create_consistencygroup(context, group)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
         return self.cli.delete_consistencygroup(
             self, context, group)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         return self.cli.create_cgsnapshot(
             self, context, cgsnapshot)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         return self.cli.delete_cgsnapshot(self, context, cgsnapshot)
 
index 13404bc4229e04ebe123a47f29d32ffd28af9347..3c16d7e0dca87bdbbab3f913728e47c0dacfb8ca 100644 (file)
@@ -313,17 +313,16 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
         """Creates a consistencygroup."""
         self.common.create_consistencygroup(context, group)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
-        volumes = self.db.volume_get_all_by_group(context, group['id'])
         return self.common.delete_consistencygroup(
             context, group, volumes)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         return self.common.create_cgsnapshot(context, cgsnapshot, self.db)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         return self.common.delete_cgsnapshot(context, cgsnapshot, self.db)
 
index b120a736e324a1e6e74010b0cded424fdc05f6b8..f0ceb187e7efb0d3a11460a1c3e8f5a77637b5c6 100644 (file)
@@ -331,17 +331,16 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
         """Creates a consistencygroup."""
         self.common.create_consistencygroup(context, group)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
-        volumes = self.db.volume_get_all_by_group(context, group['id'])
         return self.common.delete_consistencygroup(
             context, group, volumes)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         return self.common.create_cgsnapshot(context, cgsnapshot, self.db)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         return self.common.delete_cgsnapshot(context, cgsnapshot, self.db)
 
index a147d8c8becd67b00f6675c615f0b2e43171fd26..6578b05f21767f9929c338a7066c3623afb85ebf 100644 (file)
@@ -565,7 +565,7 @@ class XtremIOVolumeDriver(san.SanDriver):
                         ver='v2')
         return {'status': 'available'}
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
         self.client.req('consistency-groups', 'DELETE', name=group['id'],
                         ver='v2')
@@ -647,7 +647,7 @@ class XtremIOVolumeDriver(san.SanDriver):
                                    .replace('-', ''),
                                    'snap': cgsnapshot['id'].replace('-', '')}
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         data = {'consistency-group-id': cgsnapshot['consistencygroup_id'],
                 'snapshot-set-name': self._get_cgsnap_name(cgsnapshot)}
@@ -663,7 +663,7 @@ class XtremIOVolumeDriver(san.SanDriver):
 
         return model_update, snapshots
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         self.client.req('snapshot-sets', 'DELETE',
                         name=self._get_cgsnap_name(cgsnapshot), ver='v2')
index 691ea3f32a3ab69f14de32a7cc88504b9a71e0bf..ba669317822402505dc666910d097e9e1589d45a 100644 (file)
@@ -1158,7 +1158,7 @@ class GPFSDriver(driver.ConsistencyGroupVD, driver.ExtendVD,
         model_update = {'status': 'available'}
         return model_update
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Delete consistency group of GPFS volumes."""
         cgname = "consisgroup-%s" % group['id']
         fsdev = self._gpfs_device
@@ -1194,7 +1194,7 @@ class GPFSDriver(driver.ConsistencyGroupVD, driver.ExtendVD,
 
         return model_update, volumes
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Create snapshot of a consistency group of GPFS volumes."""
         snapshots = self.db.snapshot_get_all_for_cgsnapshot(
             context, cgsnapshot['id'])
@@ -1207,7 +1207,7 @@ class GPFSDriver(driver.ConsistencyGroupVD, driver.ExtendVD,
 
         return model_update, snapshots
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Delete snapshot of a consistency group of GPFS volumes."""
         snapshots = self.db.snapshot_get_all_for_cgsnapshot(
             context, cgsnapshot['id'])
index 9fe37c8da3fc948017e84c2d4866aa27b38fba97..9c3e6206654e6a7301e1532337aa664e6fa70c20 100644 (file)
@@ -1053,7 +1053,7 @@ class StorwizeSVCDriver(san.SanDriver,
         model_update = {'status': 'available'}
         return model_update
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group.
 
         IBM Storwize will delete the volumes of the CG.
@@ -1076,7 +1076,7 @@ class StorwizeSVCDriver(san.SanDriver,
                           {'vol': volume['name'], 'exception': err})
         return model_update, volumes
 
-    def create_cgsnapshot(self, ctxt, cgsnapshot):
+    def create_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         # Use cgsnapshot id as cg name
         cg_name = 'cg_snap-' + cgsnapshot['id']
@@ -1096,7 +1096,7 @@ class StorwizeSVCDriver(san.SanDriver,
 
         return model_update, snapshots_model
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         cgsnapshot_id = cgsnapshot['id']
         cg_name = 'cg_snap-' + cgsnapshot_id
index 3e9abffc35f14aa8247c5088ffe67205c6e80d88..afbdc95444821c5bfcc675b2e232fba35c539593 100644 (file)
@@ -247,17 +247,17 @@ class XIVDS8KDriver(san.SanDriver,
 
         return self.xiv_ds8k_proxy.create_consistencygroup(context, group)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
 
         return self.xiv_ds8k_proxy.delete_consistencygroup(context, group)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a consistency group snapshot."""
 
         return self.xiv_ds8k_proxy.create_cgsnapshot(context, cgsnapshot)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a consistency group snapshot."""
 
         return self.xiv_ds8k_proxy.delete_cgsnapshot(context, cgsnapshot)
index 18109769e670907ea53701c6411abee6f62315e7..8fa790ab6b4ede0241e2f8e2bcb145184315d827 100644 (file)
@@ -887,7 +887,7 @@ class DPLCOMMONDriver(driver.ConsistencyGroupVD, driver.ExtendVD,
                                                     'reason': six.text_type(e)}
             raise exception.VolumeBackendAPIException(data=msg)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Delete a consistency group."""
         ret = 0
         volumes = self.db.volume_get_all_by_group(
@@ -916,7 +916,7 @@ class DPLCOMMONDriver(driver.ConsistencyGroupVD, driver.ExtendVD,
             model_update['status'] = 'deleted'
         return model_update, volumes
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
         snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
             context, cgsnapshot['id'])
@@ -943,7 +943,7 @@ class DPLCOMMONDriver(driver.ConsistencyGroupVD, driver.ExtendVD,
 
         return model_update, snapshots
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
         snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
             context, cgsnapshot['id'])
index 4cb1663b120b3712baee4f1edee4dc90782a74a3..66c6c8214f7d34a39ce9a7b0ee8e931be30a9967 100644 (file)
@@ -399,7 +399,7 @@ class PureBaseVolumeDriver(san.SanDriver):
         return None, None
 
     @log_debug_trace
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
 
         try:
@@ -446,7 +446,7 @@ class PureBaseVolumeDriver(san.SanDriver):
         return None, None, None
 
     @log_debug_trace
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a cgsnapshot."""
 
         cg_id = cgsnapshot.consistencygroup_id
@@ -481,7 +481,7 @@ class PureBaseVolumeDriver(san.SanDriver):
                                     "Snapshot: %s"), err.text)
 
     @log_debug_trace
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a cgsnapshot."""
 
         pgsnap_name = self._get_pgroup_snap_name(cgsnapshot)
index 40d55c61ccecbc377b39854b2b18d66083d77c99..4a03b408fb5416cd37fbd33414bc3bce408cba24 100644 (file)
@@ -454,7 +454,7 @@ class HP3PARFCDriver(driver.TransferVD,
         finally:
             self._logout(common)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         common = self._login()
         try:
             return common.delete_consistencygroup(context, group)
@@ -470,14 +470,14 @@ class HP3PARFCDriver(driver.TransferVD,
         finally:
             self._logout(common)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         common = self._login()
         try:
             return common.create_cgsnapshot(context, cgsnapshot)
         finally:
             self._logout(common)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         common = self._login()
         try:
             return common.delete_cgsnapshot(context, cgsnapshot)
index f4fc7ecfc93915cf2c85f168a45b8029d13dcda5..39d474ce27fa37b2c22fb24b8f2b90061dd5804e 100644 (file)
@@ -751,7 +751,7 @@ class HP3PARISCSIDriver(driver.TransferVD,
         finally:
             self._logout(common)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         common = self._login()
         try:
             return common.delete_consistencygroup(context, group)
@@ -767,14 +767,14 @@ class HP3PARISCSIDriver(driver.TransferVD,
         finally:
             self._logout(common)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         common = self._login()
         try:
             return common.create_cgsnapshot(context, cgsnapshot)
         finally:
             self._logout(common)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         common = self._login()
         try:
             return common.delete_cgsnapshot(context, cgsnapshot)
index 09c929755044ac40ce40180940435cac9059ab4c..01ed065be3ccf8af01b0d15a623ce7ac9dc67308 100644 (file)
@@ -129,7 +129,7 @@ class HPLeftHandISCSIDriver(driver.TransferVD,
             context, group, volumes, cgsnapshot, snapshots, source_cg,
             source_vols)
 
-    def delete_consistencygroup(self, context, group):
+    def delete_consistencygroup(self, context, group, volumes):
         """Deletes a consistency group."""
         return self.proxy.delete_consistencygroup(context, group)
 
@@ -139,11 +139,11 @@ class HPLeftHandISCSIDriver(driver.TransferVD,
         return self.proxy.update_consistencygroup(context, group, add_volumes,
                                                   remove_volumes)
 
-    def create_cgsnapshot(self, context, cgsnapshot):
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Creates a consistency group snapshot."""
         return self.proxy.create_cgsnapshot(context, cgsnapshot)
 
-    def delete_cgsnapshot(self, context, cgsnapshot):
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
         """Deletes a consistency group snapshot."""
         return self.proxy.delete_cgsnapshot(context, cgsnapshot)
 
index 74e3b9af29793efb79c44a6c37fa12e394206834..db0a685689e9d6e156c2c7b896ff215c7fb51e32 100644 (file)
@@ -2297,7 +2297,7 @@ class VolumeManager(manager.SchedulerDependentManager):
         context = context.elevated()
 
         status = 'available'
-        model_update = False
+        model_update = None
 
         self._notify_about_consistencygroup_usage(
             context, group, "create.start")
@@ -2310,8 +2310,15 @@ class VolumeManager(manager.SchedulerDependentManager):
                                                                group)
 
             if model_update:
-                group.update(model_update)
-                group.save()
+                if model_update['status'] == 'error':
+                    msg = (_('Create consistency group failed.'))
+                    LOG.error(msg,
+                              resource={'type': 'consistency_group',
+                                        'id': group.id})
+                    raise exception.VolumeDriverException(message=msg)
+                else:
+                    group.update(model_update)
+                    group.save()
         except Exception:
             with excutils.save_and_reraise_exception():
                 group.status = 'error'
@@ -2602,14 +2609,16 @@ class VolumeManager(manager.SchedulerDependentManager):
         self._notify_about_consistencygroup_usage(
             context, group, "delete.start")
 
+        volumes_model_update = None
+        model_update = None
         try:
             utils.require_driver_initialized(self.driver)
 
-            model_update, volumes = self.driver.delete_consistencygroup(
-                context, group)
+            model_update, volumes_model_update = (
+                self.driver.delete_consistencygroup(context, group, volumes))
 
-            if volumes:
-                for volume in volumes:
+            if volumes_model_update:
+                for volume in volumes_model_update:
                     update = {'status': volume['status']}
                     self.db.volume_update(context, volume['id'],
                                           update)
@@ -2633,8 +2642,14 @@ class VolumeManager(manager.SchedulerDependentManager):
 
         except Exception:
             with excutils.save_and_reraise_exception():
-                group.status = 'error_deleting'
+                group.status = 'error'
                 group.save()
+                # Update volume status to 'error' if driver returns
+                # None for volumes_model_update.
+                if not volumes_model_update:
+                    for vol in volumes:
+                        self.db.volume_update(
+                            context, vol['id'], {'status': 'error'})
 
         # Get reservations for group
         try:
@@ -2843,6 +2858,8 @@ class VolumeManager(manager.SchedulerDependentManager):
         self._notify_about_cgsnapshot_usage(
             context, cgsnapshot, "create.start")
 
+        snapshots_model_update = None
+        model_update = None
         try:
             utils.require_driver_initialized(self.driver)
 
@@ -2855,23 +2872,26 @@ class VolumeManager(manager.SchedulerDependentManager):
             for snapshot in snapshots:
                 snapshot.context = caller_context
 
-            model_update, snapshots = \
-                self.driver.create_cgsnapshot(context, cgsnapshot)
+            model_update, snapshots_model_update = (
+                self.driver.create_cgsnapshot(context, cgsnapshot,
+                                              snapshots))
 
-            if snapshots:
-                for snapshot in snapshots:
+            if snapshots_model_update:
+                for snap_model in snapshots_model_update:
                     # Update db if status is error
-                    if snapshot['status'] == 'error':
-                        update = {'status': snapshot['status']}
-
-                        # TODO(thangp): Switch over to use snapshot.update()
-                        # after cgsnapshot-objects bugs are fixed
-                        self.db.snapshot_update(context, snapshot['id'],
-                                                update)
-                        # If status for one snapshot is error, make sure
-                        # the status for the cgsnapshot is also error
-                        if model_update['status'] != 'error':
-                            model_update['status'] = snapshot['status']
+                    if snap_model['status'] == 'error':
+                        # NOTE(xyang): snapshots is a list of snapshot objects.
+                        # snapshots_model_update should be a list of dicts.
+                        snap = next((item for item in snapshots if
+                                     item.id == snap_model['id']), None)
+                        if snap:
+                            snap.status = snap_model['status']
+                            snap.save()
+
+                    if (snap_model['status'] in ['error_deleting', 'error'] and
+                            model_update['status'] not in
+                            ['error_deleting', 'error']):
+                        model_update['status'] = snap_model['status']
 
             if model_update:
                 if model_update['status'] == 'error':
@@ -2880,10 +2900,16 @@ class VolumeManager(manager.SchedulerDependentManager):
                     LOG.error(msg)
                     raise exception.VolumeDriverException(message=msg)
 
-        except Exception:
+        except exception.CinderException:
             with excutils.save_and_reraise_exception():
                 cgsnapshot.status = 'error'
                 cgsnapshot.save()
+                # Update snapshot status to 'error' if driver returns
+                # None for snapshots_model_update.
+                if not snapshots_model_update:
+                    for snapshot in snapshots:
+                        snapshot.status = 'error'
+                        snapshot.save()
 
         for snapshot in snapshots:
             volume_id = snapshot['volume_id']
@@ -2934,6 +2960,8 @@ class VolumeManager(manager.SchedulerDependentManager):
         self._notify_about_cgsnapshot_usage(
             context, cgsnapshot, "delete.start")
 
+        snapshots_model_update = None
+        model_update = None
         try:
             utils.require_driver_initialized(self.driver)
 
@@ -2944,23 +2972,26 @@ class VolumeManager(manager.SchedulerDependentManager):
             # but it is not a requirement for all drivers.
             cgsnapshot.context = caller_context
             for snapshot in snapshots:
-                snapshot['context'] = caller_context
-
-            model_update, snapshots = \
-                self.driver.delete_cgsnapshot(context, cgsnapshot)
-
-            if snapshots:
-                for snapshot in snapshots:
-                    update = {'status': snapshot['status']}
+                snapshot.context = caller_context
 
-                    # TODO(thangp): Switch over to use snapshot.update()
-                    # after cgsnapshot-objects bugs are fixed
-                    self.db.snapshot_update(context, snapshot['id'],
-                                            update)
-                    if snapshot['status'] in ['error_deleting', 'error'] and \
-                            model_update['status'] not in \
-                            ['error_deleting', 'error']:
-                        model_update['status'] = snapshot['status']
+            model_update, snapshots_model_update = (
+                self.driver.delete_cgsnapshot(context, cgsnapshot,
+                                              snapshots))
+
+            if snapshots_model_update:
+                for snap_model in snapshots_model_update:
+                    # NOTE(xyang): snapshots is a list of snapshot objects.
+                    # snapshots_model_update should be a list of dicts.
+                    snap = next((item for item in snapshots if
+                                 item.id == snap_model['id']), None)
+                    if snap:
+                        snap.status = snap_model['status']
+                        snap.save()
+
+                    if (snap_model['status'] in ['error_deleting', 'error'] and
+                            model_update['status'] not in
+                            ['error_deleting', 'error']):
+                        model_update['status'] = snap_model['status']
 
             if model_update:
                 if model_update['status'] in ['error_deleting', 'error']:
@@ -2972,10 +3003,16 @@ class VolumeManager(manager.SchedulerDependentManager):
                     cgsnapshot.update(model_update)
                     cgsnapshot.save()
 
-        except Exception:
+        except exception.CinderException:
             with excutils.save_and_reraise_exception():
-                cgsnapshot.status = 'error_deleting'
+                cgsnapshot.status = 'error'
                 cgsnapshot.save()
+                # Update snapshot status to 'error' if driver returns
+                # None for snapshots_model_update.
+                if not snapshots_model_update:
+                    for snapshot in snapshots:
+                        snapshot.status = 'error'
+                        snapshot.save()
 
         for snapshot in snapshots:
             # Get reservations
@@ -3002,7 +3039,7 @@ class VolumeManager(manager.SchedulerDependentManager):
             self.db.volume_glance_metadata_delete_by_snapshot(context,
                                                               snapshot['id'])
 
-            # TODO(thangp): Switch over to use snapshot.delete()
+            # TODO(thangp): Switch over to use snapshot.destroy()
             # after cgsnapshot-objects bugs are fixed
             self.db.snapshot_destroy(context, snapshot['id'])