From: Navneet Singh Date: Thu, 27 Feb 2014 15:20:52 +0000 (+0530) Subject: NetApp fix attach fail for already mapped volume X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=dcec1b84f4d3462fc408f4152f4c89b8df79d629;p=openstack-build%2Fcinder-build.git NetApp fix attach fail for already mapped volume 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 --- diff --git a/cinder/tests/test_netapp_eseries_iscsi.py b/cinder/tests/test_netapp_eseries_iscsi.py index 50aa36999..00d793f2b 100644 --- a/cinder/tests/test_netapp_eseries_iscsi.py +++ b/cinder/tests/test_netapp_eseries_iscsi.py @@ -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) diff --git a/cinder/volume/drivers/netapp/eseries/iscsi.py b/cinder/volume/drivers/netapp/eseries/iscsi.py index 39dd80371..5eb519ccf 100644 --- a/cinder/volume/drivers/netapp/eseries/iscsi.py +++ b/cinder/volume/drivers/netapp/eseries/iscsi.py @@ -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'])