]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Use look up service for auto zoning
authorXing Yang <xing.yang@emc.com>
Thu, 9 Oct 2014 05:26:28 +0000 (01:26 -0400)
committerXing Yang <xing.yang@emc.com>
Mon, 27 Oct 2014 21:56:20 +0000 (17:56 -0400)
The VMAX FC driver didn't use the look up service for auto zoning.
Instead it built initiator target map itself. However, that
requires the initiator to log into the fabric before zoning
in order to find out target WWNs.

This patch is to use the look up service to find out valid initiator
target WWNS and use that to build initiator target map. With this fix,
the initiator is no longer required to log into the fabric ahead of time.

Change-Id: I76e1a8a2e7d4230b851b763f7d13dd1489b69364
Closes-Bug: #1379156

cinder/tests/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_masking.py

index de26053bb4a5f92f1a9b44dd22c7d8051ace144d..5bbd40e24d56bed9f46ceedf64b31c47adabd4f1 100644 (file)
@@ -128,13 +128,31 @@ class FakeDB():
 
 
 class EMCVMAXCommonData():
+    wwpn1 = "123456789012345"
+    wwpn2 = "123456789054321"
     connector = {'ip': '10.0.0.2',
                  'initiator': 'iqn.1993-08.org.debian: 01: 222',
-                 'wwpns': ["123456789012345", "123456789054321"],
+                 'wwpns': [wwpn1, wwpn2],
                  'wwnns': ["223456789012345", "223456789054321"],
                  'host': 'fakehost'}
+
+    target_wwns = [wwn[::-1] for wwn in connector['wwpns']]
+
+    fabric_name_prefix = "fakeFabric"
+    end_point_map = {connector['wwpns'][0]: [target_wwns[0]],
+                     connector['wwpns'][1]: [target_wwns[1]]}
+    device_map = {}
+    for wwn in connector['wwpns']:
+        fabric_name = ''.join([fabric_name_prefix,
+                              wwn[-2:]])
+        target_wwn = wwn[::-1]
+        fabric_map = {'initiator_port_wwn_list': [wwn],
+                      'target_port_wwn_list': [target_wwn]
+                      }
+        device_map[fabric_name] = fabric_map
+
     default_storage_group = (
-        u'//10.108.246.202/root/emc: SE_DeviceMaskingGroup.InstanceID='
+        u'//10.10.10.10/root/emc: SE_DeviceMaskingGroup.InstanceID='
         '"SYMMETRIX+000198700440+OS_default_GOLD1_SG"')
     storage_system = 'SYMMETRIX+000195900551'
     lunmaskctrl_id =\
@@ -245,6 +263,11 @@ class EMCVMAXCommonData():
     diff = {}
 
 
+class FakeLookupService():
+    def get_device_mapping_from_network(self, initiator_wwns, target_wwns):
+        return EMCVMAXCommonData.device_map
+
+
 class FakeEcomConnection():
 
     def __init__(self, *args, **kwargs):
@@ -302,10 +325,12 @@ class FakeEcomConnection():
             targetendpoints = {}
             endpoints = []
             endpoint = {}
-            endpoint['Name'] = '1234567890123'
+            endpoint['Name'] = (EMCVMAXCommonData.end_point_map[
+                EMCVMAXCommonData.connector['wwpns'][0]])
             endpoints.append(endpoint)
             endpoint2 = {}
-            endpoint2['Name'] = '0987654321321'
+            endpoint2['Name'] = (EMCVMAXCommonData.end_point_map[
+                EMCVMAXCommonData.connector['wwpns'][1]])
             endpoints.append(endpoint2)
             targetendpoints['TargetEndpoints'] = endpoints
             return rc, targetendpoints
@@ -428,6 +453,8 @@ class FakeEcomConnection():
             result = self._enum_storage_extent()
         elif ResultClass == 'SE_StorageHardwareID':
             result = self._enum_storhdwids()
+        elif ResultClass == 'Symm_FCSCSIProtocolEndpoint':
+            result = self._enum_fcscsiendpoint()
 
         else:
             result = self._default_assocnames(objectpath)
@@ -571,7 +598,6 @@ class FakeEcomConnection():
             foundinstance = None
         else:
             foundinstance = instance
-
         return foundinstance
 
     def _getinstance_lunmask(self):
