]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
EMC VMAX - VMAX driver failing to remove zones
authorHelen Walsh <helen.walsh@emc.com>
Fri, 13 Nov 2015 00:42:49 +0000 (00:42 +0000)
committerHelen Walsh <helen.walsh@emc.com>
Fri, 22 Jan 2016 21:35:31 +0000 (21:35 +0000)
The population of the target_wwns and init_targ_map
should occur before the terminate_connection
and not after.

Closes-Bug: #1501938
Change-Id: I3a896a1fcdfd9c09a4c8fa5a1f7fb7253ff36715

cinder/tests/unit/test_emc_vmax.py
cinder/volume/drivers/emc/emc_vmax_common.py
cinder/volume/drivers/emc/emc_vmax_fc.py
cinder/volume/drivers/emc/emc_vmax_iscsi.py
cinder/volume/drivers/emc/emc_vmax_masking.py

index 29088b3c1ebb7c3fca17370f982d18577c4a67c1..1c688e65fe74b05c4b7b0109313f5ea851193ea8 100644 (file)
@@ -7238,3 +7238,117 @@ class EMCVMAXMaskingTest(test.TestCase):
                 maskingviewdict,
                 controllerConfigService, maskingviewdict['volumeName']))
         self.assertIsNone(result)
+
+
+class EMCVMAXFCTest(test.TestCase):
+    def setUp(self):
+        self.data = EMCVMAXCommonData()
+
+        super(EMCVMAXFCTest, self).setUp()
+
+        configuration = mock.Mock()
+        configuration.safe_get.return_value = 'FCTests'
+        configuration.config_group = 'FCTests'
+        emc_vmax_common.EMCVMAXCommon._gather_info = mock.Mock()
+        driver = emc_vmax_fc.EMCVMAXFCDriver(configuration=configuration)
+        driver.db = FakeDB()
+        self.driver = driver
+
+    def test_terminate_connection(self):
+        common = self.driver.common
+        common.conn = FakeEcomConnection()
+        common._unmap_lun = mock.Mock()
+        common.get_masking_view_by_volume = mock.Mock(
+            return_value='testMV')
+        common.get_masking_views_by_port_group = mock.Mock(
+            return_value=[])
+        common.get_target_wwns = mock.Mock(
+            return_value=EMCVMAXCommonData.target_wwns)
+        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']))
+
+    def test_get_common_masking_views_two_exist(self):
+        common = self.driver.common
+        common.conn = FakeEcomConnection()
+        maskingviews = [{'CreationClassName': 'Symm_LunMaskingView',
+                         'ElementName': 'MV1'},
+                        {'CreationClassName': 'Symm_LunMaskingView',
+                         'ElementName': 'MV2'}]
+
+        portGroupInstanceName = (
+            self.driver.common.masking._get_port_group_from_masking_view(
+                common.conn, self.data.lunmaskctrl_name,
+                self.data.storage_system))
+
+        initiatorGroupInstanceName = (
+            self.driver.common.masking._get_initiator_group_from_masking_view(
+                common.conn, self.data.lunmaskctrl_name,
+                self.data.storage_system))
+        common.get_masking_views_by_port_group = mock.Mock(
+            return_value=maskingviews)
+        common.get_masking_views_by_initiator_group = mock.Mock(
+            return_value=maskingviews)
+
+        mvInstances = self.driver._get_common_masking_views(
+            portGroupInstanceName, initiatorGroupInstanceName)
+        self.assertTrue(len(mvInstances) == 2)
+
+    def test_get_common_masking_views_one_overlap(self):
+        common = self.driver.common
+        common.conn = FakeEcomConnection()
+        maskingviewsPG = [{'CreationClassName': 'Symm_LunMaskingView',
+                           'ElementName': 'MV1'},
+                          {'CreationClassName': 'Symm_LunMaskingView',
+                           'ElementName': 'MV2'}]
+
+        maskingviewsIG = [{'CreationClassName': 'Symm_LunMaskingView',
+                           'ElementName': 'MV1'}]
+
+        portGroupInstanceName = (
+            self.driver.common.masking._get_port_group_from_masking_view(
+                common.conn, self.data.lunmaskctrl_name,
+                self.data.storage_system))
+
+        initiatorGroupInstanceName = (
+            self.driver.common.masking._get_initiator_group_from_masking_view(
+                common.conn, self.data.lunmaskctrl_name,
+                self.data.storage_system))
+        common.get_masking_views_by_port_group = mock.Mock(
+            return_value=maskingviewsPG)
+        common.get_masking_views_by_initiator_group = mock.Mock(
+            return_value=maskingviewsIG)
+
+        mvInstances = self.driver._get_common_masking_views(
+            portGroupInstanceName, initiatorGroupInstanceName)
+        self.assertTrue(len(mvInstances) == 1)
+
+    def test_get_common_masking_views_no_overlap(self):
+        common = self.driver.common
+        common.conn = FakeEcomConnection()
+        maskingviewsPG = [{'CreationClassName': 'Symm_LunMaskingView',
+                           'ElementName': 'MV2'}]
+
+        maskingviewsIG = [{'CreationClassName': 'Symm_LunMaskingView',
+                           'ElementName': 'MV1'}]
+
+        portGroupInstanceName = (
+            self.driver.common.masking._get_port_group_from_masking_view(
+                common.conn, self.data.lunmaskctrl_name,
+                self.data.storage_system))
+
+        initiatorGroupInstanceName = (
+            self.driver.common.masking._get_initiator_group_from_masking_view(
+                common.conn, self.data.lunmaskctrl_name,
+                self.data.storage_system))
+        common.get_masking_views_by_port_group = mock.Mock(
+            return_value=maskingviewsPG)
+        common.get_masking_views_by_initiator_group = mock.Mock(
+            return_value=maskingviewsIG)
+
+        mvInstances = self.driver._get_common_masking_views(
+            portGroupInstanceName, initiatorGroupInstanceName)
+        self.assertTrue(len(mvInstances) == 0)
index e6ed9795a5bf766e052324ede7ee7877dec74a5f..d29406a781e4217fbfe37bc4025f995048052d83 100644 (file)
@@ -3691,6 +3691,15 @@ class EMCVMAXCommon(object):
         return self.masking.get_port_group_from_masking_view(
             self.conn, maskingViewInstanceName)
 
