]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
NetApp fix for controller preferred path
authorNavneet Singh <singn@netapp.com>
Thu, 27 Feb 2014 07:39:03 +0000 (13:09 +0530)
committerNavneet Singh <singn@netapp.com>
Wed, 17 Sep 2014 16:09:43 +0000 (21:39 +0530)
This patch optimizes the data path by choosing
the preferred path to access the volume by selecting
the controller owning the volume.

Closes-Bug: #1365881

Change-Id: I7069111dfd22d4fca92615b5730854f6d696ec13

cinder/tests/test_netapp_eseries_iscsi.py
cinder/volume/drivers/netapp/eseries/iscsi.py

index f345bb4021d3cd28c32c57725e22e17fd3e8f443..7b1784514fe90e09a97ebc3a2f95153de62d5f0d 100644 (file)
@@ -118,6 +118,32 @@ class FakeEseriesServerHandler(object):
                     "currentControllerId": "070000000000000000000001",
                     "protectionInformationCapable": false, "mapped": false,
                     "reconPriority": 1, "protectionType":
+                    "type1Protection"},
+                    {"extremeProtection": false, "pitBaseVolume": true,
+                    "dssMaxSegmentSize": 131072,
+                    "totalSizeInBytes": "1073741824", "raidLevel": "raid6",
+                    "volumeRef": "0200000060080E500023BB34000003FB515C2293",
+                    "listOfMappings": [], "sectorOffset": "15",
+                    "id": "0200000060080E500023BB34000003FB515C2293",
+                    "wwn": "60080E500023BB3400001FC352D14CB2",
+                    "capacity": "2147483648", "mgmtClientAttribute": 0,
+                    "label": "CFDXJ67BLJH25DXCZFZD4NSF54",
+                    "volumeFull": false,
+                    "blkSize": 512, "volumeCopyTarget": false,
+                    "volumeGroupRef":
+                    "0400000060080E500023BB3400001F9F52CECC3F",
+                    "preferredControllerId": "070000000000000000000001",
+                    "currentManager": "070000000000000000000001",
+                    "applicationTagOwned": false, "status": "optimal",
+                    "segmentSize": 131072, "volumeUse": "standardVolume",
+                    "action": "none", "preferredManager":
+                    "070000000000000000000001", "volumeHandle": 15,
+                    "offline": false, "preReadRedundancyCheckEnabled": false,
+                    "dssPreallocEnabled": false, "name": "bdm-vc-test-1",
+                    "worldWideName": "60080E500023BB3400001FC352D14CB2",
+                    "currentControllerId": "070000000000000000000001",
+                    "protectionInformationCapable": false, "mapped": false,
+                    "reconPriority": 1, "protectionType":
                     "type1Protection"}]"""
         elif re.match("^/storage-systems/[0-9a-zA-Z]+/volumes/[0-9A-Za-z]+$",
                       path):
@@ -680,7 +706,7 @@ class NetAppEseriesIscsiDriverTestCase(test.TestCase):
 
         maps = [{'lunMappingRef': 'hdkjsdhjsdh',
                  'mapRef': '8400000060080E500023C73400300381515BFBA3',
-                 'volumeRef': 'CFDXJ67BLJH25DXCZFZD4NSF54',
+                 'volumeRef': '0200000060080E500023BB34000003FB515C2293',
                  'lun': 2}]
         self.driver._get_host_mapping_for_vol_frm_array = mock.Mock(
             return_value=maps)
@@ -834,3 +860,21 @@ class NetAppEseriesIscsiDriverTestCase(test.TestCase):
                           self.driver._create_volume,
                           self.fake_eseries_pool_label,
                           self.fake_eseries_volume_label, self.fake_size_gb)
+
+    def test_portal_for_vol_controller(self):
+        volume = {'id': 'vol_id', 'currentManager': 'ctrl1'}
+        vol_nomatch = {'id': 'vol_id', 'currentManager': 'ctrl3'}
+        portals = [{'controller': 'ctrl2', 'iqn': 'iqn2'},
+                   {'controller': 'ctrl1', 'iqn': 'iqn1'}]
+        portal = self.driver._get_iscsi_portal_for_vol(volume, portals)
+        self.assertEqual(portal, {'controller': 'ctrl1', 'iqn': 'iqn1'})
+        portal = self.driver._get_iscsi_portal_for_vol(vol_nomatch, portals)
+        self.assertEqual(portal, {'controller': 'ctrl2', 'iqn': 'iqn2'})
+
+    def test_portal_for_vol_any_false(self):
+        vol_nomatch = {'id': 'vol_id', 'currentManager': 'ctrl3'}
+        portals = [{'controller': 'ctrl2', 'iqn': 'iqn2'},
+                   {'controller': 'ctrl1', 'iqn': 'iqn1'}]
+        self.assertRaises(exception.NetAppDriverException,
+                          self.driver._get_iscsi_portal_for_vol,
+                          vol_nomatch, portals, False)
index 1b1f97c7b0674ce0787ff6f252cef8f7af333e99..bfb08d79ff37edca9c4b48d688773d9bff1c3493 100644 (file)
@@ -254,11 +254,15 @@ class Driver(driver.ISCSIDriver):
         try:
             return self._get_cached_volume(label)
         except KeyError:
-            for vol in self._client.list_volumes():
-                if vol.get('label') == label:
-                    self._cache_volume(vol)
-                    break
-            return self._get_cached_volume(label)
+            return self._get_latest_volume(uid)
+
+    def _get_latest_volume(self, uid):
+        label = utils.convert_uuid_to_es_fmt(uid)
+        for vol in self._client.list_volumes():
+            if vol.get('label') == label:
+                self._cache_volume(vol)
+                return self._get_cached_volume(label)
+        raise exception.NetAppDriverException(_("Volume %s not found."), uid)
 
     def _get_cached_volume(self, label):
         vol_id = self._objects['volumes']['label_ref'][label]
@@ -504,8 +508,9 @@ class Driver(driver.ISCSIDriver):
     def initialize_connection(self, volume, connector):
         """Allow connection to connector and return connection info."""
         initiator_name = connector['initiator']
-        vol = self._get_volume(volume['id'])
-        iscsi_det = self._get_iscsi_service_details()
+        vol = self._get_latest_volume(volume['id'])
+        iscsi_details = self._get_iscsi_service_details()
+        iscsi_det = self._get_iscsi_portal_for_vol(vol, iscsi_details)
         mapping = self._map_volume_to_host(vol, initiator_name)
         lun_id = mapping['lun']
         self._cache_vol_mapping(mapping)
@@ -535,6 +540,7 @@ class Driver(driver.ISCSIDriver):
 
     def _get_iscsi_service_details(self):
         """Gets iscsi iqn, ip and port information."""
+        ports = []
         hw_inventory = self._client.list_hardware_inventory()
         iscsi_ports = hw_inventory.get('iscsiPorts')
         if iscsi_ports:
@@ -550,9 +556,23 @@ class Driver(driver.ISCSIDriver):
                     iscsi_det['ip'] =\
                         port['ipv4Data']['ipv4AddressData']['ipv4Address']
                     iscsi_det['iqn'] = port['iqn']
-                    iscsi_det['tcp_port'] = port.get('tcpListenPort', '3260')
-                    return iscsi_det
-        msg = _('No good iscsi portal information found for %s.')
+                    iscsi_det['tcp_port'] = port.get('tcpListenPort')
+                    iscsi_det['controller'] = port.get('controllerId')
+                    ports.append(iscsi_det)
+        if not ports:
+            msg = _('No good iscsi portals found for %s.')
+            raise exception.NetAppDriverException(
+                msg % self._client.get_system_id())
+        return ports
+
+    def _get_iscsi_portal_for_vol(self, volume, portals, anyController=True):
+        """Get the iscsi portal info relevant to volume."""
+        for portal in portals:
+            if portal.get('controller') == volume.get('currentManager'):
+                return portal
+        if anyController and portals:
+            return portals[0]
+        msg = _('No good iscsi portal found in supplied list for %s.')
         raise exception.NetAppDriverException(
             msg % self._client.get_system_id())