@@ -793,8 +819,6 @@ class FakeEcomConnection():
         initatorgroup['DeviceID'] = self.data.initiatorgroup_id
         initatorgroup['SystemName'] = self.data.storage_system
         initatorgroup['ElementName'] = self.data.initiatorgroup_name
-#         initatorgroup.path = initatorgroup
-#         initatorgroup.path.classname = initatorgroup['CreationClassName']
         initatorgroups.append(initatorgroup)
         return initatorgroups
 
@@ -909,6 +933,13 @@ class FakeEcomConnection():
         storhdwids.append(hdwid)
         return storhdwids
 
+    def _enum_fcscsiendpoint(self):
+        wwns = []
+        wwn = {}
+        wwn['Name'] = "5000090000000000"
+        wwns.append(wwn)
+        return wwns
+
     def _default_enum(self):
         names = []
         name = {}
@@ -1018,10 +1049,10 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         self.config_file_1364232 = self.tempdir + '/' + filename
         text_file = open(self.config_file_1364232, "w")
         text_file.write("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
-                        "<EcomServerIp>10.108.246.202</EcomServerIp>\n"
+                        "<EcomServerIp>10.10.10.10</EcomServerIp>\n"
                         "<EcomServerPort>5988</EcomServerPort>\n"
-                        "<EcomUserName>admin\t</EcomUserName>\n"
-                        "<EcomPassword>#1Password</EcomPassword>\n"
+                        "<EcomUserName>user\t</EcomUserName>\n"
+                        "<EcomPassword>password</EcomPassword>\n"
                         "<PortGroups><PortGroup>OS-PORTGROUP1-PG"
                         "</PortGroup><PortGroup>OS-PORTGROUP2-PG"
                         "                </PortGroup>\n"
@@ -1919,6 +1950,8 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
 
         driver = EMCVMAXFCDriver(configuration=configuration)
         driver.db = FakeDB()
+        driver.common.conn = FakeEcomConnection()
+        driver.zonemanager_lookup_service = FakeLookupService()
         self.driver = driver
 
     def create_fake_config_file_no_fast(self):
@@ -2098,30 +2131,44 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
     @mock.patch.object(
         volume_types,
         'get_volume_type_extra_specs',
-        return_value={'volume_backend_name': 'FCNoFAST'})
+        return_value={'volume_backend_name': 'FCNoFAST',
+                      'FASTPOLICY': 'FC_GOLD1'})
     @mock.patch.object(
         EMCVMAXMasking,
-        '_wrap_get_storage_group_from_volume',
-        return_value=None)
-    @mock.patch.object(
-        EMCVMAXCommon,
-        '_wrap_find_device_number',
-        return_value={'hostlunid': 1,
-                      'storagesystem': EMCVMAXCommonData.storage_system})
-    def test_map_no_fast_success(self, _mock_volume_type, mock_wrap_group,
-                                 mock_wrap_device):
-        self.driver.initialize_connection(self.data.test_volume,
-                                          self.data.connector)
+        'get_masking_view_from_storage_group',
+        return_value=EMCVMAXCommonData.lunmaskctrl_name)
+    def test_map_lookup_service_no_fast_success(
+            self, _mock_volume_type, mock_maskingview):
+        self.data.test_volume['volume_name'] = "vmax-1234567"
+        common = self.driver.common
+        common.get_target_wwns_from_masking_view = mock.Mock(
+            return_value=EMCVMAXCommonData.target_wwns)
+        lookup_service = self.driver.zonemanager_lookup_service
+        lookup_service.get_device_mapping_from_network = mock.Mock(
+            return_value=EMCVMAXCommonData.device_map)
+        data = self.driver.initialize_connection(self.data.test_volume,
+                                                 self.data.connector)
+        common.get_target_wwns_from_masking_view.assert_called_once_with(
+            EMCVMAXCommonData.storage_system, self.data.test_volume,
+            EMCVMAXCommonData.connector)
+        lookup_service.get_device_mapping_from_network.assert_called_once_with(
+            EMCVMAXCommonData.connector['wwpns'],
+            EMCVMAXCommonData.target_wwns)
+
+        # Test the lookup service code path.
+        for init, target in data['data']['initiator_target_map'].items():
+            self.assertEqual(init, target[0][::-1])
 
     @mock.patch.object(
-        EMCVMAXMasking,
-        '_wrap_get_storage_group_from_volume',
-        return_value=None)
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'FCNoFAST',
+                      'FASTPOLICY': 'FC_GOLD1'})
     @mock.patch.object(
         EMCVMAXCommon,
-        '_wrap_find_device_number',
-        return_value={'storagesystem': EMCVMAXCommonData.storage_system})
-    def test_map_no_fast_failed(self, mock_wrap_group, mock_wrap_device):
+        'find_device_number',
+        return_value={'Name': "0001"})
+    def test_map_no_fast_failed(self, mock_wrap_group, mock_maskingview):
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.initialize_connection,
                           self.data.test_volume,
