[Pure Storage] Fix issue with LACP ports not being identified
When using iSCSI or NVMe as dataplanes target ports are identified directly from the backend. When an LACP bond is created this was not being correctly identified as valid. This patch resolves this issue. Closes-Bug: #2101859 Change-Id: I5b56c590a6c9b82ab2e08e4211bfd3d187afdf8e
This commit is contained in:
parent
79928cd6a9
commit
5070eeaecf
@ -590,7 +590,34 @@ NON_ISCSI_PORT = {
|
||||
"portal": None,
|
||||
"wwn": "5001500150015081",
|
||||
}
|
||||
NVME_PORTS_WITH = NVME_PORTS + [NON_ISCSI_PORT]
|
||||
ISCSI_LACP_PORTS = [
|
||||
{
|
||||
"name": "lacp2",
|
||||
"iqn": TARGET_IQN,
|
||||
"nqn": None,
|
||||
"portal": None,
|
||||
"wwn": None,
|
||||
},
|
||||
]
|
||||
NVME_LACP_PORTS = [
|
||||
{
|
||||
"name": "lacp0",
|
||||
"iqn": None,
|
||||
"nqn": TARGET_NQN,
|
||||
"portal": None,
|
||||
"wwn": None,
|
||||
},
|
||||
{
|
||||
"name": "lacp1",
|
||||
"iqn": None,
|
||||
"nqn": TARGET_NQN,
|
||||
"portal": None,
|
||||
"wwn": None,
|
||||
},
|
||||
]
|
||||
NVME_PORTS_WITH = NVME_PORTS + [NON_ISCSI_PORT] + NVME_LACP_PORTS
|
||||
ISCSI_PORTS_WITH = ISCSI_PORTS + ISCSI_LACP_PORTS
|
||||
PORTS_WITH = ISCSI_PORTS + [NON_ISCSI_PORT] + ISCSI_LACP_PORTS
|
||||
PORTS_WITH = ISCSI_PORTS + [NON_ISCSI_PORT]
|
||||
PORTS_WITHOUT = [NON_ISCSI_PORT]
|
||||
TOTAL_CAPACITY = 50.0
|
||||
@ -1175,6 +1202,56 @@ QOS_BWS = {"maxBWS": "1"}
|
||||
ARRAY_RESPONSE = {
|
||||
'status_code': 200
|
||||
}
|
||||
INTERFACES = [
|
||||
{
|
||||
'name': 'ct0.eth4',
|
||||
'services': ['nvme-tcp'],
|
||||
'eth': {'address': '1.1.1.1',
|
||||
'subtype': 'physical'},
|
||||
},
|
||||
{
|
||||
'name': 'ct0.eth5',
|
||||
'services': ['iscsi'],
|
||||
'eth': {'address': '2.2.2.2',
|
||||
'subtype': 'physical'},
|
||||
},
|
||||
{
|
||||
'name': 'ct0.eth20',
|
||||
'services': ['nvme-roce'],
|
||||
'eth': {'address': '3.3.3.3',
|
||||
'subtype': 'physical'}
|
||||
},
|
||||
{
|
||||
'name': 'ct0.fc4',
|
||||
'services': ['nvme-fc'],
|
||||
'eth': {'address': None,
|
||||
'subtype': 'physical'},
|
||||
},
|
||||
{
|
||||
'name': 'lacp0',
|
||||
'services': ['nvme-roce'],
|
||||
'eth': {'address': '4.4.4.4',
|
||||
'subtype': 'lacp_bond'},
|
||||
},
|
||||
{
|
||||
'name': 'lacp1',
|
||||
'services': ['nvme-tcp'],
|
||||
'eth': {'address': '5.5.5.5',
|
||||
'subtype': 'lacp_bond'},
|
||||
},
|
||||
{
|
||||
'name': 'lacp2',
|
||||
'services': ['iscsi'],
|
||||
'eth': {'address': '6.6.6.6',
|
||||
'subtype': 'lacp_bond'},
|
||||
},
|
||||
{
|
||||
'name': 'ct0.fc1',
|
||||
'services': ['scsi-fc'],
|
||||
'eth': {'address': None,
|
||||
'subtype': 'physical'},
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
class PureDriverTestCase(test.TestCase):
|
||||
@ -4501,21 +4578,27 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
|
||||
def test_get_target_iscsi_ports(self):
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
self.array.get_ports.return_value = VALID_ISCSI_PORTS
|
||||
self.array.get_network_interfaces.return_value = ValidResponse(
|
||||
200, None, 1, [DotNotation(INTERFACES[1])], {})
|
||||
ret = self.driver._get_target_iscsi_ports(self.array)
|
||||
self.assertEqual(ISCSI_PORTS[0:4], ret)
|
||||
self.assertEqual(ISCSI_PORTS[0:4], ret[0:4])
|
||||
|
||||
def test_get_target_iscsi_ports_with_iscsi_and_fc(self):
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
PORTS_DATA = [DotNotation(i) for i in PORTS_WITH]
|
||||
PORTS_DATA = [DotNotation(i) for i in ISCSI_PORTS_WITH]
|
||||
ifc_ports = ValidResponse(200, None, 1, PORTS_DATA, {})
|
||||
self.array.get_ports.return_value = ifc_ports
|
||||
self.array.get_network_interfaces.return_value = ValidResponse(
|
||||
200, None, 1, [DotNotation(INTERFACES[0])], {})
|
||||
ret = self.driver._get_target_iscsi_ports(self.array)
|
||||
self.assertEqual(ISCSI_PORTS, ret)
|
||||
self.assertEqual(ISCSI_PORTS_WITH[0:9], ret[0:9])
|
||||
|
||||
def test_get_target_iscsi_ports_with_no_ports(self):
|
||||
# Should raise an exception if there are no ports
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
no_ports = ValidResponse(200, None, 1, [], {})
|
||||
self.array.get_network_interfaces.return_value = ValidResponse(
|
||||
200, None, 1, [], {})
|
||||
self.array.get_ports.return_value = no_ports
|
||||
self.assertRaises(pure.PureDriverException,
|
||||
self.driver._get_target_iscsi_ports,
|
||||
@ -4525,6 +4608,8 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
|
||||
# Should raise an exception of there are no iscsi ports
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
PORTS_NOISCSI = [DotNotation(i) for i in PORTS_WITHOUT]
|
||||
self.array.get_network_interfaces.return_value = ValidResponse(
|
||||
200, None, 1, [DotNotation(INTERFACES[3])], {})
|
||||
self.array.get_ports.\
|
||||
return_value = ValidResponse(200, None, 1, PORTS_NOISCSI, {})
|
||||
self.assertRaises(pure.PureDriverException,
|
||||
@ -5677,18 +5762,20 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
||||
{'name': 'CT0.FC4',
|
||||
'wwn': TARGET_WWN,
|
||||
'iqn': None,
|
||||
'nqn': TARGET_NQN},
|
||||
{'name': 'LACP0',
|
||||
'wwn': None,
|
||||
'iqn': None,
|
||||
'nqn': TARGET_NQN},
|
||||
{'name': 'LACP1',
|
||||
'wwn': None,
|
||||
'iqn': None,
|
||||
'nqn': TARGET_NQN}]
|
||||
interfaces = [
|
||||
{'name': 'ct0.eth4', 'services': ['nvme-tcp']},
|
||||
{'name': 'ct0.eth5', 'services': ['iscsi']},
|
||||
{'name': 'ct0.eth20', 'services': ['nvme-roce']},
|
||||
{'name': 'ct0.fc4', 'services': ['nvme-fc']}
|
||||
]
|
||||
# Test for the nvme-tcp port
|
||||
self.driver.configuration.pure_nvme_transport = "tcp"
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
nvme_interfaces = ValidResponse(200, None, 4,
|
||||
[DotNotation(interfaces[x])
|
||||
[DotNotation(INTERFACES[x])
|
||||
for x in range(4)], {})
|
||||
self.array.get_network_interfaces.return_value = nvme_interfaces
|
||||
nvme_ports = ValidResponse(200, None, 4,
|
||||
@ -5711,17 +5798,37 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
||||
# Test for the nvme-roce port
|
||||
self.driver.configuration.pure_nvme_transport = "roce"
|
||||
nvme_roce_interface = ValidResponse(200, None, 1,
|
||||
[DotNotation(interfaces[2])], {})
|
||||
[DotNotation(INTERFACES[2])], {})
|
||||
self.array.get_network_interfaces.return_value = nvme_roce_interface
|
||||
nvme_roce_ports = ValidResponse(200, None, 1,
|
||||
[DotNotation(ports[2])], {})
|
||||
self.array.get_ports.return_value = nvme_roce_ports
|
||||
ret = self.driver._get_target_nvme_ports(self.array)
|
||||
self.assertEqual([ports[2]], ret)
|
||||
self.assertEqual([ports[2]], [ret[0]])
|
||||
# Test for the nvme-roce LACP port
|
||||
self.driver.configuration.pure_nvme_transport = "roce"
|
||||
nvme_roce_interface = ValidResponse(200, None, 1,
|
||||
[DotNotation(INTERFACES[4])], {})
|
||||
self.array.get_network_interfaces.return_value = nvme_roce_interface
|
||||
nvme_roce_ports = ValidResponse(200, None, 1,
|
||||
[DotNotation(ports[4])], {})
|
||||
self.array.get_ports.return_value = nvme_roce_ports
|
||||
ret = self.driver._get_target_nvme_ports(self.array)
|
||||
self.assertEqual([ports[4]], [ret[0]])
|
||||
# Test for the nvme-tcp LACP port
|
||||
self.driver.configuration.pure_nvme_transport = "tcp"
|
||||
nvme_roce_interface = ValidResponse(200, None, 1,
|
||||
[DotNotation(INTERFACES[5])], {})
|
||||
self.array.get_network_interfaces.return_value = nvme_roce_interface
|
||||
nvme_roce_ports = ValidResponse(200, None, 1,
|
||||
[DotNotation(ports[5])], {})
|
||||
self.array.get_ports.return_value = nvme_roce_ports
|
||||
ret = self.driver._get_target_nvme_ports(self.array)
|
||||
self.assertEqual([ports[5]], [ret[0]])
|
||||
# Test for empty dict if only nvme-fc port
|
||||
self.driver.configuration.pure_nvme_transport = "roce"
|
||||
nvme_fc_interface = ValidResponse(200, None, 1,
|
||||
[DotNotation(interfaces[3])], {})
|
||||
[DotNotation(INTERFACES[3])], {})
|
||||
self.array.get_network_interfaces.return_value = nvme_fc_interface
|
||||
nvme_fc_ports = ValidResponse(200, None, 1,
|
||||
[DotNotation(ports[3])], {})
|
||||
@ -5733,7 +5840,9 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
||||
# Should raise an exception if there are no ports
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
nvme_no_ports = ValidResponse(200, None, 1, [], {})
|
||||
nvme_no_interfaces = ValidResponse(200, None, 1, [], {})
|
||||
self.array.get_ports.return_value = nvme_no_ports
|
||||
self.array.get_network_interfaces.return_value = nvme_no_interfaces
|
||||
self.assertRaises(
|
||||
pure.PureDriverException,
|
||||
self.driver._get_target_nvme_ports,
|
||||
@ -5743,8 +5852,12 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
||||
def test_get_target_nvme_ports_with_only_fc_ports(self):
|
||||
# Should raise an exception of there are no nvme ports
|
||||
self.array.get_controllers.return_value = CTRL_OBJ
|
||||
nvme_noports = ValidResponse(200, None, 1, [PORTS_WITHOUT], {})
|
||||
PORTS_NONVME = [DotNotation(i) for i in PORTS_WITHOUT]
|
||||
nvme_noports = ValidResponse(200, None, 1, PORTS_NONVME, {})
|
||||
nvme_nointerfaces = ValidResponse(200, None, 1,
|
||||
[DotNotation(INTERFACES[3])], {})
|
||||
self.array.get_ports.return_value = nvme_noports
|
||||
self.array.get_network_interfaces.return_value = nvme_nointerfaces
|
||||
self.assertRaises(
|
||||
pure.PureDriverException,
|
||||
self.driver._get_target_nvme_ports,
|
||||
|
@ -3081,6 +3081,18 @@ class PureBaseVolumeDriver(san.SanDriver):
|
||||
ports += list(
|
||||
array.get_ports(filter="name='" + controller + ".*'").items
|
||||
)
|
||||
lacps = list(
|
||||
array.get_network_interfaces(
|
||||
filter="eth.subtype='lacp_bond'"
|
||||
).items
|
||||
)
|
||||
if lacps:
|
||||
for lacp in range(0, len(lacps)):
|
||||
ports += list(
|
||||
array.get_ports(
|
||||
names=[lacps[lacp].name.upper()]
|
||||
).items
|
||||
)
|
||||
return ports
|
||||
|
||||
|
||||
@ -3729,13 +3741,13 @@ class PureNVMEDriver(PureBaseVolumeDriver, driver.BaseVD):
|
||||
valid_nvme_ports = []
|
||||
nvme_ports = [port for port in ports if getattr(port, "nqn", None)]
|
||||
for port in range(0, len(nvme_ports)):
|
||||
if "ETH" in nvme_ports[port].name:
|
||||
port_detail = list(array.get_network_interfaces(
|
||||
names=[nvme_ports[port].name]
|
||||
).items)[0]
|
||||
if port_detail.services[0] == "nvme-" + \
|
||||
self.configuration.pure_nvme_transport:
|
||||
valid_nvme_ports.append(nvme_ports[port])
|
||||
port_detail = list(array.get_network_interfaces(
|
||||
names=[nvme_ports[port].name.lower()]
|
||||
).items)[0]
|
||||
if hasattr(port_detail.eth, "address") and (
|
||||
port_detail.services[0] == "nvme-" +
|
||||
self.configuration.pure_nvme_transport):
|
||||
valid_nvme_ports.append(nvme_ports[port])
|
||||
if not nvme_ports:
|
||||
raise PureDriverException(
|
||||
reason=_("No %(type)s enabled ports on target array.") %
|
||||
|
7
releasenotes/notes/pure_lacp_iscsi-34678bdb98fa6bab.yaml
Normal file
7
releasenotes/notes/pure_lacp_iscsi-34678bdb98fa6bab.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Pure Storage `bug #2101859
|
||||
<https://bugs.launchpad.net/cinder/+bug/2101859>`_: Fixed issue where
|
||||
LACP bonds were not been correctly identified as iSCSI and NVMe
|
||||
targets.
|
Loading…
x
Reference in New Issue
Block a user