]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add error handling to _connect function in PureISCSIDriver
authorDaniel Wilson <daniel.wilson@purestorage.com>
Wed, 17 Dec 2014 20:05:44 +0000 (12:05 -0800)
committerDaniel Wilson <daniel.wilson@purestorage.com>
Fri, 19 Dec 2014 05:11:03 +0000 (21:11 -0800)
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

cinder/tests/test_pure.py
cinder/volume/drivers/pure.py

index b0bae9a59092689357d2001ed6b64869e8d29bfe..34c75dc442099d266448847f339dbe192ac31047 100644 (file)
@@ -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])
index 12c7362b2fadc9615661fb369a20174099bec1e7..a071a0f7aa1dcc11fecc4d1cee9570c85a840992 100644 (file)
@@ -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."""