Merge "[Pure Storage] Fix issue with LACP ports not being identified" into stable/2025.1
This commit is contained in:
commit
3df9d33c89
@ -590,7 +590,34 @@ NON_ISCSI_PORT = {
|
|||||||
"portal": None,
|
"portal": None,
|
||||||
"wwn": "5001500150015081",
|
"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_WITH = ISCSI_PORTS + [NON_ISCSI_PORT]
|
||||||
PORTS_WITHOUT = [NON_ISCSI_PORT]
|
PORTS_WITHOUT = [NON_ISCSI_PORT]
|
||||||
TOTAL_CAPACITY = 50.0
|
TOTAL_CAPACITY = 50.0
|
||||||
@ -1186,6 +1213,56 @@ VGROUP = 'puretest-vgroup'
|
|||||||
ARRAY_RESPONSE = {
|
ARRAY_RESPONSE = {
|
||||||
'status_code': 200
|
'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):
|
class PureDriverTestCase(test.TestCase):
|
||||||
@ -4746,21 +4823,27 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
def test_get_target_iscsi_ports(self):
|
def test_get_target_iscsi_ports(self):
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
self.array.get_controllers.return_value = CTRL_OBJ
|
||||||
self.array.get_ports.return_value = VALID_ISCSI_PORTS
|
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)
|
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):
|
def test_get_target_iscsi_ports_with_iscsi_and_fc(self):
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
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, {})
|
ifc_ports = ValidResponse(200, None, 1, PORTS_DATA, {})
|
||||||
self.array.get_ports.return_value = ifc_ports
|
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)
|
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):
|
def test_get_target_iscsi_ports_with_no_ports(self):
|
||||||
# Should raise an exception if there are no ports
|
# Should raise an exception if there are no ports
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
self.array.get_controllers.return_value = CTRL_OBJ
|
||||||
no_ports = ValidResponse(200, None, 1, [], {})
|
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.array.get_ports.return_value = no_ports
|
||||||
self.assertRaises(pure.PureDriverException,
|
self.assertRaises(pure.PureDriverException,
|
||||||
self.driver._get_target_iscsi_ports,
|
self.driver._get_target_iscsi_ports,
|
||||||
@ -4770,6 +4853,8 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
# Should raise an exception of there are no iscsi ports
|
# Should raise an exception of there are no iscsi ports
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
self.array.get_controllers.return_value = CTRL_OBJ
|
||||||
PORTS_NOISCSI = [DotNotation(i) for i in PORTS_WITHOUT]
|
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.\
|
self.array.get_ports.\
|
||||||
return_value = ValidResponse(200, None, 1, PORTS_NOISCSI, {})
|
return_value = ValidResponse(200, None, 1, PORTS_NOISCSI, {})
|
||||||
self.assertRaises(pure.PureDriverException,
|
self.assertRaises(pure.PureDriverException,
|
||||||
@ -5922,18 +6007,20 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
{'name': 'CT0.FC4',
|
{'name': 'CT0.FC4',
|
||||||
'wwn': TARGET_WWN,
|
'wwn': TARGET_WWN,
|
||||||
'iqn': None,
|
'iqn': None,
|
||||||
|
'nqn': TARGET_NQN},
|
||||||
|
{'name': 'LACP0',
|
||||||
|
'wwn': None,
|
||||||
|
'iqn': None,
|
||||||
|
'nqn': TARGET_NQN},
|
||||||
|
{'name': 'LACP1',
|
||||||
|
'wwn': None,
|
||||||
|
'iqn': None,
|
||||||
'nqn': TARGET_NQN}]
|
'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
|
# Test for the nvme-tcp port
|
||||||
self.driver.configuration.pure_nvme_transport = "tcp"
|
self.driver.configuration.pure_nvme_transport = "tcp"
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
self.array.get_controllers.return_value = CTRL_OBJ
|
||||||
nvme_interfaces = ValidResponse(200, None, 4,
|
nvme_interfaces = ValidResponse(200, None, 4,
|
||||||
[DotNotation(interfaces[x])
|
[DotNotation(INTERFACES[x])
|
||||||
for x in range(4)], {})
|
for x in range(4)], {})
|
||||||
self.array.get_network_interfaces.return_value = nvme_interfaces
|
self.array.get_network_interfaces.return_value = nvme_interfaces
|
||||||
nvme_ports = ValidResponse(200, None, 4,
|
nvme_ports = ValidResponse(200, None, 4,
|
||||||
@ -5956,17 +6043,37 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
# Test for the nvme-roce port
|
# Test for the nvme-roce port
|
||||||
self.driver.configuration.pure_nvme_transport = "roce"
|
self.driver.configuration.pure_nvme_transport = "roce"
|
||||||
nvme_roce_interface = ValidResponse(200, None, 1,
|
nvme_roce_interface = ValidResponse(200, None, 1,
|
||||||
[DotNotation(interfaces[2])], {})
|
[DotNotation(INTERFACES[2])], {})
|
||||||
self.array.get_network_interfaces.return_value = nvme_roce_interface
|
self.array.get_network_interfaces.return_value = nvme_roce_interface
|
||||||
nvme_roce_ports = ValidResponse(200, None, 1,
|
nvme_roce_ports = ValidResponse(200, None, 1,
|
||||||
[DotNotation(ports[2])], {})
|
[DotNotation(ports[2])], {})
|
||||||
self.array.get_ports.return_value = nvme_roce_ports
|
self.array.get_ports.return_value = nvme_roce_ports
|
||||||
ret = self.driver._get_target_nvme_ports(self.array)
|
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
|
# Test for empty dict if only nvme-fc port
|
||||||
self.driver.configuration.pure_nvme_transport = "roce"
|
self.driver.configuration.pure_nvme_transport = "roce"
|
||||||
nvme_fc_interface = ValidResponse(200, None, 1,
|
nvme_fc_interface = ValidResponse(200, None, 1,
|
||||||
[DotNotation(interfaces[3])], {})
|
[DotNotation(INTERFACES[3])], {})
|
||||||
self.array.get_network_interfaces.return_value = nvme_fc_interface
|
self.array.get_network_interfaces.return_value = nvme_fc_interface
|
||||||
nvme_fc_ports = ValidResponse(200, None, 1,
|
nvme_fc_ports = ValidResponse(200, None, 1,
|
||||||
[DotNotation(ports[3])], {})
|
[DotNotation(ports[3])], {})
|
||||||
@ -5978,7 +6085,9 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
# Should raise an exception if there are no ports
|
# Should raise an exception if there are no ports
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
self.array.get_controllers.return_value = CTRL_OBJ
|
||||||
nvme_no_ports = ValidResponse(200, None, 1, [], {})
|
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_ports.return_value = nvme_no_ports
|
||||||
|
self.array.get_network_interfaces.return_value = nvme_no_interfaces
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
pure.PureDriverException,
|
pure.PureDriverException,
|
||||||
self.driver._get_target_nvme_ports,
|
self.driver._get_target_nvme_ports,
|
||||||
@ -5988,8 +6097,12 @@ class PureNVMEDriverTestCase(PureBaseSharedDriverTestCase):
|
|||||||
def test_get_target_nvme_ports_with_only_fc_ports(self):
|
def test_get_target_nvme_ports_with_only_fc_ports(self):
|
||||||
# Should raise an exception of there are no nvme ports
|
# Should raise an exception of there are no nvme ports
|
||||||
self.array.get_controllers.return_value = CTRL_OBJ
|
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_ports.return_value = nvme_noports
|
||||||
|
self.array.get_network_interfaces.return_value = nvme_nointerfaces
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
pure.PureDriverException,
|
pure.PureDriverException,
|
||||||
self.driver._get_target_nvme_ports,
|
self.driver._get_target_nvme_ports,
|
||||||
|
@ -3554,6 +3554,18 @@ class PureBaseVolumeDriver(san.SanDriver):
|
|||||||
ports += list(
|
ports += list(
|
||||||
array.get_ports(filter="name='" + controller + ".*'").items
|
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
|
return ports
|
||||||
|
|
||||||
|
|
||||||
@ -4202,13 +4214,13 @@ class PureNVMEDriver(PureBaseVolumeDriver, driver.BaseVD):
|
|||||||
valid_nvme_ports = []
|
valid_nvme_ports = []
|
||||||
nvme_ports = [port for port in ports if getattr(port, "nqn", None)]
|
nvme_ports = [port for port in ports if getattr(port, "nqn", None)]
|
||||||
for port in range(0, len(nvme_ports)):
|
for port in range(0, len(nvme_ports)):
|
||||||
if "ETH" in nvme_ports[port].name:
|
port_detail = list(array.get_network_interfaces(
|
||||||
port_detail = list(array.get_network_interfaces(
|
names=[nvme_ports[port].name.lower()]
|
||||||
names=[nvme_ports[port].name]
|
).items)[0]
|
||||||
).items)[0]
|
if hasattr(port_detail.eth, "address") and (
|
||||||
if port_detail.services[0] == "nvme-" + \
|
port_detail.services[0] == "nvme-" +
|
||||||
self.configuration.pure_nvme_transport:
|
self.configuration.pure_nvme_transport):
|
||||||
valid_nvme_ports.append(nvme_ports[port])
|
valid_nvme_ports.append(nvme_ports[port])
|
||||||
if not nvme_ports:
|
if not nvme_ports:
|
||||||
raise PureDriverException(
|
raise PureDriverException(
|
||||||
reason=_("No %(type)s enabled ports on target array.") %
|
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