VMAX driver - Cleanup of Initiator group fails
When the last volume has been deleted from the Storage Group and the Masking View has been deleted and the initiator group is no longer in use, the deletion of the Initiator group fails. The initiator group is actually deleted off the array, but the code is throwing up an error when it uses the now deleted initiator group name to search for remaining masking views. The solution is to check if the initiator group has been deleted by common.terminate_connection before searching for remaining masking views. Change-Id: I79559789459f73c4adebf010d84cbeedd25f7f74 Closes-Bug: #1605193
This commit is contained in:
parent
781475f114
commit
8e62557f6e
@ -4841,9 +4841,9 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
|
||||
self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
emc_vmax_masking.EMCVMAXMasking,
|
||||
'get_initiator_group_from_masking_view',
|
||||
return_value='myInitGroup')
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'check_ig_instance_name',
|
||||
return_value=None)
|
||||
@mock.patch.object(
|
||||
emc_vmax_masking.EMCVMAXMasking,
|
||||
'_find_initiator_masking_group',
|
||||
@ -4857,7 +4857,8 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
|
||||
'get_volume_type_extra_specs',
|
||||
return_value={'volume_backend_name': 'FCNoFAST'})
|
||||
def test_detach_no_fast_last_volume_success(
|
||||
self, mock_volume_type, mock_mv, mock_ig, mock_igc):
|
||||
self, mock_volume_type, mock_mv, mock_ig, mock_check_ig):
|
||||
# last volume so initiatorGroup will be deleted by terminate connection
|
||||
self.driver.terminate_connection(self.data.test_source_volume,
|
||||
self.data.connector)
|
||||
|
||||
@ -5431,6 +5432,10 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
||||
self.data.test_volume,
|
||||
self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'check_ig_instance_name',
|
||||
return_value='myInitGroup')
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'get_masking_views_by_port_group',
|
||||
@ -5453,7 +5458,7 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
||||
return_value={'volume_backend_name': 'FCFAST',
|
||||
'FASTPOLICY': 'FC_GOLD1'})
|
||||
def test_detach_fast_success(self, mock_volume_type, mock_maskingview,
|
||||
mock_ig, mock_igc, mock_mv):
|
||||
mock_ig, mock_igc, mock_mv, mock_check_ig):
|
||||
common = self.driver.common
|
||||
common.get_target_wwns = mock.Mock(
|
||||
return_value=EMCVMAXCommonData.target_wwns)
|
||||
@ -6470,6 +6475,10 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
self.data.test_volume,
|
||||
self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'check_ig_instance_name',
|
||||
return_value='myInitGroup')
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'get_masking_views_by_port_group',
|
||||
@ -6491,7 +6500,7 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
'get_volume_type_extra_specs',
|
||||
return_value={'volume_backend_name': 'V3_BE'})
|
||||
def test_detach_v3_success(self, mock_volume_type, mock_maskingview,
|
||||
mock_ig, mock_igc, mock_mv):
|
||||
mock_ig, mock_igc, mock_mv, mock_check_ig):
|
||||
common = self.driver.common
|
||||
common.get_target_wwns = mock.Mock(
|
||||
return_value=EMCVMAXCommonData.target_wwns)
|
||||
@ -7847,7 +7856,7 @@ class EMCVMAXFCTest(test.TestCase):
|
||||
driver.db = FakeDB()
|
||||
self.driver = driver
|
||||
|
||||
def test_terminate_connection(self):
|
||||
def test_terminate_connection_ig_present(self):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
common._unmap_lun = mock.Mock()
|
||||
@ -7857,6 +7866,44 @@ class EMCVMAXFCTest(test.TestCase):
|
||||
return_value=[])
|
||||
common.get_target_wwns = mock.Mock(
|
||||
return_value=EMCVMAXCommonData.target_wwns)
|
||||
initiatorGroupInstanceName = (
|
||||
self.driver.common.masking._get_initiator_group_from_masking_view(
|
||||
common.conn, self.data.lunmaskctrl_name,
|
||||
self.data.storage_system))
|
||||
with mock.patch.object(self.driver.common,
|
||||
'check_ig_instance_name',
|
||||
return_value=initiatorGroupInstanceName):
|
||||
data = self.driver.terminate_connection(self.data.test_volume_v3,
|
||||
self.data.connector)
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
EMCVMAXCommonData.storage_system, EMCVMAXCommonData.connector)
|
||||
numTargetWwns = len(EMCVMAXCommonData.target_wwns)
|
||||
self.assertEqual(numTargetWwns, len(data['data']))
|
||||
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'check_ig_instance_name',
|
||||
return_value=None)
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'get_target_wwns',
|
||||
return_value=EMCVMAXCommonData.target_wwns)
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'get_masking_views_by_port_group',
|
||||
return_value=[])
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'get_masking_view_by_volume',
|
||||
return_value='testMV')
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'_unmap_lun')
|
||||
def test_terminate_connection_no_ig(self, mock_unmap,
|
||||
mock_mv_vol, mock_mv_pg,
|
||||
mock_wwns, mock_check_ig):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
data = self.driver.terminate_connection(self.data.test_volume_v3,
|
||||
self.data.connector)
|
||||
common.get_target_wwns.assert_called_once_with(
|
||||
@ -8217,6 +8264,30 @@ class EMCVMAXUtilsTest(test.TestCase):
|
||||
foundIqn = self.driver.utils.get_iqn(conn, ipprotocolendpoints[1])
|
||||
self.assertEqual(iqn, foundIqn)
|
||||
|
||||
# bug #1605193 - Cleanup of Initiator Group fails
|
||||
def test_check_ig_instance_name_present(self):
|
||||
conn = FakeEcomConnection()
|
||||
initiatorgroup = SE_InitiatorMaskingGroup()
|
||||
initiatorgroup['CreationClassName'] = (
|
||||
self.data.initiatorgroup_creationclass)
|
||||
initiatorgroup['DeviceID'] = self.data.initiatorgroup_id
|
||||
initiatorgroup['SystemName'] = self.data.storage_system
|
||||
initiatorgroup['ElementName'] = self.data.initiatorgroup_name
|
||||
foundIg = self.driver.utils.check_ig_instance_name(
|
||||
conn, initiatorgroup)
|
||||
self.assertEqual(initiatorgroup, foundIg)
|
||||
|
||||
# bug #1605193 - Cleanup of Initiator Group fails
|
||||
def test_check_ig_instance_name_not_present(self):
|
||||
conn = FakeEcomConnection()
|
||||
initiatorgroup = None
|
||||
with mock.patch.object(self.driver.utils,
|
||||
'get_existing_instance',
|
||||
return_value=None):
|
||||
foundIg = self.driver.utils.check_ig_instance_name(
|
||||
conn, initiatorgroup)
|
||||
self.assertIsNone(foundIg)
|
||||
|
||||
|
||||
class EMCVMAXCommonTest(test.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -549,6 +549,15 @@ class EMCVMAXCommon(object):
|
||||
data=exception_message)
|
||||
return portGroupName
|
||||
|
||||
def check_ig_instance_name(self, initiatorGroupInstanceName):
|
||||
"""Check if an initiator group instance is on the array.
|
||||
|
||||
:param initiatorGroupInstanceName: initiator group instance name
|
||||
:returns: initiator group name, or None if deleted
|
||||
"""
|
||||
return self.utils.check_ig_instance_name(
|
||||
self.conn, initiatorGroupInstanceName)
|
||||
|
||||
def terminate_connection(self, volume, connector):
|
||||
"""Disallow connection from connector.
|
||||
|
||||
|
@ -245,18 +245,38 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
|
||||
|
||||
LOG.debug("Looking for masking views still associated with "
|
||||
"Port Group %s.", portGroupInstanceName)
|
||||
mvInstances = self._get_common_masking_views(
|
||||
portGroupInstanceName, initiatorGroupInstanceName)
|
||||
if len(mvInstances) > 0:
|
||||
LOG.debug("Found %(numViews)lu MaskingViews.",
|
||||
{'numViews': len(mvInstances)})
|
||||
else: # No views found.
|
||||
LOG.debug("No MaskingViews were found. Deleting zone.")
|
||||
# check if the initiator group has been deleted
|
||||
checkIgInstanceName = (
|
||||
self.common.check_ig_instance_name(initiatorGroupInstanceName))
|
||||
|
||||
# if it has not been deleted, check for remaining masking views
|
||||
if checkIgInstanceName is not None:
|
||||
mvInstances = self._get_common_masking_views(
|
||||
portGroupInstanceName, initiatorGroupInstanceName)
|
||||
|
||||
if len(mvInstances) > 0:
|
||||
LOG.debug("Found %(numViews)lu MaskingViews.",
|
||||
{'numViews': len(mvInstances)})
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
else: # no masking views found
|
||||
LOG.debug("No MaskingViews were found. Deleting zone.")
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {'target_wwn': target_wwns,
|
||||
'initiator_target_map': init_targ_map}}
|
||||
|
||||
LOG.debug("Return FC data for zone removal: %(data)s.",
|
||||
{'data': data})
|
||||
|
||||
else: # The initiator group has been deleted
|
||||
LOG.debug("Initiator Group has been deleted. Deleting zone.")
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {'target_wwn': target_wwns,
|
||||
'initiator_target_map': init_targ_map}}
|
||||
LOG.debug("Return FC data for zone removal: %(data)s.",
|
||||
{'data': data})
|
||||
|
||||
LOG.debug("Return FC data for zone removal: %(data)s.",
|
||||
{'data': data})
|
||||
|
||||
else:
|
||||
LOG.warning(_LW("Volume %(volume)s is not in any masking view."),
|
||||
{'volume': volume['name']})
|
||||
|
@ -2812,3 +2812,23 @@ class EMCVMAXUtils(object):
|
||||
cimProperties = properties[1]
|
||||
foundIqn = cimProperties.value
|
||||
return foundIqn
|
||||
|
||||
def check_ig_instance_name(
|
||||
self, conn, initiatorGroupInstanceName):
|
||||
"""Check if a given Initiator Group Instance Name has been deleted.
|
||||
|
||||
:param conn: the ecom connection
|
||||
:param initiatorGroupInstanceName: the given IG instance name
|
||||
:return: foundinitiatorGroupInstanceName or None if deleted
|
||||
"""
|
||||
foundinitiatorGroupInstanceName = self.get_existing_instance(
|
||||
conn, initiatorGroupInstanceName)
|
||||
if foundinitiatorGroupInstanceName is not None:
|
||||
LOG.debug("Found initiator group name: "
|
||||
"%(igName)s.",
|
||||
{'igName': foundinitiatorGroupInstanceName})
|
||||
else:
|
||||
LOG.debug("Could not find initiator group name: "
|
||||
"%(igName)s.",
|
||||
{'igName': foundinitiatorGroupInstanceName})
|
||||
return foundinitiatorGroupInstanceName
|
||||
|
Loading…
Reference in New Issue
Block a user