+    def get_initiator_group_from_masking_view(self, maskingViewInstanceName):
+        """Get the initiator group in a masking view.
+
+        :param maskingViewInstanceName: masking view instance name
+        :returns: initiatorGroupInstanceName
+        """
+        return self.masking.get_initiator_group_from_masking_view(
+            self.conn, maskingViewInstanceName)
+
     def get_masking_view_by_volume(self, volume, connector):
         """Given volume, retrieve the masking view instance name.
 
@@ -3715,6 +3724,18 @@ class EMCVMAXCommon(object):
         return self.masking.get_masking_views_by_port_group(
             self.conn, portGroupInstanceName)
 
+    def get_masking_views_by_initiator_group(
+            self, initiatorGroupInstanceName):
+        """Given initiator group, retrieve the masking view instance name.
+
+        :param initiatorGroupInstanceName: initiator group instance name
+        :returns: list -- maskingViewInstanceNames
+        """
+        LOG.debug("Finding Masking Views for initiator group %(ig)s.",
+                  {'ig': initiatorGroupInstanceName})
+        return self.masking.get_masking_views_by_initiator_group(
+            self.conn, initiatorGroupInstanceName)
+
     def _create_replica_v3(
             self, repServiceInstanceName, cloneVolume,
             sourceVolume, sourceInstance, isSnapshot, extraSpecs):
index 2c95dc625a15986dc70be1b387c82c806ddb667a..40843c0fb79a4f0ba4ba82baf61face85f1cae6b 100644 (file)
@@ -52,6 +52,7 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
               - Extend Volume for VMAX3, SE8.1.0.3
               https://blueprints.launchpad.net/cinder/+spec/vmax3-extend-volume
               - Incorrect SG selected on an attach (#1515176)
+              - Cleanup Zoning (bug #1501938)  NOTE: FC only
     """
 
     VERSION = "2.3.0"
