[PURE] support IPv6 / add parameter pure_iscsi_cidr_list
Pure storage: Add support for IPv6 in pure_iscsi_cidr parameter. Pure storage: Add parameter pure_iscsi_cidr_list to support a list of networks. Change-Id: Ib04e49dac9fdabd81809ca389553ce3638bb9bbf Closes-Bug: 1910143
This commit is contained in:
parent
ccb6025cd1
commit
7aa5e95d48
@ -76,13 +76,20 @@ VOLUME_BACKEND_NAME = "Pure_iSCSI"
|
|||||||
ISCSI_PORT_NAMES = ["ct0.eth2", "ct0.eth3", "ct1.eth2", "ct1.eth3"]
|
ISCSI_PORT_NAMES = ["ct0.eth2", "ct0.eth3", "ct1.eth2", "ct1.eth3"]
|
||||||
FC_PORT_NAMES = ["ct0.fc2", "ct0.fc3", "ct1.fc2", "ct1.fc3"]
|
FC_PORT_NAMES = ["ct0.fc2", "ct0.fc3", "ct1.fc2", "ct1.fc3"]
|
||||||
# These two IP blocks should use the same prefix (see ISCSI_CIDR_FILTERED to
|
# These two IP blocks should use the same prefix (see ISCSI_CIDR_FILTERED to
|
||||||
# make sure changes make sense)
|
# make sure changes make sense). Our arrays now have 4 IPv4 + 4 IPv6 ports.
|
||||||
ISCSI_IPS = ["10.0.0." + str(i + 1) for i in range(len(ISCSI_PORT_NAMES))]
|
ISCSI_IPS = ["10.0.0." + str(i + 1) for i in range(len(ISCSI_PORT_NAMES))]
|
||||||
|
ISCSI_IPS += ["[2001:db8::" + str(i + 1) + "]"
|
||||||
|
for i in range(len(ISCSI_PORT_NAMES))]
|
||||||
AC_ISCSI_IPS = ["10.0.0." + str(i + 1 + len(ISCSI_PORT_NAMES))
|
AC_ISCSI_IPS = ["10.0.0." + str(i + 1 + len(ISCSI_PORT_NAMES))
|
||||||
for i in range(len(ISCSI_PORT_NAMES))]
|
for i in range(len(ISCSI_PORT_NAMES))]
|
||||||
|
AC_ISCSI_IPS += ["[2001:db8::1:" + str(i + 1) + "]"
|
||||||
|
for i in range(len(ISCSI_PORT_NAMES))]
|
||||||
ISCSI_CIDR = "0.0.0.0/0"
|
ISCSI_CIDR = "0.0.0.0/0"
|
||||||
|
ISCSI_CIDR_V6 = "::/0"
|
||||||
# Designed to filter out only one of the AC ISCSI IPs, leaving the rest in
|
# Designed to filter out only one of the AC ISCSI IPs, leaving the rest in
|
||||||
ISCSI_CIDR_FILTERED = '10.0.0.0/29'
|
ISCSI_CIDR_FILTERED = '10.0.0.0/29'
|
||||||
|
# Include several IP / networks: 10.0.0.2, 10.0.0.3, 10.0.0.6, 10.0.0.7
|
||||||
|
ISCSI_CIDRS_FILTERED = ['10.0.0.2', '10.0.0.3', '2001:db8::1:2/127']
|
||||||
FC_WWNS = ["21000024ff59fe9" + str(i + 1) for i in range(len(FC_PORT_NAMES))]
|
FC_WWNS = ["21000024ff59fe9" + str(i + 1) for i in range(len(FC_PORT_NAMES))]
|
||||||
AC_FC_WWNS = [
|
AC_FC_WWNS = [
|
||||||
"21000024ff59fab" + str(i + 1) for i in range(len(FC_PORT_NAMES))]
|
"21000024ff59fab" + str(i + 1) for i in range(len(FC_PORT_NAMES))]
|
||||||
@ -126,16 +133,17 @@ AC_DEVICE_MAPPING = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# We now have IPv6 in addition to IPv4 on each interface
|
||||||
ISCSI_PORTS = [{"name": name,
|
ISCSI_PORTS = [{"name": name,
|
||||||
"iqn": TARGET_IQN,
|
"iqn": TARGET_IQN,
|
||||||
"portal": ip + ":" + TARGET_PORT,
|
"portal": ip + ":" + TARGET_PORT,
|
||||||
"wwn": None,
|
"wwn": None,
|
||||||
} for name, ip in zip(ISCSI_PORT_NAMES, ISCSI_IPS)]
|
} for name, ip in zip(ISCSI_PORT_NAMES * 2, ISCSI_IPS)]
|
||||||
AC_ISCSI_PORTS = [{"name": name,
|
AC_ISCSI_PORTS = [{"name": name,
|
||||||
"iqn": AC_TARGET_IQN,
|
"iqn": AC_TARGET_IQN,
|
||||||
"portal": ip + ":" + TARGET_PORT,
|
"portal": ip + ":" + TARGET_PORT,
|
||||||
"wwn": None,
|
"wwn": None,
|
||||||
} for name, ip in zip(ISCSI_PORT_NAMES, AC_ISCSI_IPS)]
|
} for name, ip in zip(ISCSI_PORT_NAMES * 2, AC_ISCSI_IPS)]
|
||||||
FC_PORTS = [{"name": name,
|
FC_PORTS = [{"name": name,
|
||||||
"iqn": None,
|
"iqn": None,
|
||||||
"portal": None,
|
"portal": None,
|
||||||
@ -193,6 +201,20 @@ ISCSI_CONNECTION_INFO = {
|
|||||||
"wwn": "3624a93709714b5cb91634c470002b2c8",
|
"wwn": "3624a93709714b5cb91634c470002b2c8",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
ISCSI_CONNECTION_INFO_V6 = {
|
||||||
|
"driver_volume_type": "iscsi",
|
||||||
|
"data": {
|
||||||
|
"target_discovered": False,
|
||||||
|
"discard": True,
|
||||||
|
"target_luns": [1, 1, 1, 1],
|
||||||
|
"target_iqns": [TARGET_IQN, TARGET_IQN, TARGET_IQN, TARGET_IQN],
|
||||||
|
"target_portals": [ISCSI_IPS[4] + ":" + TARGET_PORT,
|
||||||
|
ISCSI_IPS[5] + ":" + TARGET_PORT,
|
||||||
|
ISCSI_IPS[6] + ":" + TARGET_PORT,
|
||||||
|
ISCSI_IPS[7] + ":" + TARGET_PORT],
|
||||||
|
"wwn": "3624a93709714b5cb91634c470002b2c8",
|
||||||
|
},
|
||||||
|
}
|
||||||
ISCSI_CONNECTION_INFO_AC = {
|
ISCSI_CONNECTION_INFO_AC = {
|
||||||
"driver_volume_type": "iscsi",
|
"driver_volume_type": "iscsi",
|
||||||
"data": {
|
"data": {
|
||||||
@ -236,6 +258,23 @@ ISCSI_CONNECTION_INFO_AC_FILTERED = {
|
|||||||
"wwn": "3624a93709714b5cb91634c470002b2c8",
|
"wwn": "3624a93709714b5cb91634c470002b2c8",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
ISCSI_CONNECTION_INFO_AC_FILTERED_LIST = {
|
||||||
|
"driver_volume_type": "iscsi",
|
||||||
|
"data": {
|
||||||
|
"target_discovered": False,
|
||||||
|
"discard": True,
|
||||||
|
"target_luns": [1, 1, 5, 5],
|
||||||
|
# Final entry filtered by ISCSI_CIDR_FILTERED
|
||||||
|
"target_iqns": [TARGET_IQN, TARGET_IQN,
|
||||||
|
AC_TARGET_IQN, AC_TARGET_IQN],
|
||||||
|
# Final entry filtered by ISCSI_CIDR_FILTERED
|
||||||
|
"target_portals": [ISCSI_IPS[1] + ":" + TARGET_PORT,
|
||||||
|
ISCSI_IPS[2] + ":" + TARGET_PORT,
|
||||||
|
AC_ISCSI_IPS[5] + ":" + TARGET_PORT, # IPv6
|
||||||
|
AC_ISCSI_IPS[6] + ":" + TARGET_PORT], # IPv6
|
||||||
|
"wwn": "3624a93709714b5cb91634c470002b2c8",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
FC_CONNECTION_INFO = {
|
FC_CONNECTION_INFO = {
|
||||||
"driver_volume_type": "fibre_channel",
|
"driver_volume_type": "fibre_channel",
|
||||||
@ -519,6 +558,7 @@ class PureDriverTestCase(test.TestCase):
|
|||||||
self.mock_config.driver_ssl_cert_verify = False
|
self.mock_config.driver_ssl_cert_verify = False
|
||||||
self.mock_config.driver_ssl_cert_path = None
|
self.mock_config.driver_ssl_cert_path = None
|
||||||
self.mock_config.pure_iscsi_cidr = ISCSI_CIDR
|
self.mock_config.pure_iscsi_cidr = ISCSI_CIDR
|
||||||
|
self.mock_config.pure_iscsi_cidr_list = None
|
||||||
self.array = mock.Mock()
|
self.array = mock.Mock()
|
||||||
self.array.get.return_value = GET_ARRAY_PRIMARY
|
self.array.get.return_value = GET_ARRAY_PRIMARY
|
||||||
self.array.array_name = GET_ARRAY_PRIMARY["array_name"]
|
self.array.array_name = GET_ARRAY_PRIMARY["array_name"]
|
||||||
@ -3146,6 +3186,34 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
self.driver.initialize_connection,
|
self.driver.initialize_connection,
|
||||||
vol, ISCSI_CONNECTOR)
|
vol, ISCSI_CONNECTOR)
|
||||||
|
|
||||||
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_wwn")
|
||||||
|
@mock.patch(ISCSI_DRIVER_OBJ + "._connect")
|
||||||
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_target_iscsi_ports")
|
||||||
|
def test_initialize_connection_ipv6(self, mock_get_iscsi_ports,
|
||||||
|
mock_connection, mock_get_wwn):
|
||||||
|
vol, vol_name = self.new_fake_vol()
|
||||||
|
mock_get_iscsi_ports.return_value = ISCSI_PORTS
|
||||||
|
mock_get_wwn.return_value = '3624a93709714b5cb91634c470002b2c8'
|
||||||
|
lun = 1
|
||||||
|
connection = {
|
||||||
|
"vol": vol_name,
|
||||||
|
"lun": lun,
|
||||||
|
}
|
||||||
|
mock_connection.return_value = connection
|
||||||
|
|
||||||
|
self.mock_config.pure_iscsi_cidr = ISCSI_CIDR_V6
|
||||||
|
result = deepcopy(ISCSI_CONNECTION_INFO_V6)
|
||||||
|
|
||||||
|
real_result = self.driver.initialize_connection(vol,
|
||||||
|
ISCSI_CONNECTOR)
|
||||||
|
self.assertDictEqual(result, real_result)
|
||||||
|
mock_get_iscsi_ports.assert_called_with(self.array)
|
||||||
|
mock_connection.assert_called_with(self.array, vol_name,
|
||||||
|
ISCSI_CONNECTOR, None, None)
|
||||||
|
self.assert_error_propagates([mock_get_iscsi_ports, mock_connection],
|
||||||
|
self.driver.initialize_connection,
|
||||||
|
vol, ISCSI_CONNECTOR)
|
||||||
|
|
||||||
@mock.patch(ISCSI_DRIVER_OBJ + "._get_wwn")
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_wwn")
|
||||||
@mock.patch(ISCSI_DRIVER_OBJ + "._connect")
|
@mock.patch(ISCSI_DRIVER_OBJ + "._connect")
|
||||||
@mock.patch(ISCSI_DRIVER_OBJ + "._get_target_iscsi_ports")
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_target_iscsi_ports")
|
||||||
@ -3232,6 +3300,53 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
mock.call(mock_secondary, vol_name, ISCSI_CONNECTOR, None, None),
|
mock.call(mock_secondary, vol_name, ISCSI_CONNECTOR, None, None),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_wwn")
|
||||||
|
@mock.patch(ISCSI_DRIVER_OBJ + "._connect")
|
||||||
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_target_iscsi_ports")
|
||||||
|
def test_initialize_connection_uniform_ac_cidrs(self,
|
||||||
|
mock_get_iscsi_ports,
|
||||||
|
mock_connection,
|
||||||
|
mock_get_wwn):
|
||||||
|
repl_extra_specs = {
|
||||||
|
'replication_type': '<in> sync',
|
||||||
|
'replication_enabled': '<is> true',
|
||||||
|
}
|
||||||
|
vol, vol_name = self.new_fake_vol(type_extra_specs=repl_extra_specs)
|
||||||
|
mock_get_iscsi_ports.side_effect = [ISCSI_PORTS, AC_ISCSI_PORTS]
|
||||||
|
mock_get_wwn.return_value = '3624a93709714b5cb91634c470002b2c8'
|
||||||
|
mock_connection.side_effect = [
|
||||||
|
{
|
||||||
|
"vol": vol_name,
|
||||||
|
"lun": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"vol": vol_name,
|
||||||
|
"lun": 5,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
result = deepcopy(ISCSI_CONNECTION_INFO_AC_FILTERED_LIST)
|
||||||
|
|
||||||
|
self.driver._is_active_cluster_enabled = True
|
||||||
|
# Set up some CIDRs to block: this will allow only 2 addresses from
|
||||||
|
# each host of the ActiveCluster, so we should check that we only
|
||||||
|
# get two+two results back
|
||||||
|
self.driver.configuration.pure_iscsi = ISCSI_CIDR
|
||||||
|
self.driver.configuration.pure_iscsi_cidr_list = ISCSI_CIDRS_FILTERED
|
||||||
|
mock_secondary = mock.MagicMock()
|
||||||
|
self.driver._uniform_active_cluster_target_arrays = [mock_secondary]
|
||||||
|
|
||||||
|
real_result = self.driver.initialize_connection(vol,
|
||||||
|
ISCSI_CONNECTOR)
|
||||||
|
self.assertDictEqual(result, real_result)
|
||||||
|
mock_get_iscsi_ports.assert_has_calls([
|
||||||
|
mock.call(self.array),
|
||||||
|
mock.call(mock_secondary),
|
||||||
|
])
|
||||||
|
mock_connection.assert_has_calls([
|
||||||
|
mock.call(self.array, vol_name, ISCSI_CONNECTOR, None, None),
|
||||||
|
mock.call(mock_secondary, vol_name, ISCSI_CONNECTOR, None, None),
|
||||||
|
])
|
||||||
|
|
||||||
@mock.patch(ISCSI_DRIVER_OBJ + "._get_wwn")
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_wwn")
|
||||||
@mock.patch(ISCSI_DRIVER_OBJ + "._get_chap_credentials")
|
@mock.patch(ISCSI_DRIVER_OBJ + "._get_chap_credentials")
|
||||||
@mock.patch(ISCSI_DRIVER_OBJ + "._connect")
|
@mock.patch(ISCSI_DRIVER_OBJ + "._connect")
|
||||||
|
@ -85,7 +85,13 @@ PURE_OPTS = [
|
|||||||
cfg.StrOpt("pure_iscsi_cidr", default="0.0.0.0/0",
|
cfg.StrOpt("pure_iscsi_cidr", default="0.0.0.0/0",
|
||||||
help="CIDR of FlashArray iSCSI targets hosts are allowed to "
|
help="CIDR of FlashArray iSCSI targets hosts are allowed to "
|
||||||
"connect to. Default will allow connection to any "
|
"connect to. Default will allow connection to any "
|
||||||
"IP address."),
|
"IPv4 address. This parameter now supports IPv6 subnets. "
|
||||||
|
"Ignored when pure_iscsi_cidr_list is set."),
|
||||||
|
cfg.ListOpt("pure_iscsi_cidr_list", default=None,
|
||||||
|
help="Comma-separated list of CIDR of FlashArray iSCSI "
|
||||||
|
"targets hosts are allowed to connect to. It supports "
|
||||||
|
"IPv4 and IPv6 subnets. This parameter supersedes "
|
||||||
|
"pure_iscsi_cidr."),
|
||||||
cfg.BoolOpt("pure_eradicate_on_delete",
|
cfg.BoolOpt("pure_eradicate_on_delete",
|
||||||
default=False,
|
default=False,
|
||||||
help="When enabled, all Pure volumes, snapshots, and "
|
help="When enabled, all Pure volumes, snapshots, and "
|
||||||
@ -2418,12 +2424,15 @@ class PureISCSIDriver(PureBaseVolumeDriver, san.SanISCSIDriver):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Convert CIDR to the expected type
|
if self.configuration.pure_iscsi_cidr_list:
|
||||||
if not isinstance(self.configuration.pure_iscsi_cidr, str):
|
cidrs = self.configuration.pure_iscsi_cidr_list
|
||||||
cidr = self.configuration.pure_iscsi_cidr.decode('utf8')
|
if self.configuration.pure_iscsi_cidr != "0.0.0.0/0":
|
||||||
|
LOG.warning("pure_iscsi_cidr was ignored as "
|
||||||
|
"pure_iscsi_cidr_list is set")
|
||||||
else:
|
else:
|
||||||
cidr = self.configuration.pure_iscsi_cidr
|
cidrs = [self.configuration.pure_iscsi_cidr]
|
||||||
check_cidr = ipaddress.IPv4Network(cidr)
|
|
||||||
|
check_cidrs = [ipaddress.ip_network(item) for item in cidrs]
|
||||||
|
|
||||||
target_luns = []
|
target_luns = []
|
||||||
target_iqns = []
|
target_iqns = []
|
||||||
@ -2438,15 +2447,14 @@ class PureISCSIDriver(PureBaseVolumeDriver, san.SanISCSIDriver):
|
|||||||
# Check to ensure that the portal IP is in the iSCSI target
|
# Check to ensure that the portal IP is in the iSCSI target
|
||||||
# CIDR before adding it
|
# CIDR before adding it
|
||||||
target_portal = port["portal"]
|
target_portal = port["portal"]
|
||||||
if not isinstance(target_portal.split(":")[0], str):
|
portal, p_sep, p_port = target_portal.rpartition(':')
|
||||||
portal = (target_portal.split(":")[0]).decode('utf8')
|
portal = portal.strip('[]')
|
||||||
else:
|
check_ip = ipaddress.ip_address(portal)
|
||||||
portal = target_portal.split(":")[0]
|
for check_cidr in check_cidrs:
|
||||||
check_ip = ipaddress.IPv4Address(portal)
|
if check_ip in check_cidr:
|
||||||
if check_ip in check_cidr:
|
target_luns.append(target["connection"]["lun"])
|
||||||
target_luns.append(target["connection"]["lun"])
|
target_iqns.append(port["iqn"])
|
||||||
target_iqns.append(port["iqn"])
|
target_portals.append(target_portal)
|
||||||
target_portals.append(target_portal)
|
|
||||||
|
|
||||||
LOG.info("iSCSI target portals that match CIDR range: '%s'",
|
LOG.info("iSCSI target portals that match CIDR range: '%s'",
|
||||||
target_portals)
|
target_portals)
|
||||||
|
12
releasenotes/notes/pure-iscsi-cidrs-7195eda9f7214fce.yaml
Normal file
12
releasenotes/notes/pure-iscsi-cidrs-7195eda9f7214fce.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Pure Storage FlashArray driver `bug 1910143
|
||||||
|
<https://bugs.launchpad.net/cinder/+bug/1910143>`_: Parameter
|
||||||
|
``pure_iscsi_cidr`` is now IPv4/v6 agnostic.
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Pure Storage FlashArray driver: added configuration option
|
||||||
|
``pure_iscsi_cidr_list`` for setting several network CIDRs for iSCSI target
|
||||||
|
connection. Both IPv4 and IPv6 is supported. The default still allows all
|
||||||
|
IPv4 targets.
|
Loading…
Reference in New Issue
Block a user