@@ -2133,12 +2180,10 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
         return_value={'volume_backend_name': 'FCNoFAST',
                       'FASTPOLICY': 'FC_GOLD1'})
     @mock.patch.object(
-        EMCVMAXUtils,
-        'find_storage_masking_group',
-        return_value=EMCVMAXCommonData.storagegroupname)
-    def test_detach_no_fast_success(self, mock_volume_type,
-                                    mock_storage_group):
-
+        EMCVMAXMasking,
+        'get_masking_view_by_volume',
+        return_value=EMCVMAXCommonData.lunmaskctrl_name)
+    def test_detach_no_fast_success(self, mock_volume_type, mock_maskingview):
         self.driver.terminate_connection(self.data.test_volume,
                                          self.data.connector)
 
@@ -2147,16 +2192,12 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
         'get_volume_type_extra_specs',
         return_value={'volume_backend_name': 'FCNoFAST'})
     @mock.patch.object(
-        EMCVMAXUtils, 'find_storage_system',
-        return_value={'Name': EMCVMAXCommonData.storage_system})
-    @mock.patch.object(
-        EMCVMAXUtils,
-        'find_storage_masking_group',
-        return_value=EMCVMAXCommonData.storagegroupname)
-    def test_detach_no_fast_last_volume_success(self, mock_volume_type,
-                                                mock_storage_system,
-                                                mock_storage_group):
-        self.driver.terminate_connection(self.data.test_volume,
+        EMCVMAXMasking,
+        'get_masking_view_by_volume',
+        return_value=EMCVMAXCommonData.lunmaskctrl_name)
+    def test_detach_no_fast_last_volume_success(
+            self, mock_volume_type, mock_mv):
+        self.driver.terminate_connection(self.data.test_source_volume,
                                          self.data.connector)
 
     @mock.patch.object(
@@ -2319,6 +2360,8 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
 
         driver = EMCVMAXFCDriver(configuration=configuration)
         driver.db = FakeDB()
+        driver.common.conn = FakeEcomConnection()
+        driver.zonemanager_lookup_service = None
         self.driver = driver
 
     def create_fake_config_file_fast(self):
@@ -2523,30 +2566,35 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
     @mock.patch.object(
         volume_types,
         'get_volume_type_extra_specs',
-        return_value={'volume_backend_name': 'FCFAST'})
+        return_value={'volume_backend_name': 'FCFAST',
+                      'FASTPOLICY': 'FC_GOLD1'})
     @mock.patch.object(
         EMCVMAXMasking,
-        '_wrap_get_storage_group_from_volume',
-        return_value=None)
-    @mock.patch.object(
-        EMCVMAXCommon,
-        '_wrap_find_device_number',
-        return_value={'hostlunid': 1,
-                      'storagesystem': EMCVMAXCommonData.storage_system})
-    def test_map_fast_success(self, _mock_volume_type, mock_wrap_group,
-                              mock_wrap_device):
-        self.driver.initialize_connection(self.data.test_volume,
-                                          self.data.connector)
+        'get_masking_view_from_storage_group',
+        return_value=EMCVMAXCommonData.lunmaskctrl_name)
+    def test_map_fast_success(self, _mock_volume_type, mock_maskingview):
+        self.data.test_volume['volume_name'] = "vmax-1234567"
+        common = self.driver.common
+        common.get_target_wwns = mock.Mock(
+            return_value=EMCVMAXCommonData.target_wwns)
+        data = self.driver.initialize_connection(
+            self.data.test_volume, self.data.connector)
+        # Test the no lookup service, pre-zoned case.
+        common.get_target_wwns.assert_called_once_with(
+            EMCVMAXCommonData.storage_system, EMCVMAXCommonData.connector)
+        for init, target in data['data']['initiator_target_map'].items():
+            self.assertIn(init[::-1], target)
 
     @mock.patch.object(
-        EMCVMAXMasking,
-        '_wrap_get_storage_group_from_volume',
-        return_value=None)
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'FCFAST',
+                      'FASTPOLICY': 'FC_GOLD1'})
     @mock.patch.object(
         EMCVMAXCommon,
-        '_wrap_find_device_number',
-        return_value={'storagesystem': EMCVMAXCommonData.storage_system})
-    def test_map_fast_failed(self, mock_wrap_group, mock_wrap_device):
+        'find_device_number',
+        return_value={'Name': "0001"})
+    def test_map_fast_failed(self, mock_wrap_group, mock_maskingview):
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.initialize_connection,
                           self.data.test_volume,
