From 0de6b37930cc5b5f8dd842ac05b730df67121d8e Mon Sep 17 00:00:00 2001 From: Geraint North Date: Mon, 21 Jul 2014 22:23:48 +0100 Subject: [PATCH] Adds storwize_svc_npiv_compatibility_mode flag to Storwize/SVC driver This configuration option allows the driver to function in an environment where an attach operation occurs before the virtual FC ports are logged into the fabric. Today's behaviour (which is maintained as default behaviour) is to only build the initiator_target_map for initiator ports that are logged into the fabric, and error if there are no such ports. If this new flag is set to True, then if no initiator ports are found on the fabric, ALL initiator ports are placed into the initiator_target_map, rather than none, which is the case today. Closes-Bug: 1346622 Change-Id: Ie722612bc5a9af2816348392c0c39da003b99028 --- cinder/tests/test_storwize_svc.py | 86 +++++++++++++++++++ .../drivers/ibm/storwize_svc/__init__.py | 29 +++++-- etc/cinder/cinder.conf.sample | 6 ++ 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/cinder/tests/test_storwize_svc.py b/cinder/tests/test_storwize_svc.py index 6ac863ecd..074a23b80 100644 --- a/cinder/tests/test_storwize_svc.py +++ b/cinder/tests/test_storwize_svc.py @@ -1979,7 +1979,35 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.driver.initialize_connection, volume2, self._connector) + # with storwize_svc_npiv_compatibility_mode set to True, + # lsfabric can return [] and initilize_connection will still + # complete successfully + + with mock.patch.object(helpers.StorwizeHelpers, + 'get_conn_fc_wwpns') as conn_fc_wwpns: + conn_fc_wwpns.return_value = [] + self._set_flag('storwize_svc_npiv_compatibility_mode', + True) + expected_fc_npiv = { + 'driver_volume_type': 'fibre_channel', + 'data': {'target_lun': 1, + 'target_wwn': '500507680220C744', + 'target_discovered': False}} + ret = self.driver.initialize_connection(volume2, + self._connector) + self.assertEqual( + ret['driver_volume_type'], + expected_fc_npiv['driver_volume_type']) + for k, v in expected_fc_npiv['data'].iteritems(): + self.assertEqual(ret['data'][k], v) + self._set_flag('storwize_svc_npiv_compatibility_mode', + False) + self.driver.terminate_connection(volume1, self._connector) + # for npiv compatibility test case, we need to terminate connection + # to the 2nd volume + if protocol == 'FC' and self.USESIM: + self.driver.terminate_connection(volume2, self._connector) if self.USESIM: ret = self.driver._helpers.get_host_from_connector( self._connector) @@ -2565,6 +2593,64 @@ class StorwizeSVCDriverTestCase(test.TestCase): self.assertEqual(term_data, term_ret) + def test_storwize_initiator_target_map_npiv(self): + # Create two volumes to be used in mappings + ctxt = context.get_admin_context() + self._set_flag('storwize_svc_npiv_compatibility_mode', True) + + # Generate us a test volume + volume = self._generate_vol_info(None, None) + self.driver.create_volume(volume) + + # FIbre Channel volume type + vol_type = volume_types.create(ctxt, 'FC', {'protocol': 'FC'}) + + volume['volume_type_id'] = vol_type['id'] + + # Make sure that the volumes have been created + self._assert_vol_exists(volume['name'], True) + + wwpns = ['ff00000000000000', 'ff00000000000001'] + connector = {'host': 'storwize-svc-test', 'wwpns': wwpns} + + # Initialise the connection + with mock.patch.object(helpers.StorwizeHelpers, + 'get_conn_fc_wwpns') as conn_fc_wwpns: + conn_fc_wwpns.return_value = [] + init_ret = self.driver.initialize_connection(volume, connector) + + # Check that the initiator_target_map is as expected + init_data = {'driver_volume_type': 'fibre_channel', + 'data': {'initiator_target_map': + {'ff00000000000000': ['500507680220C744', + '500507680210C744', + '500507680220C745', + '500507680230C745'], + 'ff00000000000001': ['500507680220C744', + '500507680210C744', + '500507680220C745', + '500507680230C745']}, + 'target_discovered': False, + 'target_lun': 0, + 'target_wwn': '500507680220C744', + 'volume_id': volume['id'] + } + } + + self.assertEqual(init_data, init_ret) + + # Terminate connection + term_ret = self.driver.terminate_connection(volume, connector) + # Check that the initiator_target_map is as expected + term_data = {'driver_volume_type': 'fibre_channel', + 'data': {'initiator_target_map': + {'ff00000000000000': ['AABBCCDDEEFF0011'], + 'ff00000000000001': ['AABBCCDDEEFF0011']} + } + } + + self.assertEqual(term_data, term_ret) + def _get_vdisk_uid(self, vdisk_name): """Return vdisk_UID for given vdisk. diff --git a/cinder/volume/drivers/ibm/storwize_svc/__init__.py b/cinder/volume/drivers/ibm/storwize_svc/__init__.py index 70659626c..dcc5368ea 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/__init__.py +++ b/cinder/volume/drivers/ibm/storwize_svc/__init__.py @@ -101,6 +101,12 @@ storwize_svc_opts = [ cfg.BoolOpt('storwize_svc_multihostmap_enabled', default=True, help='Allows vdisk to multi host mapping'), + cfg.BoolOpt('storwize_svc_npiv_compatibility_mode', + default=False, + help='Indicate whether svc driver is compatible for NPIV ' + 'setup. If it is compatible, it will allow no wwpns ' + 'being returned on get_conn_fc_wwpns during ' + 'initialize_connection'), ] CONF = cfg.CONF @@ -410,12 +416,25 @@ class StorwizeSVCDriver(san.SanDriver): else: type_str = 'fibre_channel' conn_wwpns = self._helpers.get_conn_fc_wwpns(host_name) + + # If conn_wwpns is empty, then that means that there were + # no target ports with visibility to any of the initiators. + # We will either fail the attach, or return all target + # ports, depending on the value of the + # storwize_svc_npiv_compatibity_mode flag. if len(conn_wwpns) == 0: - msg = (_('Could not get FC connection information for the ' - 'host-volume connection. Is the host configured ' - 'properly for FC connections?')) - LOG.error(msg) - raise exception.VolumeBackendAPIException(data=msg) + npiv_compat = self.configuration.\ + storwize_svc_npiv_compatibility_mode + if not npiv_compat: + msg = (_('Could not get FC connection information for ' + 'the host-volume connection. Is the host ' + 'configured properly for FC connections?')) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + else: + for node in self._state['storage_nodes'].itervalues(): + conn_wwpns.extend(node['WWPN']) + if not vol_opts['multipath']: # preferred_node_entry can have a list of WWPNs while only # one WWPN may be available on the storage host. Here we diff --git a/etc/cinder/cinder.conf.sample b/etc/cinder/cinder.conf.sample index e6c7af015..ec24b09f8 100644 --- a/etc/cinder/cinder.conf.sample +++ b/etc/cinder/cinder.conf.sample @@ -1280,6 +1280,12 @@ # Allows vdisk to multi host mapping (boolean value) #storwize_svc_multihostmap_enabled=true +# Indicate whether svc driver is compatible for NPIV setup. If +# it is compatible, it will allow no wwpns being returned on +# get_conn_fc_wwpns during initialize_connection (boolean +# value) +#storwize_svc_npiv_compatibility_mode=false + # # Options defined in cinder.volume.drivers.ibm.xiv_ds8k -- 2.45.2