Merge "NetApp: Return all iSCSI targets-portals" into stable/rocky
This commit is contained in:
commit
6e5180441d
@ -685,8 +685,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
self.zapi_client.get_iscsi_target_details.return_value = (
|
||||
target_details_list)
|
||||
self.mock_object(block_base.NetAppBlockStorageLibrary,
|
||||
'_get_preferred_target_from_list',
|
||||
return_value=target_details_list[1])
|
||||
'_get_targets_from_list',
|
||||
return_value=target_details_list)
|
||||
self.zapi_client.get_iscsi_service_details.return_value = (
|
||||
fake.ISCSI_SERVICE_IQN)
|
||||
self.mock_object(na_utils,
|
||||
@ -722,7 +722,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
fake.ISCSI_VOLUME['name'], [fake.ISCSI_CONNECTOR['initiator']],
|
||||
'iscsi', None)
|
||||
self.zapi_client.get_iscsi_target_details.assert_called_once_with()
|
||||
block_base.NetAppBlockStorageLibrary._get_preferred_target_from_list\
|
||||
block_base.NetAppBlockStorageLibrary._get_targets_from_list\
|
||||
.assert_called_once_with(
|
||||
target_details_list)
|
||||
self.zapi_client.get_iscsi_service_details.assert_called_once_with()
|
||||
@ -734,7 +734,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
return_value=fake.ISCSI_LUN['lun_id'])
|
||||
self.zapi_client.get_iscsi_target_details.return_value = None
|
||||
self.mock_object(block_base.NetAppBlockStorageLibrary,
|
||||
'_get_preferred_target_from_list')
|
||||
'_get_targets_from_list')
|
||||
self.mock_object(na_utils,
|
||||
'get_iscsi_connection_properties',
|
||||
return_value=fake.ISCSI_CONNECTION_PROPERTIES)
|
||||
@ -745,7 +745,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
0, block_base.NetAppBlockStorageLibrary
|
||||
._get_preferred_target_from_list.call_count)
|
||||
._get_targets_from_list.call_count)
|
||||
self.assertEqual(
|
||||
0, self.zapi_client.get_iscsi_service_details.call_count)
|
||||
self.assertEqual(
|
||||
@ -758,7 +758,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
return_value=fake.ISCSI_LUN['lun_id'])
|
||||
self.zapi_client.get_iscsi_target_details.return_value = None
|
||||
self.mock_object(block_base.NetAppBlockStorageLibrary,
|
||||
'_get_preferred_target_from_list',
|
||||
'_get_targets_from_list',
|
||||
return_value=None)
|
||||
self.mock_object(na_utils, 'get_iscsi_connection_properties')
|
||||
|
||||
@ -780,8 +780,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
self.zapi_client.get_iscsi_target_details.return_value = (
|
||||
target_details_list)
|
||||
self.mock_object(block_base.NetAppBlockStorageLibrary,
|
||||
'_get_preferred_target_from_list',
|
||||
return_value=target_details_list[1])
|
||||
'_get_targets_from_list',
|
||||
return_value=target_details_list)
|
||||
self.zapi_client.get_iscsi_service_details.return_value = None
|
||||
self.mock_object(na_utils, 'get_iscsi_connection_properties')
|
||||
|
||||
@ -794,53 +794,49 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
|
||||
fake.ISCSI_VOLUME['name'], [fake.ISCSI_CONNECTOR['initiator']],
|
||||
'iscsi', None)
|
||||
self.zapi_client.get_iscsi_target_details.assert_called_once_with()
|
||||
block_base.NetAppBlockStorageLibrary._get_preferred_target_from_list\
|
||||
block_base.NetAppBlockStorageLibrary._get_targets_from_list\
|
||||
.assert_called_once_with(target_details_list)
|
||||
|
||||
def test_get_target_details_list(self):
|
||||
target_details_list = fake.ISCSI_TARGET_DETAILS_LIST
|
||||
|
||||
result = self.library._get_preferred_target_from_list(
|
||||
target_details_list)
|
||||
result = self.library._get_targets_from_list(target_details_list)
|
||||
|
||||
self.assertEqual(target_details_list[0], result)
|
||||
self.assertEqual(target_details_list, result)
|
||||
|
||||
def test_get_preferred_target_from_empty_list(self):
|
||||
target_details_list = []
|
||||
|
||||
result = self.library._get_preferred_target_from_list(
|
||||
target_details_list)
|
||||
result = self.library._get_targets_from_list(target_details_list)
|
||||
|
||||
self.assertIsNone(result)
|
||||
self.assertFalse(bool(result))
|
||||
|
||||
def test_get_preferred_target_from_list_with_one_interface_disabled(self):
|
||||
def test_get_targets_from_list_with_one_interface_disabled(self):
|
||||
target_details_list = copy.deepcopy(fake.ISCSI_TARGET_DETAILS_LIST)
|
||||
target_details_list[0]['interface-enabled'] = 'false'
|
||||
|
||||
result = self.library._get_preferred_target_from_list(
|
||||
target_details_list)
|
||||
result = self.library._get_targets_from_list(target_details_list)
|
||||
|
||||
self.assertEqual(target_details_list[1], result)
|
||||
self.assertEqual(target_details_list[1:], result)
|
||||
|
||||
def test_get_preferred_target_from_list_with_all_interfaces_disabled(self):
|
||||
def test_get_targets_from_list_with_all_interfaces_disabled(self):
|
||||
target_details_list = copy.deepcopy(fake.ISCSI_TARGET_DETAILS_LIST)
|
||||
for target in target_details_list:
|
||||
target['interface-enabled'] = 'false'
|
||||
|
||||
result = self.library._get_preferred_target_from_list(
|
||||
target_details_list)
|
||||
result = self.library._get_targets_from_list(target_details_list)
|
||||
|
||||
self.assertEqual(target_details_list[0], result)
|
||||
self.assertEqual(target_details_list, result)
|
||||
|
||||
def test_get_preferred_target_from_list_with_filter(self):
|
||||
def test_get_targets_from_list_with_filter(self):
|
||||
target_details_list = fake.ISCSI_TARGET_DETAILS_LIST
|
||||
filter = [target_detail['address']
|
||||
for target_detail in target_details_list[1:]]
|
||||
|
||||
result = self.library._get_preferred_target_from_list(
|
||||
target_details_list, filter)
|
||||
result = self.library._get_targets_from_list(target_details_list,
|
||||
filter)
|
||||
|
||||
self.assertEqual(target_details_list[1], result)
|
||||
self.assertEqual(target_details_list[1:], result)
|
||||
|
||||
@mock.patch.object(na_utils, 'check_flags', mock.Mock())
|
||||
@mock.patch.object(block_base, 'LOG', mock.Mock())
|
||||
|
@ -336,19 +336,6 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
fake.VOLUME_ID, fake.LUN_ID, fake.LUN_SIZE, fake.LUN_METADATA,
|
||||
None)
|
||||
|
||||
def test_get_preferred_target_from_list(self):
|
||||
target_details_list = fake.ISCSI_TARGET_DETAILS_LIST
|
||||
operational_addresses = [
|
||||
target['address']
|
||||
for target in target_details_list[2:]]
|
||||
self.zapi_client.get_operational_lif_addresses = (
|
||||
mock.Mock(return_value=operational_addresses))
|
||||
|
||||
result = self.library._get_preferred_target_from_list(
|
||||
target_details_list)
|
||||
|
||||
self.assertEqual(target_details_list[2], result)
|
||||
|
||||
@ddt.data({'replication_backends': [], 'cluster_credentials': False},
|
||||
{'replication_backends': ['target_1', 'target_2'],
|
||||
'cluster_credentials': True})
|
||||
|
@ -258,17 +258,17 @@ class NetAppESeriesDriverTestCase(object):
|
||||
vol_nomatch = {'id': 'vol_id', 'currentManager': 'ctrl3'}
|
||||
portals = [{'controller': 'ctrl2', 'iqn': 'iqn2'},
|
||||
{'controller': 'ctrl1', 'iqn': 'iqn1'}]
|
||||
portal = self.library._get_iscsi_portal_for_vol(volume, portals)
|
||||
self.assertEqual({'controller': 'ctrl1', 'iqn': 'iqn1'}, portal)
|
||||
portal = self.library._get_iscsi_portal_for_vol(vol_nomatch, portals)
|
||||
self.assertEqual({'controller': 'ctrl2', 'iqn': 'iqn2'}, portal)
|
||||
portal = self.library._get_iscsi_portals_for_vol(volume, portals)
|
||||
self.assertEqual({'controller': 'ctrl1', 'iqn': 'iqn1'}, portal[0])
|
||||
portal = self.library._get_iscsi_portals_for_vol(vol_nomatch, portals)
|
||||
self.assertEqual({'controller': 'ctrl2', 'iqn': 'iqn2'}, portal[0])
|
||||
|
||||
def test_portal_for_vol_any_false(self):
|
||||
vol_nomatch = {'id': 'vol_id', 'currentManager': 'ctrl3'}
|
||||
portals = [{'controller': 'ctrl2', 'iqn': 'iqn2'},
|
||||
{'controller': 'ctrl1', 'iqn': 'iqn1'}]
|
||||
self.assertRaises(exception.NetAppDriverException,
|
||||
self.library._get_iscsi_portal_for_vol,
|
||||
self.library._get_iscsi_portals_for_vol,
|
||||
vol_nomatch, portals, False)
|
||||
|
||||
def test_do_setup_all_default(self):
|
||||
|
@ -23,8 +23,10 @@ import cinder.volume.drivers.netapp.options as na_opts
|
||||
ISCSI_FAKE_LUN_ID = 1
|
||||
|
||||
ISCSI_FAKE_IQN = 'iqn.1993-08.org.debian:01:10'
|
||||
ISCSI_FAKE_IQN2 = 'iqn.1993-08.org.debian:01:11'
|
||||
|
||||
ISCSI_FAKE_ADDRESS_IPV4 = '10.63.165.216'
|
||||
ISCSI_FAKE_ADDRESS2_IPV4 = '10.63.165.217'
|
||||
ISCSI_FAKE_ADDRESS_IPV6 = 'fe80::72a4:a152:aad9:30d9'
|
||||
|
||||
ISCSI_FAKE_PORT = '2232'
|
||||
@ -38,6 +40,18 @@ ISCSI_FAKE_TARGET['port'] = ISCSI_FAKE_PORT
|
||||
ISCSI_FAKE_VOLUME = {'id': 'fake_id', 'provider_auth': 'None stack password'}
|
||||
ISCSI_FAKE_VOLUME_NO_AUTH = {'id': 'fake_id', 'provider_auth': ''}
|
||||
|
||||
ISCSI_MP_TARGET_INFO_DICT = {'target_discovered': False,
|
||||
'target_portal': '10.63.165.216:2232',
|
||||
'target_portals': ['10.63.165.216:2232',
|
||||
'10.63.165.217:2232'],
|
||||
'target_iqn': ISCSI_FAKE_IQN,
|
||||
'target_iqns': [ISCSI_FAKE_IQN, ISCSI_FAKE_IQN2],
|
||||
'target_lun': ISCSI_FAKE_LUN_ID,
|
||||
'target_luns': [ISCSI_FAKE_LUN_ID] * 2,
|
||||
'volume_id': ISCSI_FAKE_VOLUME['id'],
|
||||
'auth_method': 'None', 'auth_username': 'stack',
|
||||
'auth_password': 'password'}
|
||||
|
||||
FC_ISCSI_TARGET_INFO_DICT = {'target_discovered': False,
|
||||
'target_portal': '10.63.165.216:2232',
|
||||
'target_iqn': ISCSI_FAKE_IQN,
|
||||
|
@ -119,40 +119,56 @@ class NetAppDriverUtilsTestCase(test.TestCase):
|
||||
self.assertAlmostEqual(na_utils.round_down(-5.567, '0'), -5)
|
||||
|
||||
def test_iscsi_connection_properties(self):
|
||||
|
||||
actual_properties = na_utils.get_iscsi_connection_properties(
|
||||
fake.ISCSI_FAKE_LUN_ID, fake.ISCSI_FAKE_VOLUME,
|
||||
fake.ISCSI_FAKE_IQN, fake.ISCSI_FAKE_ADDRESS_IPV4,
|
||||
fake.ISCSI_FAKE_PORT)
|
||||
[fake.ISCSI_FAKE_IQN, fake.ISCSI_FAKE_IQN2],
|
||||
[fake.ISCSI_FAKE_ADDRESS_IPV4, fake.ISCSI_FAKE_ADDRESS2_IPV4],
|
||||
[fake.ISCSI_FAKE_PORT, fake.ISCSI_FAKE_PORT])
|
||||
|
||||
actual_properties_mapped = actual_properties['data']
|
||||
|
||||
self.assertDictEqual(actual_properties_mapped,
|
||||
fake.FC_ISCSI_TARGET_INFO_DICT)
|
||||
fake.ISCSI_MP_TARGET_INFO_DICT)
|
||||
|
||||
def test_iscsi_connection_properties_single_iqn(self):
|
||||
actual_properties = na_utils.get_iscsi_connection_properties(
|
||||
fake.ISCSI_FAKE_LUN_ID, fake.ISCSI_FAKE_VOLUME,
|
||||
fake.ISCSI_FAKE_IQN,
|
||||
[fake.ISCSI_FAKE_ADDRESS_IPV4, fake.ISCSI_FAKE_ADDRESS2_IPV4],
|
||||
[fake.ISCSI_FAKE_PORT, fake.ISCSI_FAKE_PORT])
|
||||
|
||||
actual_properties_mapped = actual_properties['data']
|
||||
expected = fake.ISCSI_MP_TARGET_INFO_DICT.copy()
|
||||
expected['target_iqns'][1] = expected['target_iqns'][0]
|
||||
|
||||
self.assertDictEqual(actual_properties_mapped,
|
||||
fake.ISCSI_MP_TARGET_INFO_DICT)
|
||||
|
||||
def test_iscsi_connection_lun_id_type_str(self):
|
||||
FAKE_LUN_ID = '1'
|
||||
|
||||
actual_properties = na_utils.get_iscsi_connection_properties(
|
||||
FAKE_LUN_ID, fake.ISCSI_FAKE_VOLUME, fake.ISCSI_FAKE_IQN,
|
||||
fake.ISCSI_FAKE_ADDRESS_IPV4, fake.ISCSI_FAKE_PORT)
|
||||
[fake.ISCSI_FAKE_ADDRESS_IPV4], [fake.ISCSI_FAKE_PORT])
|
||||
|
||||
actual_properties_mapped = actual_properties['data']
|
||||
|
||||
self.assertIs(int, type(actual_properties_mapped['target_lun']))
|
||||
self.assertDictEqual(actual_properties_mapped,
|
||||
fake.FC_ISCSI_TARGET_INFO_DICT)
|
||||
|
||||
def test_iscsi_connection_lun_id_type_dict(self):
|
||||
FAKE_LUN_ID = {'id': 'fake_id'}
|
||||
|
||||
self.assertRaises(TypeError, na_utils.get_iscsi_connection_properties,
|
||||
FAKE_LUN_ID, fake.ISCSI_FAKE_VOLUME,
|
||||
fake.ISCSI_FAKE_IQN, fake.ISCSI_FAKE_ADDRESS_IPV4,
|
||||
fake.ISCSI_FAKE_PORT)
|
||||
fake.ISCSI_FAKE_IQN, [fake.ISCSI_FAKE_ADDRESS_IPV4],
|
||||
[fake.ISCSI_FAKE_PORT])
|
||||
|
||||
def test_iscsi_connection_properties_ipv6(self):
|
||||
actual_properties = na_utils.get_iscsi_connection_properties(
|
||||
'1', fake.ISCSI_FAKE_VOLUME_NO_AUTH, fake.ISCSI_FAKE_IQN,
|
||||
fake.ISCSI_FAKE_ADDRESS_IPV6, fake.ISCSI_FAKE_PORT)
|
||||
[fake.ISCSI_FAKE_ADDRESS_IPV6], [fake.ISCSI_FAKE_PORT])
|
||||
|
||||
self.assertDictEqual(actual_properties['data'],
|
||||
fake.FC_ISCSI_TARGET_INFO_DICT_IPV6)
|
||||
|
@ -839,13 +839,12 @@ class NetAppBlockStorageLibrary(object):
|
||||
"initiator %(initiator_name)s",
|
||||
{'name': name, 'initiator_name': initiator_name})
|
||||
|
||||
preferred_target = self._get_preferred_target_from_list(
|
||||
target_list)
|
||||
if preferred_target is None:
|
||||
targets = self._get_targets_from_list(target_list)
|
||||
if not targets:
|
||||
msg = _('Failed to get target portal for the LUN %s')
|
||||
raise exception.VolumeBackendAPIException(data=msg % name)
|
||||
(address, port) = (preferred_target['address'],
|
||||
preferred_target['port'])
|
||||
addresses = [target['address'] for target in targets]
|
||||
ports = [target['port'] for target in targets]
|
||||
|
||||
iqn = self.zapi_client.get_iscsi_service_details()
|
||||
if not iqn:
|
||||
@ -853,8 +852,8 @@ class NetAppBlockStorageLibrary(object):
|
||||
raise exception.VolumeBackendAPIException(data=msg % name)
|
||||
|
||||
properties = na_utils.get_iscsi_connection_properties(lun_id, volume,
|
||||
iqn, address,
|
||||
port)
|
||||
iqn, addresses,
|
||||
ports)
|
||||
|
||||
if self.configuration.use_chap_auth:
|
||||
chap_username, chap_password = self._configure_chap(initiator_name)
|
||||
@ -881,18 +880,13 @@ class NetAppBlockStorageLibrary(object):
|
||||
properties['data']['discovery_auth_username'] = username
|
||||
properties['data']['discovery_auth_password'] = password
|
||||
|
||||
def _get_preferred_target_from_list(self, target_details_list,
|
||||
filter=None):
|
||||
preferred_target = None
|
||||
for target in target_details_list:
|
||||
if filter and target['address'] not in filter:
|
||||
continue
|
||||
if target.get('interface-enabled', 'true') == 'true':
|
||||
preferred_target = target
|
||||
break
|
||||
if preferred_target is None and len(target_details_list) > 0:
|
||||
preferred_target = target_details_list[0]
|
||||
return preferred_target
|
||||
def _get_targets_from_list(self, target_details_list, filter=None):
|
||||
targets = [target for target in target_details_list
|
||||
if (not filter or target['address'] in filter) and
|
||||
target.get('interface-enabled', 'true') == 'true']
|
||||
if not targets and len(target_details_list) > 0:
|
||||
targets = target_details_list
|
||||
return targets
|
||||
|
||||
def terminate_connection_iscsi(self, volume, connector, **kwargs):
|
||||
"""Driver entry point to unattach a volume from an instance.
|
||||
|
@ -390,29 +390,6 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
|
||||
msg = 'Deleted LUN with name %(name)s and QoS info %(qos)s'
|
||||
LOG.debug(msg, {'name': volume['name'], 'qos': qos_policy_group_info})
|
||||
|
||||
def _get_preferred_target_from_list(self, target_details_list,
|
||||
filter=None):
|
||||
# cDOT iSCSI LIFs do not migrate from controller to controller
|
||||
# in failover. Rather, an iSCSI LIF must be configured on each
|
||||
# controller and the initiator has to take responsibility for
|
||||
# using a LIF that is UP. In failover, the iSCSI LIF on the
|
||||
# downed controller goes DOWN until the controller comes back up.
|
||||
#
|
||||
# Currently Nova only accepts a single target when obtaining
|
||||
# target details from Cinder, so we pass back the first portal
|
||||
# with an UP iSCSI LIF. There are plans to have Nova accept
|
||||
# and try multiple targets. When that happens, we can and should
|
||||
# remove this filter and return all targets since their operational
|
||||
# state could change between the time we test here and the time
|
||||
# Nova uses the target.
|
||||
|
||||
operational_addresses = (
|
||||
self.zapi_client.get_operational_lif_addresses())
|
||||
|
||||
return (super(NetAppBlockStorageCmodeLibrary, self)
|
||||
._get_preferred_target_from_list(target_details_list,
|
||||
filter=operational_addresses))
|
||||
|
||||
def _setup_qos_for_volume(self, volume, extra_specs):
|
||||
try:
|
||||
qos_policy_group_info = na_utils.get_valid_qos_policy_group_info(
|
||||
|
@ -1292,19 +1292,19 @@ class NetAppESeriesLibrary(object):
|
||||
msg_fmt)
|
||||
|
||||
iscsi_details = self._get_iscsi_service_details()
|
||||
iscsi_portal = self._get_iscsi_portal_for_vol(eseries_vol,
|
||||
iscsi_details)
|
||||
iscsi_portals = self._get_iscsi_portals_for_vol(eseries_vol,
|
||||
iscsi_details)
|
||||
LOG.debug("Successfully fetched target details for volume %(id)s and "
|
||||
"initiator %(initiator_name)s.", msg_fmt)
|
||||
iqn = iscsi_portal['iqn']
|
||||
address = iscsi_portal['ip']
|
||||
port = iscsi_portal['tcp_port']
|
||||
iqns = [portal['iqn'] for portal in iscsi_portals]
|
||||
addresses = [portal['ip'] for portal in iscsi_portals]
|
||||
ports = [portal['tcp_port'] for portal in iscsi_portals]
|
||||
properties = na_utils.get_iscsi_connection_properties(lun_id, volume,
|
||||
iqn, address,
|
||||
port)
|
||||
iqns, addresses,
|
||||
ports)
|
||||
if self.configuration.use_chap_auth:
|
||||
if self._client.features.CHAP_AUTHENTICATION:
|
||||
chap_username, chap_password = self._configure_chap(iqn)
|
||||
chap_username, chap_password = self._configure_chap(iqns[0])
|
||||
properties['data']['auth_username'] = chap_username
|
||||
properties['data']['auth_password'] = chap_password
|
||||
properties['data']['auth_method'] = 'CHAP'
|
||||
@ -1359,13 +1359,15 @@ class NetAppESeriesLibrary(object):
|
||||
msg % self._client.get_system_id())
|
||||
return ports
|
||||
|
||||
def _get_iscsi_portal_for_vol(self, volume, portals, anyController=True):
|
||||
def _get_iscsi_portals_for_vol(self, volume, portals, anyController=True):
|
||||
"""Get the iscsi portal info relevant to volume."""
|
||||
for portal in portals:
|
||||
if portal.get('controller') == volume.get('currentManager'):
|
||||
return portal
|
||||
manager = volume.get('currentManager')
|
||||
current_manager_portals = [portal for portal in portals
|
||||
if portal.get('controller') == manager]
|
||||
if current_manager_portals:
|
||||
return current_manager_portals
|
||||
if anyController and portals:
|
||||
return portals[0]
|
||||
return portals
|
||||
msg = _('No good iscsi portal found in supplied list for %s.')
|
||||
raise exception.NetAppDriverException(
|
||||
msg % self._client.get_system_id())
|
||||
|
@ -173,18 +173,29 @@ def log_extra_spec_warnings(extra_specs):
|
||||
'new': DEPRECATED_SSC_SPECS[spec]})
|
||||
|
||||
|
||||
def get_iscsi_connection_properties(lun_id, volume, iqn,
|
||||
address, port):
|
||||
def get_iscsi_connection_properties(lun_id, volume, iqns,
|
||||
addresses, ports):
|
||||
# literal ipv6 address
|
||||
if netutils.is_valid_ipv6(address):
|
||||
address = netutils.escape_ipv6(address)
|
||||
addresses = [netutils.escape_ipv6(a) if netutils.is_valid_ipv6(a) else a
|
||||
for a in addresses]
|
||||
|
||||
lun_id = int(lun_id)
|
||||
if isinstance(iqns, six.string_types):
|
||||
iqns = [iqns] * len(addresses)
|
||||
|
||||
target_portals = ['%s:%s' % (a, p) for a, p in zip(addresses, ports)]
|
||||
|
||||
properties = {}
|
||||
properties['target_discovered'] = False
|
||||
properties['target_portal'] = '%s:%s' % (address, port)
|
||||
properties['target_iqn'] = iqn
|
||||
properties['target_lun'] = int(lun_id)
|
||||
properties['target_portal'] = target_portals[0]
|
||||
properties['target_iqn'] = iqns[0]
|
||||
properties['target_lun'] = lun_id
|
||||
properties['volume_id'] = volume['id']
|
||||
if len(addresses) > 1:
|
||||
properties['target_portals'] = target_portals
|
||||
properties['target_iqns'] = iqns
|
||||
properties['target_luns'] = [lun_id] * len(addresses)
|
||||
|
||||
auth = volume['provider_auth']
|
||||
if auth:
|
||||
(auth_method, auth_username, auth_secret) = auth.split()
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
NetApp iSCSI drivers no longer use the discovery mechanism for multipathing
|
||||
and they always return all target/portals when attaching a volume. Thanks
|
||||
to this, volumes will be successfully attached even if the target/portal
|
||||
selected as primary is down, this will be the case for both, multipath and
|
||||
single path connections.
|
Loading…
Reference in New Issue
Block a user