@@ -2558,31 +2606,19 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
         return_value={'volume_backend_name': 'FCFAST',
                       'FASTPOLICY': 'FC_GOLD1'})
     @mock.patch.object(
-        EMCVMAXUtils,
-        'find_storage_masking_group',
-        return_value=EMCVMAXCommonData.storagegroupname)
-    def test_detach_fast_success(self, mock_volume_type,
-                                 mock_storage_group):
-
-        self.driver.terminate_connection(self.data.test_volume,
-                                         self.data.connector)
-
-    @mock.patch.object(
-        volume_types,
-        'get_volume_type_extra_specs',
-        return_value={'volume_backend_name': 'FCFAST'})
-    @mock.patch.object(
-        EMCVMAXUtils, 'find_storage_system',
-        return_value={'Name': EMCVMAXCommonData.storage_system})
-    @mock.patch.object(
-        EMCVMAXUtils,
-        'find_storage_masking_group',
-        return_value=EMCVMAXCommonData.storagegroupname)
-    def test_detach_fast_last_volume_success(
-            self, mock_volume_type,
-            mock_storage_system, mock_storage_group):
-        self.driver.terminate_connection(self.data.test_volume,
-                                         self.data.connector)
+        EMCVMAXMasking,
+        'get_masking_view_by_volume',
+        return_value=EMCVMAXCommonData.lunmaskctrl_name)
+    def test_detach_fast_success(self, mock_volume_type, mock_maskingview):
+        common = self.driver.common
+        common.get_target_wwns = mock.Mock(
+            return_value=EMCVMAXCommonData.target_wwns)
+        data = self.driver.terminate_connection(self.data.test_volume,
+                                                self.data.connector)
+        common.get_target_wwns.assert_called_once_with(
+            EMCVMAXCommonData.storage_system, EMCVMAXCommonData.connector)
+
+        self.assertEqual(0, len(data['data']))
 
     @mock.patch.object(
         volume_types,
index 238029f852d0e63728839787947b71d83ac9c355..04738a02f9e0f0a33b613dfa639f775f72655a5a 100644 (file)
@@ -1264,6 +1264,8 @@ class EMCVMAXCommon(object):
         volumename = volume['name']
 
         loc = volume['provider_location']
+        if self.conn is None:
+            self.conn = self._get_ecom_connection()
         if isinstance(loc, six.string_types):
             name = eval(loc)
 
@@ -2185,3 +2187,54 @@ class EMCVMAXCommon(object):
                      'connector': connector})
 
         return numVolumesMapped
