From: Patrick East Date: Fri, 13 Feb 2015 21:35:51 +0000 (-0800) Subject: PureISCSIDriver consistency group updates. X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=8d5b795b37ed021c2639066689645f8aa0b1012f;p=openstack-build%2Fcinder-build.git PureISCSIDriver consistency group updates. This will enable the driver to add and remove volumes from Purity protection groups that correspond to Cinders consistency groups, as well as create a consistency group from a cgsnapshot. Implements: blueprint pure-iscsi-update-cg Change-Id: I662e705a1b531a64900304782183041600e13354 --- diff --git a/cinder/tests/test_pure.py b/cinder/tests/test_pure.py index 949775c8c..3cb4289e4 100644 --- a/cinder/tests/test_pure.py +++ b/cinder/tests/test_pure.py @@ -784,6 +784,46 @@ class PureISCSIDriverTestCase(test.TestCase): [self.array.create_pgroup], self.driver.create_consistencygroup, None, mock_cgroup) + @mock.patch(DRIVER_OBJ + ".create_volume_from_snapshot") + @mock.patch(DRIVER_OBJ + ".create_consistencygroup") + def test_create_consistencygroup_from_src(self, mock_create_cg, + mock_create_vol): + mock_context = mock.Mock() + mock_group = mock.Mock() + mock_cgsnapshot = mock.Mock() + mock_snapshots = [mock.Mock() for i in range(5)] + mock_volumes = [mock.Mock() for i in range(5)] + self.driver.create_consistencygroup_from_src( + mock_context, + mock_group, + mock_volumes, + cgsnapshot=mock_cgsnapshot, + snapshots=mock_snapshots + ) + mock_create_cg.assert_called_with(mock_context, mock_group) + expected_calls = [mock.call(vol, snap) + for vol, snap in zip(mock_volumes, mock_snapshots)] + mock_create_vol.assert_has_calls(expected_calls, + any_order=True) + + self.assert_error_propagates( + [mock_create_vol, mock_create_cg], + self.driver.create_consistencygroup_from_src, + mock_context, + mock_group, + mock_volumes, + cgsnapshot=mock_cgsnapshot, + snapshots=mock_snapshots + ) + + def test_create_consistencygroup_from_src_no_snap(self): + # Expect an error when no cgsnapshot or snapshots are provided + self.assertRaises(exception.InvalidInput, + self.driver.create_consistencygroup_from_src, + mock.Mock(), # context + mock.Mock(), # group + [mock.Mock()]) # volumes + @mock.patch(DRIVER_OBJ + ".delete_volume", autospec=True) def test_delete_consistencygroup(self, mock_delete_volume): mock_cgroup = mock.MagicMock() @@ -847,6 +887,77 @@ class PureISCSIDriverTestCase(test.TestCase): [self.array.destroy_pgroup], self.driver.delete_consistencygroup, mock_context, mock_cgroup) + def _create_mock_cg(self): + mock_group = mock.MagicMock() + mock_group.id = "4a2f7e3a-312a-40c5-96a8-536b8a0fe074" + mock_group.status = "Available" + mock_group.cg_name = "consisgroup-" + mock_group.id + "-cinder" + return mock_group + + def test_update_consistencygroup(self): + mock_group = self._create_mock_cg() + add_vols = [ + {'name': 'vol1'}, + {'name': 'vol2'}, + {'name': 'vol3'}, + ] + expected_addvollist = [vol['name'] + '-cinder' for vol in add_vols] + remove_vols = [ + {'name': 'vol4'}, + {'name': 'vol5'} + ] + expected_remvollist = [vol['name'] + '-cinder' for vol in remove_vols] + self.driver.update_consistencygroup(mock.Mock(), mock_group, + add_vols, remove_vols) + self.array.set_pgroup.assert_called_with( + mock_group.cg_name, + addvollist=expected_addvollist, + remvollist=expected_remvollist + ) + + def test_update_consistencygroup_no_add_vols(self): + mock_group = self._create_mock_cg() + expected_addvollist = [] + remove_vols = [ + {'name': 'vol4'}, + {'name': 'vol5'} + ] + expected_remvollist = [vol['name'] + '-cinder' for vol in remove_vols] + self.driver.update_consistencygroup(mock.Mock(), mock_group, + None, remove_vols) + self.array.set_pgroup.assert_called_with( + mock_group.cg_name, + addvollist=expected_addvollist, + remvollist=expected_remvollist + ) + + def test_update_consistencygroup_no_remove_vols(self): + mock_group = self._create_mock_cg() + add_vols = [ + {'name': 'vol1'}, + {'name': 'vol2'}, + {'name': 'vol3'}, + ] + expected_addvollist = [vol['name'] + '-cinder' for vol in add_vols] + expected_remvollist = [] + self.driver.update_consistencygroup(mock.Mock(), mock_group, + add_vols, None) + self.array.set_pgroup.assert_called_with( + mock_group.cg_name, + addvollist=expected_addvollist, + remvollist=expected_remvollist + ) + + def test_update_consistencygroup_no_vols(self): + mock_group = self._create_mock_cg() + self.driver.update_consistencygroup(mock.Mock(), mock_group, + None, None) + self.array.set_pgroup.assert_called_with( + mock_group.cg_name, + addvollist=[], + remvollist=[] + ) + def test_create_cgsnapshot(self): mock_cgsnap = mock.Mock() mock_cgsnap.id = "4a2f7e3a-312a-40c5-96a8-536b8a0fe074" diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py index 4520a8d5a..ec2cf9f9f 100644 --- a/cinder/volume/drivers/pure.py +++ b/cinder/volume/drivers/pure.py @@ -107,7 +107,7 @@ def _generate_chap_secret(): class PureISCSIDriver(san.SanISCSIDriver): """Performs volume management on Pure Storage FlashArray.""" - VERSION = "2.0.5" + VERSION = "2.0.6" SUPPORTED_REST_API_VERSIONS = ['1.2', '1.3', '1.4'] @@ -517,6 +517,22 @@ class PureISCSIDriver(san.SanISCSIDriver): LOG.debug("Leave PureISCSIDriver.create_consistencygroup") return model_update + def create_consistencygroup_from_src(self, context, group, volumes, + cgsnapshot=None, snapshots=None): + LOG.debug("Enter PureISCSIDriver.create_consistencygroup_from_src") + + if cgsnapshot and snapshots: + self.create_consistencygroup(context, group) + for volume, snapshot in zip(volumes, snapshots): + self.create_volume_from_snapshot(volume, snapshot) + else: + msg = _("create_consistencygroup_from_src only supports a" + " cgsnapshot source, other sources cannot be used.") + raise exception.InvalidInput(msg) + + LOG.debug("Leave PureISCSIDriver.create_consistencygroup_from_src") + return None, None + def delete_consistencygroup(self, context, group): """Deletes a consistency group.""" LOG.debug("Enter PureISCSIDriver.delete_consistencygroup") @@ -545,6 +561,27 @@ class PureISCSIDriver(san.SanISCSIDriver): LOG.debug("Leave PureISCSIDriver.delete_consistencygroup") return model_update, volumes + def update_consistencygroup(self, context, group, + add_volumes=None, remove_volumes=None): + LOG.debug("Enter PureISCSIDriver.update_consistencygroup") + + pgroup_name = _get_pgroup_name_from_id(group.id) + if add_volumes: + addvollist = [_get_vol_name(volume) for volume in add_volumes] + else: + addvollist = [] + + if remove_volumes: + remvollist = [_get_vol_name(volume) for volume in remove_volumes] + else: + remvollist = [] + + self._array.set_pgroup(pgroup_name, addvollist=addvollist, + remvollist=remvollist) + + LOG.debug("Leave PureISCSIDriver.update_consistencygroup") + return None, None, None + def create_cgsnapshot(self, context, cgsnapshot): """Creates a cgsnapshot.""" LOG.debug("Enter PureISCSIDriver.create_cgsnapshot")