From: Daniel Wilson Date: Wed, 17 Dec 2014 20:05:44 +0000 (-0800) Subject: Add error handling to _connect function in PureISCSIDriver X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=4da33ea23319b16b8e81ee0413b0c251a444d669;p=openstack-build%2Fcinder-build.git Add error handling to _connect function in PureISCSIDriver The driver was throwing an exception when trying to connect a volume to a host when they were already connected. This change catches the exception and looks up the existing connection information to use as a return value. Change-Id: Id0e6b1d3c3cd1e51745e97f99eef88a15e285526 Closes-Bug: 1403631 --- diff --git a/cinder/tests/test_pure.py b/cinder/tests/test_pure.py index b0bae9a59..34c75dc44 100644 --- a/cinder/tests/test_pure.py +++ b/cinder/tests/test_pure.py @@ -354,6 +354,42 @@ class PureISCSIDriverTestCase(test.TestCase): self.array.create_host], self.driver._connect, VOLUME, CONNECTOR) + @mock.patch(DRIVER_OBJ + "._get_host", autospec=True) + def test_connect_already_connected(self, mock_host): + mock_host.return_value = PURE_HOST + expected = {"host": PURE_HOST_NAME, "lun": 1} + self.array.list_volume_hosts.return_value = \ + [expected, {"host": "extra", "lun": 2}] + self.array.connect_host.side_effect = exception.PureAPIException( + code=400, reason="Connection already exists") + actual = self.driver._connect(VOLUME, CONNECTOR) + self.assertEqual(expected, actual) + self.assertTrue(self.array.connect_host.called) + self.assertTrue(self.array.list_volume_hosts) + + @mock.patch(DRIVER_OBJ + "._get_host", autospec=True) + def test_connect_already_connected_list_hosts_empty(self, mock_host): + mock_host.return_value = PURE_HOST + self.array.list_volume_hosts.return_value = [] + self.array.connect_host.side_effect = exception.PureAPIException( + code=400, reason="Connection already exists") + self.assertRaises(exception.PureDriverException, + lambda: self.driver._connect(VOLUME, CONNECTOR)) + self.assertTrue(self.array.connect_host.called) + self.assertTrue(self.array.list_volume_hosts) + + @mock.patch(DRIVER_OBJ + "._get_host", autospec=True) + def test_connect_already_connected_list_hosts_exception(self, mock_host): + mock_host.return_value = PURE_HOST + self.array.list_volume_hosts.side_effect = \ + exception.PureAPIException(code=400, reason="") + self.array.connect_host.side_effect = exception.PureAPIException( + code=400, reason="Connection already exists") + self.assertRaises(exception.PureAPIException, + lambda: self.driver._connect(VOLUME, CONNECTOR)) + self.assertTrue(self.array.connect_host.called) + self.assertTrue(self.array.list_volume_hosts) + def test_get_host(self): good_host = PURE_HOST.copy() good_host.update(iqn=["another-wrong-iqn", INITIATOR_IQN]) diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py index 12c7362b2..a071a0f7a 100644 --- a/cinder/volume/drivers/pure.py +++ b/cinder/volume/drivers/pure.py @@ -30,7 +30,7 @@ from oslo.utils import excutils from oslo.utils import units from cinder import exception -from cinder.i18n import _LE, _LI, _LW +from cinder.i18n import _, _LE, _LI, _LW from cinder.openstack.common import log as logging from cinder import utils from cinder.volume.drivers.san import san @@ -229,6 +229,7 @@ class PureISCSIDriver(san.SanISCSIDriver): def _connect(self, volume, connector): """Connect the host and volume; return dict describing connection.""" + connection = None vol_name = _get_vol_name(volume) host = self._get_host(connector) if host: @@ -242,7 +243,26 @@ class PureISCSIDriver(san.SanISCSIDriver): " %(iqn)s.") % {"host_name": host_name, "iqn": iqn}) self._array.create_host(host_name, iqnlist=[iqn]) - return self._array.connect_host(host_name, vol_name) + try: + connection = self._array.connect_host(host_name, vol_name) + except exception.PureAPIException as err: + with excutils.save_and_reraise_exception() as ctxt: + if (err.kwargs["code"] == 400 and + "Connection already exists" in err.msg): + # Happens if the volume is already connected to the host. + ctxt.reraise = False + LOG.warn(_LW("Volume connection already exists with " + "message: %s") % err.msg) + # Get the info for the existing connection + connected_hosts = self._array.list_volume_hosts(vol_name) + for host_info in connected_hosts: + if host_info["host"] == host_name: + connection = host_info + break + if not connection: + raise exception.PureDriverException( + reason=_("Unable to connect or find connection to host")) + return connection def _get_host(self, connector): """Return dict describing existing Purity host object or None."""