@@ -217,24 +218,28 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
             portGroupInstanceName = (
                 self.common.get_port_group_from_masking_view(
                     mvInstanceName))
+            initiatorGroupInstanceName = (
+                self.common.get_initiator_group_from_masking_view(
+                    mvInstanceName))
 
             LOG.debug("Found port group: %(portGroup)s "
                       "in masking view %(maskingView)s.",
                       {'portGroup': portGroupInstanceName,
                        'maskingView': mvInstanceName})
+            # Map must be populated before the terminate_connection
+            target_wwns, init_targ_map = self._build_initiator_target_map(
+                storage_system, volume, connector)
 
             self.common.terminate_connection(volume, connector)
 
             LOG.debug("Looking for masking views still associated with "
                       "Port Group %s.", portGroupInstanceName)
-            mvInstances = self.common.get_masking_views_by_port_group(
-                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.
-                target_wwns, init_targ_map = self._build_initiator_target_map(
-                    storage_system, volume, connector)
                 LOG.debug("No MaskingViews were found. Deleting zone.")
                 data = {'driver_volume_type': 'fibre_channel',
                         'data': {'target_wwn': target_wwns,
@@ -246,6 +251,21 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
                         {'volume': volume['name']})
         return data
 
+    def _get_common_masking_views(
+            self, portGroupInstanceName, initiatorGroupInstanceName):
+        """Check to see the existence of mv in list"""
+        mvInstances = []
+        mvInstancesByPG = self.common.get_masking_views_by_port_group(
+            portGroupInstanceName)
+
+        mvInstancesByIG = self.common.get_masking_views_by_initiator_group(
+            initiatorGroupInstanceName)
+
+        for mvInstanceByPG in mvInstancesByPG:
+            if mvInstanceByPG in mvInstancesByIG:
+                mvInstances.append(mvInstanceByPG)
+        return mvInstances
+
     def _build_initiator_target_map(self, storage_system, volume, connector):
         """Build the target_wwns and the initiator target map."""
         target_wwns = []
index 489ae583be480e031f2b88f6daf5f5d77661b002..3240754a59fb7a9ca569a0b4cab18943be268134 100644 (file)
@@ -58,6 +58,7 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
               - Extend Volume for VMAX3, SE8.1.0.3
               https://blueprints.launchpad.net/cinder/+spec/vmax3-extend-volume
               - Incorrect SG selected on an attach (#1515176)
+              - Cleanup Zoning (bug #1501938)  NOTE: FC only
     """
 
     VERSION = "2.3.0"
index b4b595bbc2d8d8d67a5b05a79a55d52a48d21ed6..d2bed73f887c6224830f4e55c25f87e572d1ae1a 100644 (file)
@@ -2158,6 +2158,19 @@ class EMCVMAXMasking(object):
             portGroupInstanceName, ResultClass='Symm_LunMaskingView')
         return mvInstanceNames
 
+    def get_masking_views_by_initiator_group(
+            self, conn, initiatorGroupInstanceName):
+        """Given initiator group, retrieve the masking view instance name.
+
+        :param conn: the ecom connection
+        :param initiatorGroupInstanceName: the instance name of the
+                                           initiator group
+        :returns: masking view instance names
+        """
+        mvInstanceNames = conn.AssociatorNames(
+            initiatorGroupInstanceName, ResultClass='Symm_LunMaskingView')
+        return mvInstanceNames
+
     def get_port_group_from_masking_view(self, conn, maskingViewInstanceName):
         """Get the port group in a masking view.