From 91ad18ef4111361b3ce2abf382f75bda9e281663 Mon Sep 17 00:00:00 2001 From: Patrick East Date: Tue, 11 Aug 2015 17:55:22 -0700 Subject: [PATCH] Fix Pure create volume from cgsnapshot We would previously lookup the consistency group id through the snapshot db object, but with the new versioned snapshot object we can no longer take that shortcut. We will now query the FlashArray for all Protection Group snapshots and search for one with the cgsnapshot id in its name. Closes-Bug: #1483916 Change-Id: Icb4991ec419c2cf46c760fa750e9f1be1528364c --- cinder/tests/unit/test_pure.py | 61 ++++++++++++++++++++++++---------- cinder/volume/drivers/pure.py | 17 +++++++--- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/cinder/tests/unit/test_pure.py b/cinder/tests/unit/test_pure.py index 166e1e801..57e532a68 100644 --- a/cinder/tests/unit/test_pure.py +++ b/cinder/tests/unit/test_pure.py @@ -283,6 +283,20 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase): self.driver.create_volume_from_snapshot, VOLUME, SNAPSHOT) SNAPSHOT["volume_size"] = 2 # reset size + @mock.patch(BASE_DRIVER_OBJ + "._get_snap_name") + def test_create_volume_from_snapshot_cant_get_name(self, mock_get_name): + mock_get_name.return_value = None + self.assertRaises(exception.PureDriverException, + self.driver.create_volume_from_snapshot, + VOLUME, SNAPSHOT) + + @mock.patch(BASE_DRIVER_OBJ + "._get_pgroup_snap_name_from_snapshot") + def test_create_volume_from_cgsnapshot_cant_get_name(self, mock_get_name): + mock_get_name.return_value = None + self.assertRaises(exception.PureDriverException, + self.driver.create_volume_from_snapshot, + VOLUME, SNAPSHOT_WITH_CGROUP) + @mock.patch(BASE_DRIVER_OBJ + "._add_volume_to_consistency_group", autospec=True) @mock.patch(BASE_DRIVER_OBJ + "._extend_if_needed", autospec=True) @@ -615,28 +629,39 @@ class PureBaseVolumeDriverTestCase(PureDriverTestCase): self.assertEqual(expected_name, actual_name) - def test_get_pgroup_vol_snap_name(self): - cg_id = "4a2f7e3a-312a-40c5-96a8-536b8a0fe074" - cgsnap_id = "4a2f7e3a-312a-40c5-96a8-536b8a0fe075" - volume_name = "volume-4a2f7e3a-312a-40c5-96a8-536b8a0fe075" + def test_get_pgroup_snap_name_from_snapshot(self): + cgsnapshot_id = 'b919b266-23b4-4b83-9a92-e66031b9a921' + volume_id = 'a3b8b294-8494-4a72-bec7-9aadec561332' + pgsnap_name_base = ('consisgroup-0cfc0e4e-5029-4839-af20-184fbc42a9ed' + '-cinder.cgsnapshot-%s-cinder.volume-%s-cinder') + pgsnap_name = pgsnap_name_base % (cgsnapshot_id, volume_id) + + target_pgsnap_dict = { + 'source': 'volume-a3b8b294-8494-4a72-bec7-9aadec561332-cinder', + 'serial': '590474D16E6708FD00015075', + 'size': 1073741824, + 'name': pgsnap_name, + 'created': '2015-08-11T22:25:43Z' + } - mock_snap = mock.Mock() - mock_snap.cgsnapshot = mock.Mock() - mock_snap.cgsnapshot.consistencygroup_id = cg_id - mock_snap.cgsnapshot.id = cgsnap_id - mock_snap.volume_name = volume_name + # Simulate another pgroup snapshot for another volume in the same group + other_volume_id = '73f6af5e-43cd-4c61-8f57-21f312e4523d' + other_pgsnap_dict = target_pgsnap_dict.copy() + other_pgsnap_dict['name'] = pgsnap_name_base % (cgsnapshot_id, + other_volume_id) - expected_name = "consisgroup-%(cg)s-cinder.cgsnapshot-%(snap)s-cinder"\ - ".%(vol)s-cinder" % { - "cg": cg_id, - "snap": cgsnap_id, - "vol": volume_name, - } + snap_list = [other_pgsnap_dict, target_pgsnap_dict] - actual_name = self.driver._get_pgroup_snap_name_from_snapshot( - mock_snap) + self.array.list_volumes.return_value = snap_list - self.assertEqual(expected_name, actual_name) + mock_snap = mock.Mock() + mock_snap.cgsnapshot_id = cgsnapshot_id + mock_snap.volume_id = volume_id + + actual_name = self.driver._get_pgroup_snap_name_from_snapshot( + mock_snap + ) + self.assertEqual(pgsnap_name, actual_name) def test_create_consistencygroup(self): mock_cgroup = mock.Mock() diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py index 7be2c8f66..d56d32ce7 100644 --- a/cinder/volume/drivers/pure.py +++ b/cinder/volume/drivers/pure.py @@ -134,6 +134,11 @@ class PureBaseVolumeDriver(san.SanDriver): else: snap_name = self._get_snap_name(snapshot) + if not snap_name: + msg = _('Unable to determine snapshot name in Purity for snapshot ' + '%(id)s.') % {'id': snapshot['id']} + raise exception.PureDriverException(reason=msg) + self._array.copy_volume(snap_name, vol_name) self._extend_if_needed(vol_name, snapshot["volume_size"], volume["size"]) @@ -614,11 +619,13 @@ class PureBaseVolumeDriver(san.SanDriver): def _get_pgroup_snap_name_from_snapshot(self, snapshot): """Return the name of the snapshot that Purity will use.""" - cg_id = snapshot.cgsnapshot.consistencygroup_id - cg_name = self._get_pgroup_name_from_id(cg_id) - cgsnapshot_id = self._get_pgroup_snap_suffix(snapshot.cgsnapshot) - volume_name = snapshot.volume_name - return "%s.%s.%s-cinder" % (cg_name, cgsnapshot_id, volume_name) + pg_snaps = self._array.list_volumes(snap=True, pgroup=True) + for pg_snap in pg_snaps: + pg_snap_name = pg_snap['name'] + if (snapshot.cgsnapshot_id in pg_snap_name and + snapshot.volume_id in pg_snap_name): + return pg_snap_name + return None @staticmethod def _generate_purity_host_name(name): -- 2.45.2