From: Xing Yang Date: Wed, 11 Mar 2015 04:42:16 +0000 (-0400) Subject: Sort snapshots in create CG from CG snapshot X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=56c47cc5f51bc94d1df382cd6f4255acd7048808;p=openstack-build%2Fcinder-build.git Sort snapshots in create CG from CG snapshot This problem was discovered while testing create CG from CG snapshot. In create_consistencygroup_from_src() in manager.py, it calls the driver method create_consistencygroup_from_src() and passes in parameters including source snapshots and target volumes. The problem is that the snapshots list is not sorted to be in the same order as their corresponding volumes. So they may be in the wrong order. In this patch, the source snapshots were sorted before being passed to the driver. Change-Id: I988ce2836f2d553391deeee6e68738356877109b Closes-Bug: #1430628 --- diff --git a/cinder/tests/test_volume.py b/cinder/tests/test_volume.py index 383790018..42e66bb52 100644 --- a/cinder/tests/test_volume.py +++ b/cinder/tests/test_volume.py @@ -3834,6 +3834,51 @@ class VolumeTestCase(BaseVolumeTestCase): self.volume.delete_cgsnapshot(self.context, cgsnapshot_id) self.volume.delete_consistencygroup(self.context, group_id) + def test_sort_snapshots(self): + vol1 = {'id': '1', 'name': 'volume 1', + 'snapshot_id': '1', + 'consistencygroup_id': '1'} + vol2 = {'id': '2', 'name': 'volume 2', + 'snapshot_id': '2', + 'consistencygroup_id': '1'} + vol3 = {'id': '3', 'name': 'volume 3', + 'snapshot_id': '3', + 'consistencygroup_id': '1'} + snp1 = {'id': '1', 'name': 'snap 1', + 'cgsnapshot_id': '1'} + snp2 = {'id': '2', 'name': 'snap 2', + 'cgsnapshot_id': '1'} + snp3 = {'id': '3', 'name': 'snap 3', + 'cgsnapshot_id': '1'} + volumes = [] + snapshots = [] + volumes.append(vol1) + volumes.append(vol2) + volumes.append(vol3) + snapshots.append(snp2) + snapshots.append(snp3) + snapshots.append(snp1) + i = 0 + for vol in volumes: + snap = snapshots[i] + i += 1 + self.assertNotEqual(vol['snapshot_id'], snap['id']) + sorted_snaps = self.volume._sort_snapshots(volumes, snapshots) + i = 0 + for vol in volumes: + snap = sorted_snaps[i] + i += 1 + self.assertEqual(vol['snapshot_id'], snap['id']) + + snapshots[2]['id'] = '9999' + self.assertRaises(exception.SnapshotNotFound, + self.volume._sort_snapshots, + volumes, snapshots) + + self.assertRaises(exception.InvalidInput, + self.volume._sort_snapshots, + volumes, []) + @staticmethod def _create_cgsnapshot(group_id, volume_id, size='0'): """Create a cgsnapshot object.""" diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index e009f71f1..92cb31db0 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -1832,6 +1832,9 @@ class VolumeManager(manager.SchedulerDependentManager): 'valid': VALID_CREATE_CG_SRC_SNAP_STATUS}) raise exception.InvalidConsistencyGroup(reason=msg) + # Sort source snapshots so that they are in the same order as their + # corresponding target volumes. + sorted_snapshots = self._sort_snapshots(volumes, snapshots) self._notify_about_consistencygroup_usage( context, group_ref, "create.start") @@ -1843,7 +1846,8 @@ class VolumeManager(manager.SchedulerDependentManager): 'snap': cgsnapshot_id}) model_update, volumes_model_update = ( self.driver.create_consistencygroup_from_src( - context, group_ref, volumes, cgsnapshot, snapshots)) + context, group_ref, volumes, cgsnapshot, + sorted_snapshots)) if volumes_model_update: for update in volumes_model_update: @@ -1890,6 +1894,29 @@ class VolumeManager(manager.SchedulerDependentManager): return group_ref['id'] + def _sort_snapshots(self, volumes, snapshots): + # Sort source snapshots so that they are in the same order as their + # corresponding target volumes. Each source snapshot in the snapshots + # list should have a corresponding target volume in the volumes list. + if not volumes or not snapshots or len(volumes) != len(snapshots): + msg = _("Input volumes or snapshots are invalid.") + LOG.error(msg) + raise exception.InvalidInput(reason=msg) + + sorted_snapshots = [] + for vol in volumes: + found_snaps = filter( + lambda snap: snap['id'] == vol['snapshot_id'], snapshots) + if not found_snaps: + LOG.error(_LE("Source snapshot cannot be found for target " + "volume %(volume_id)s."), + {'volume_id': vol['id']}) + raise exception.SnapshotNotFound( + snapshot_id=vol['snapshot_id']) + sorted_snapshots.extend(found_snaps) + + return sorted_snapshots + def _update_volume_from_src(self, context, vol, update, group_id=None): try: snapshot_ref = self.db.snapshot_get(context,