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
This commit is contained in:
Navneet Singh 2014-02-27 20:50:52 +05:30
parent e524456814
commit dcec1b84f4
2 changed files with 69 additions and 4 deletions

View File

@ -666,6 +666,52 @@ class NetAppEseriesIscsiDriverTestCase(test.TestCase):
self.driver.terminate_connection(self.volume, self.connector) self.driver.terminate_connection(self.volume, self.connector)
self.driver.delete_volume(self.volume) 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): def test_cloned_volume_destroy(self):
self.driver.create_volume(self.volume) self.driver.create_volume(self.volume)
self.driver.create_cloned_volume(self.snapshot, self.volume) self.driver.create_cloned_volume(self.snapshot, self.volume)

View File

@ -210,6 +210,9 @@ class Driver(driver.ISCSIDriver):
vol_id = mapping['volumeRef'] vol_id = mapping['volumeRef']
volume = self._objects['volumes']['ref_vol'][vol_id] volume = self._objects['volumes']['ref_vol'][vol_id]
volume['listOfMappings'] = volume.get('listOfMappings') or [] volume['listOfMappings'] = volume.get('listOfMappings') or []
for mapp in volume['listOfMappings']:
if mapp['lunMappingRef'] == mapping['lunMappingRef']:
return
volume['listOfMappings'].append(mapping) volume['listOfMappings'].append(mapping)
def _del_volume_frm_cache(self, label): def _del_volume_frm_cache(self, label):
@ -515,7 +518,15 @@ class Driver(driver.ISCSIDriver):
def _map_volume_to_host(self, vol, initiator): def _map_volume_to_host(self, vol, initiator):
"""Maps the e-series volume to host with initiator.""" """Maps the e-series volume to host with initiator."""
host = self._get_or_create_host(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'], return self._client.create_volume_mapping(vol['volumeRef'],
host['hostRef'], lun) host['hostRef'], lun)
@ -559,9 +570,10 @@ class Driver(driver.ISCSIDriver):
return ht return ht
raise exception.NotFound(_("Host type %s not supported.") % host_type) 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.""" """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)) used_luns = set(map(lambda lun: int(lun['lun']), luns))
for lun in xrange(self.MAX_LUNS_PER_HOST): for lun in xrange(self.MAX_LUNS_PER_HOST):
if lun not in used_luns: 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): def _get_vol_mapping_for_host_frm_array(self, host_ref):
"""Gets all volume mappings for given host from array.""" """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) host_maps = filter(lambda x: x.get('mapRef') == host_ref, mappings)
return host_maps 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): def terminate_connection(self, volume, connector, **kwargs):
"""Disallow connection from connector.""" """Disallow connection from connector."""
vol = self._get_volume(volume['id']) vol = self._get_volume(volume['id'])