+
+    def get_target_wwns_from_masking_view(
+            self, storageSystem, volume, connector):
+        """Find target WWNs via the masking view.
+
+        :param storageSystem: the storage system name
+        :param volume: volume to be attached
+        :param connector: the connector dict
+        :returns: targetWwns, the target WWN list
+        """
+        targetWwns = []
+        mvInstanceName = self.get_masking_view_by_volume(volume)
+        targetWwns = self.masking.get_target_wwns(self.conn, mvInstanceName)
+        LOG.info("Target wwns in masking view %(maskingView)s: %(targetWwns)s"
+                 % {'maskingView': mvInstanceName,
+                    'targetWwns': str(targetWwns)})
+        return targetWwns
+
+    def get_port_group_from_masking_view(self, maskingViewInstanceName):
+        """Find port group that is part of a masking view.
+
+        :param maskingViewInstanceName: the owning masking view
+        :returns: port group instance name
+        """
+        return self.masking.get_port_group_from_masking_view(
+            self.conn, maskingViewInstanceName)
+
+    def get_masking_view_by_volume(self, volume):
+        """Given volume, retrieve the masking view instance name
+
+        :param volume: the volume
+        :param mvInstanceName: masking view instance name
+        :returns maskingviewInstanceName
+        """
+        LOG.debug("Finding Masking View for volume %(volume)s"
+                  % {'volume': volume})
+        volumeInstance = self._find_lun(volume)
+        return self.masking.get_masking_view_by_volume(
+            self.conn, volumeInstance)
+
+    def get_masking_views_by_port_group(self, portGroupInstanceName):
+        """Given port group, retrieve the masking view instance name
+
+        :param : the volume
+        :param mvInstanceName: masking view instance name
+        :returns: maksingViewInstanceNames
+        """
+        LOG.debug("Finding Masking Views for port group %(pg)s"
+                  % {'pg': portGroupInstanceName})
+        return self.masking.get_masking_views_by_port_group(
+            self.conn, portGroupInstanceName)
index b5aba28515817d8b3c43276df17f3398f5e4f552..abc6f445bd07067cb24c3d16a010b260964f2768 100644 (file)
@@ -20,7 +20,6 @@ from cinder.volume import driver
 from cinder.volume.drivers.emc import emc_vmax_common
 from cinder.zonemanager import utils as fczm_utils
 
-
 LOG = logging.getLogger(__name__)
 
 
@@ -42,6 +41,7 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
         self.common = emc_vmax_common.EMCVMAXCommon(
             'FC',
             configuration=self.configuration)
+        self.zonemanager_lookup_service = fczm_utils.create_lookup_service()
 
     def check_for_setup_error(self):
         pass
@@ -154,7 +154,7 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
         device_number = device_info['hostlunid']
         storage_system = device_info['storagesystem']
         target_wwns, init_targ_map = self._build_initiator_target_map(
-            storage_system, connector)
+            storage_system, volume, connector)
 
         data = {'driver_volume_type': 'fibre_channel',
                 'data': {'target_lun': device_number,
@@ -162,7 +162,7 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
                          'target_wwn': target_wwns,
                          'initiator_target_map': init_targ_map}}
 
