]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
NetApp fix attach fail for already mapped volume
authorNavneet Singh <singn@netapp.com>
Thu, 27 Feb 2014 15:20:52 +0000 (20:50 +0530)
committerNavneet Singh <singn@netapp.com>
Mon, 19 May 2014 02:58:25 +0000 (08:28 +0530)
This patch fixes the error raised during mapping of a volume
to the host during attach operation if the volume is already
mapped to the host.

Change-Id: I4f711e7ac18eea0dfddab65fd85a3601fe967a88
Closes-bug: #1310659

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

index 50aa36999b803868dd38914c1a50fc6f0aa3b230..00d793f2b80104aa19c88a4ccb6c080fcc0db7b2 100644 (file)
@@ -666,6 +666,52 @@ class NetAppEseriesIscsiDriverTestCase(test.TestCase):
         self.driver.terminate_connection(self.volume, self.connector)
         self.driver.delete_volume(self.volume)
 
+    def test_map_already_mapped_same_host(self):
+        self.driver.create_volume(self.volume)
+
+        maps = [{'lunMappingRef': 'hdkjsdhjsdh',
+                 'mapRef': '8400000060080E500023C73400300381515BFBA3',
+                 'volumeRef': 'CFDXJ67BLJH25DXCZFZD4NSF54',
+                 'lun': 2}]
+        self.driver._get_host_mapping_for_vol_frm_array = mock.Mock(
+            return_value=maps)
+        self.driver._get_free_lun = mock.Mock()
+        info = self.driver.initialize_connection(self.volume, self.connector)
+        self.assertEqual(
+            self.driver._get_host_mapping_for_vol_frm_array.call_count, 1)
+        self.assertEqual(self.driver._get_free_lun.call_count, 0)
+        self.assertEqual(info['driver_volume_type'], 'iscsi')
+        properties = info.get('data')
+        self.assertIsNotNone(properties, 'Target portal is none')
+        self.driver.terminate_connection(self.volume, self.connector)
+        self.driver.delete_volume(self.volume)
+
+    def test_map_already_mapped_diff_host(self):
+        self.driver.create_volume(self.volume)
+
+        maps = [{'lunMappingRef': 'hdkjsdhjsdh',
+                 'mapRef': '7400000060080E500023C73400300381515BFBA3',
+                 'volumeRef': 'CFDXJ67BLJH25DXCZFZD4NSF54',
+                 'lun': 2}]
+        self.driver._get_host_mapping_for_vol_frm_array = mock.Mock(
+            return_value=maps)
+        self.driver._get_vol_mapping_for_host_frm_array = mock.Mock(
+            return_value=[])
+        self.driver._get_free_lun = mock.Mock(return_value=0)
+        self.driver._del_vol_mapping_frm_cache = mock.Mock()
+        info = self.driver.initialize_connection(self.volume, self.connector)
+        self.assertEqual(
+            self.driver._get_vol_mapping_for_host_frm_array.call_count, 1)
+        self.assertEqual(
+            self.driver._get_host_mapping_for_vol_frm_array.call_count, 1)
+        self.assertEqual(self.driver._get_free_lun.call_count, 1)
+        self.assertEqual(self.driver._del_vol_mapping_frm_cache.call_count, 1)
+        self.assertEqual(info['driver_volume_type'], 'iscsi')
+        properties = info.get('data')
+        self.assertIsNotNone(properties, 'Target portal is none')
+        self.driver.terminate_connection(self.volume, self.connector)
+        self.driver.delete_volume(self.volume)
+
     def test_cloned_volume_destroy(self):
         self.driver.create_volume(self.volume)
         self.driver.create_cloned_volume(self.snapshot, self.volume)
index 39dd80371bde752509a80b035318d8d18fb07c70..5eb519ccf2847f197a32944dc9fa5bccd10f659e 100644 (file)
@@ -210,6 +210,9 @@ class Driver(driver.ISCSIDriver):
         vol_id = mapping['volumeRef']
         volume = self._objects['volumes']['ref_vol'][vol_id]
         volume['listOfMappings'] = volume.get('listOfMappings') or []
+        for mapp in volume['listOfMappings']:
+            if mapp['lunMappingRef'] == mapping['lunMappingRef']:
+                return
         volume['listOfMappings'].append(mapping)
 
     def _del_volume_frm_cache(self, label):
@@ -515,7 +518,15 @@ class Driver(driver.ISCSIDriver):
     def _map_volume_to_host(self, vol, initiator):
         """Maps the e-series volume to host with initiator."""
         host = self._get_or_create_host(initiator)
-        lun = self._get_free_lun(host)
+        vol_maps = self._get_host_mapping_for_vol_frm_array(vol)
+        for vol_map in vol_maps:
+            if vol_map.get('mapRef') == host['hostRef']:
+                return vol_map
+            else:
+                self._client.delete_volume_mapping(vol_map['lunMappingRef'])
+                self._del_vol_mapping_frm_cache(vol_map)
+        mappings = self._get_vol_mapping_for_host_frm_array(host['hostRef'])
+        lun = self._get_free_lun(host, mappings)
         return self._client.create_volume_mapping(vol['volumeRef'],
                                                   host['hostRef'], lun)
 
@@ -559,9 +570,10 @@ class Driver(driver.ISCSIDriver):
                 return ht
         raise exception.NotFound(_("Host type %s not supported.") % host_type)
 
-    def _get_free_lun(self, host):
+    def _get_free_lun(self, host, maps=None):
         """Gets free lun for given host."""
-        luns = self._get_vol_mapping_for_host_frm_array(host['hostRef'])
+        ref = host['hostRef']
+        luns = maps or self._get_vol_mapping_for_host_frm_array(ref)
         used_luns = set(map(lambda lun: int(lun['lun']), luns))
         for lun in xrange(self.MAX_LUNS_PER_HOST):
             if lun not in used_luns:
@@ -571,10 +583,17 @@ class Driver(driver.ISCSIDriver):
 
     def _get_vol_mapping_for_host_frm_array(self, host_ref):
         """Gets all volume mappings for given host from array."""
-        mappings = self._client.get_volume_mappings()
+        mappings = self._client.get_volume_mappings() or []
         host_maps = filter(lambda x: x.get('mapRef') == host_ref, mappings)
         return host_maps
 
+    def _get_host_mapping_for_vol_frm_array(self, volume):
+        """Gets all host mappings for given volume from array."""
+        mappings = self._client.get_volume_mappings() or []
+        host_maps = filter(lambda x: x.get('volumeRef') == volume['volumeRef'],
+                           mappings)
+        return host_maps
+
     def terminate_connection(self, volume, connector, **kwargs):
         """Disallow connection from connector."""
         vol = self._get_volume(volume['id'])