-        LOG.debug("Return FC data: %(data)s."
+        LOG.debug("Return FC data for zone addition: %(data)s."
                   % {'data': data})
 
         return data
@@ -179,40 +179,71 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
         :returns: data - the target_wwns and initiator_target_map if the
                          zone is to be removed, otherwise empty
         """
-        self.common.terminate_connection(volume, connector)
-
         loc = volume['provider_location']
         name = eval(loc)
         storage_system = name['keybindings']['SystemName']
+        LOG.info("Start FC detach process for volume: %(volume)s"
+                 % {'volume': volume['name']})
+
+        target_wwns, init_targ_map = self._build_initiator_target_map(
+            storage_system, volume, connector)
+
+        mvInstanceName = self.common.get_masking_view_by_volume(volume)
+        portGroupInstanceName = self.common.get_port_group_from_masking_view(
+            mvInstanceName)
+
+        LOG.info("Found port group: %(portGroup)s "
+                 "in masking view %(maskingView)s"
+                 % {'portGroup': portGroupInstanceName,
+                    'maskingView': mvInstanceName})
 
-        numVolumes = self.common.get_num_volumes_mapped(volume, connector)
-        if numVolumes > 0:
+        self.common.terminate_connection(volume, connector)
+
+        LOG.info("Looking for masking views still associated with"
+                 "Port Group %s" % portGroupInstanceName)
+        mvInstances = self.common.get_masking_views_by_port_group(
+            portGroupInstanceName)
+        if len(mvInstances) > 0:
+            LOG.debug("Found %(numViews)lu maskingviews."
+                      % {'numViews': len(mvInstances)})
             data = {'driver_volume_type': 'fibre_channel',
                     'data': {}}
-        else:
-            target_wwns, init_targ_map = self._build_initiator_target_map(
-                storage_system, connector)
+        else:  # no views found
+            LOG.debug("No Masking Views 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: %(data)s."
+        LOG.debug("Return FC data for zone removal: %(data)s."
                   % {'data': data})
 
         return data
 
-    def _build_initiator_target_map(self, storage_system, connector):
+    def _build_initiator_target_map(self, storage_system, volume, connector):
         """Build the target_wwns and the initiator target map."""
-
-        target_wwns = self.common.get_target_wwns(storage_system, connector)
+        target_wwns = []
+        init_targ_map = {}
 
         initiator_wwns = connector['wwpns']
 
-        init_targ_map = {}
-        for initiator in initiator_wwns:
-            init_targ_map[initiator] = target_wwns
-
-        return target_wwns, init_targ_map
+        if self.zonemanager_lookup_service:
+            fc_targets = self.common.get_target_wwns_from_masking_view(
+                storage_system, volume, connector)
+            mapping = (
+                self.zonemanager_lookup_service.
+                get_device_mapping_from_network(initiator_wwns, fc_targets))
+            for entry in mapping:
+                map_d = mapping[entry]
+                target_wwns.extend(map_d['target_port_wwn_list'])
+                for initiator in map_d['initiator_port_wwn_list']:
+                    init_targ_map[initiator] = map_d['target_port_wwn_list']
+        else:  # no lookup service, pre-zoned case
+            target_wwns = self.common.get_target_wwns(storage_system,
+                                                      connector)
+            for initiator in initiator_wwns:
+                init_targ_map[initiator] = target_wwns
+
+        return list(set(target_wwns)), init_targ_map
 
     def extend_volume(self, volume, new_size):
         """Extend an existing volume."""
index 79379420100ebe26c57103460ecdf388c1be242a..4386a1874535d27a3f838ddc3a7255c38133b91f 100644 (file)
@@ -1396,3 +1396,64 @@ class EMCVMAXMasking(object):
         LOG.debug(
             "end: number of volumes in default storage group: %(numVol)d"
             % {'numVol': len(volumeInstanceNames)})
+
+    def get_target_wwns(self, conn, mvInstanceName):
+        """Get the DA ports' wwns.
+
+        :param conn: the ecom connection
+        :param mvInstanceName: masking view instance name
+        """
+        targetWwns = []
+        targetPortInstanceNames = conn.AssociatorNames(
+            mvInstanceName,
+            ResultClass='Symm_FCSCSIProtocolEndpoint')
+        numberOfPorts = len(targetPortInstanceNames)
+        if numberOfPorts <= 0:
+            LOG.warn("No target ports found in "
+                     "masking view %(maskingView)s"
+                     % {'numPorts': len(targetPortInstanceNames),
+                        'maskingView': mvInstanceName})
+        for targetPortInstanceName in targetPortInstanceNames:
+            targetWwns.append(targetPortInstanceName['Name'])
+        return targetWwns
+
+    def get_masking_view_by_volume(self, conn, volumeInstance):
+        """Given volume, retrieve the masking view instance name.
+
+        :param volume: the volume instance
+        :param mvInstanceName: masking view instance name
+        """
+        sgInstanceName = self.get_associated_masking_group_from_device(
+            conn, volumeInstance.path)
+        mvInstanceName = self.get_masking_view_from_storage_group(
+            conn, sgInstanceName)
+        LOG.debug("Found Masking View %(mv)s: " % {'mv': mvInstanceName})
+        return mvInstanceName
+
+    def get_masking_views_by_port_group(self, conn, portGroupInstanceName):
+        """Given port group, retrieve the masking view instance name.
+
+        :param : the volume
+        :param mvInstanceName: masking view instance name
+        :returns: maksingViewInstanceNames
+        """
+        mvInstanceNames = conn.AssociatorNames(
+            portGroupInstanceName, ResultClass='Symm_LunMaskingView')
+        return mvInstanceNames
+
+    def get_port_group_from_masking_view(self, conn, maskingViewInstanceName):
+        """Get the port group in a masking view.
+
+        :param maskingViewInstanceName: masking view instance name
+        :returns: portGroupInstanceName
+        """
+        portGroupInstanceNames = conn.AssociatorNames(
+            maskingViewInstanceName, ResultClass='SE_TargetMaskingGroup')
+        if len(portGroupInstanceNames) > 0:
+            LOG.debug("Found port group %(pg)s in masking view %(mv)s"
+                      % {'pg': portGroupInstanceNames[0],
+                         'mv': maskingViewInstanceName})
+            return portGroupInstanceNames[0]
+        else:
+            LOG.warn("No port group found in masking view %(mv)s"
+                     % {'mv': maskingViewInstanceName})