Skip to content

Commit 1d0d819

Browse files
committed
Leverage parsed LLDP inspection hook data and handle pairs of cabs
1 parent ebaa41e commit 1d0d819

File tree

5 files changed

+314
-228
lines changed

5 files changed

+314
-228
lines changed

python/ironic-understack/ironic_understack/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def setup_conf():
2525
"4f": "storage-appliance",
2626
"1d": "bmc",
2727
},
28-
)
28+
),
2929
]
3030
cfg.CONF.register_group(grp)
3131
cfg.CONF.register_opts(opts, group=grp)
Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,61 @@
1-
from ironic.objects import port as ironic_port
1+
import logging
22
from oslo_utils import uuidutils
33

44
from ironic_understack.update_baremetal_port import UpdateBaremetalPortsHook
55

6-
_INTERFACE_1 = {
7-
"name": "example1",
8-
"mac_address": "11:11:11:11:11:11",
9-
"ipv4_address": "1.1.1.1",
10-
"lldp": [
11-
(0, ""),
12-
(1, "04885a92ec5459"),
13-
(2, "0545746865726e6574312f3138"),
14-
(3, "0078"),
15-
(5, "6632302d332d32662e69616433"),
16-
],
6+
_INVENTORY = {}
7+
_PLUGIN_DATA = {
8+
"all_interfaces": {
9+
"ex1": {
10+
"name": "ex1",
11+
"mac_address": "11:11:11:11:11:11",
12+
},
13+
"ex2": {
14+
"name": "ex2",
15+
"mac_address": "22:22:22:22:22:22",
16+
},
17+
"ex3": {
18+
"name": "ex3",
19+
"mac_address": "33:33:33:33:33:33",
20+
},
21+
"ex4": {
22+
"name": "ex4",
23+
"mac_address": "44:44:44:44:44:44",
24+
},
25+
},
26+
"parsed_lldp": {
27+
"ex1": {
28+
"switch_chassis_id": "88:5a:92:ec:54:59",
29+
"switch_port_id": "Ethernet1/18",
30+
"switch_system_name": "f20-3-1.iad3",
31+
},
32+
"ex2": {
33+
"switch_chassis_id": "88:5a:92:ec:54:59",
34+
"switch_port_id": "Ethernet1/18",
35+
"switch_system_name": "f20-3-2.iad3",
36+
},
37+
"ex3": {
38+
"switch_chassis_id": "88:5a:92:ec:54:59",
39+
"switch_port_id": "Ethernet1/18",
40+
"switch_system_name": "f20-3-1f.iad3",
41+
},
42+
"ex4": {
43+
"switch_chassis_id": "88:5a:92:ec:54:59",
44+
"switch_port_id": "Ethernet1/18",
45+
"switch_system_name": "f20-3-2f.iad3",
46+
},
47+
},
1748
}
1849

19-
_PLUGIN_DATA = {"all_interfaces": {"example1": _INTERFACE_1}}
20-
21-
_INVENTORY = {"interfaces": [_INTERFACE_1]}
50+
MAPPING = {
51+
"1": "network", "2": "network",
52+
"1f": "storage", "2f": "storage",
53+
"-1d": "bmc",
54+
}
2255

56+
def test_with_valid_data(mocker, caplog):
57+
caplog.set_level(logging.DEBUG)
2358

24-
def test_with_valid_data(mocker):
2559
node_uuid = uuidutils.generate_uuid()
2660
mock_traits = mocker.Mock()
2761
mock_context = mocker.Mock()
@@ -34,24 +68,31 @@ def test_with_valid_data(mocker):
3468
local_link_connection={},
3569
physical_network="original_value",
3670
)
71+
72+
mocker.patch(
73+
"ironic_understack.update_baremetal_port.ironic_ports_for_node",
74+
return_value=[mock_port]
75+
)
3776
mocker.patch(
38-
"ironic_understack.update_baremetal_port.objects.port.Port.get_by_address",
39-
return_value=mock_port,
77+
"ironic_understack.update_baremetal_port.CONF.ironic_understack.switch_name_vlan_group_mapping",
78+
MAPPING
4079
)
4180

42-
mock_traits.get_trait_names.return_value = ["CUSTOM_NETWORK_SWITCH", "bar"]
81+
mock_traits.get_trait_names.return_value = ["CUSTOM_BMC_SWITCH", "bar"]
4382

4483
UpdateBaremetalPortsHook().__call__(mock_task, _INVENTORY, _PLUGIN_DATA)
4584

4685
assert mock_port.local_link_connection == {
4786
"port_id": "Ethernet1/18",
4887
"switch_id": "88:5a:92:ec:54:59",
49-
"switch_info": "f20-3-2f.iad3",
88+
"switch_info": "f20-3-1.iad3",
5089
}
51-
assert mock_port.physical_network == "f20-3-storage"
90+
assert mock_port.physical_network == "f20-3-network"
5291
mock_port.save.assert_called()
5392

5493
mock_traits.get_trait_names.assert_called_once()
55-
mock_traits.destroy.assert_called_once_with("CUSTOM_NETWORK_SWITCH")
56-
mock_traits.create.assert_called_once_with(mock_context, 1234, ["CUSTOM_STORAGE_SWITCH"])
94+
mock_traits.destroy.assert_called_once_with("CUSTOM_BMC_SWITCH")
95+
mock_traits.create.assert_called_once_with(
96+
mock_context, 1234, ["CUSTOM_NETWORK_SWITCH", "CUSTOM_STORAGE_SWITCH"]
97+
)
5798
mock_node.save.assert_called_once()
Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import pytest
22

3-
from ironic_understack.vlan_group_name_convention import vlan_group_name
3+
from ironic_understack.inspected_port import InspectedPort
4+
from ironic_understack.vlan_group_name_convention import TopologyError
5+
from ironic_understack.vlan_group_name_convention import vlan_group_names
46

57
mapping = {
68
"1": "network",
@@ -14,43 +16,105 @@
1416
"1d": "bmc",
1517
}
1618

17-
def test_vlan_group_name_valid_switches():
18-
assert vlan_group_name("a1-1-1", mapping) == "a1-1-network"
19-
assert vlan_group_name("a1-2-1", mapping) == "a1-2-network"
20-
assert vlan_group_name("b12-1", mapping) == "b12-network"
21-
assert vlan_group_name("a2-12-1", mapping) == "a2-12-network"
22-
assert vlan_group_name("a2-12-2", mapping) == "a2-12-network"
23-
assert vlan_group_name("a2-12-1f", mapping) == "a2-12-storage"
24-
assert vlan_group_name("a2-12-2f", mapping) == "a2-12-storage"
25-
assert vlan_group_name("a2-12-3f", mapping) == "a2-12-storage-appliance"
26-
assert vlan_group_name("a2-12-4f", mapping) == "a2-12-storage-appliance"
27-
assert vlan_group_name("a2-12-1d", mapping) == "a2-12-bmc"
2819

20+
def port(switch: str):
21+
return InspectedPort(
22+
mac_address="",
23+
name="",
24+
switch_system_name=switch,
25+
switch_chassis_id="",
26+
switch_port_id="",
27+
)
28+
29+
30+
def test_vlan_group_name_single_cab():
31+
assert vlan_group_names(
32+
[
33+
port("a1-1-1.abc1"),
34+
port("a1-1-2.abc1"),
35+
port("a1-1-1f.abc1"),
36+
port("a1-1-2f.abc1"),
37+
],
38+
mapping,
39+
) == {
40+
"a1-1-1.abc1": "a1-1-network",
41+
"a1-1-2.abc1": "a1-1-network",
42+
"a1-1-1f.abc1": "a1-1-storage",
43+
"a1-1-2f.abc1": "a1-1-storage",
44+
}
2945

30-
def test_vlan_group_name_with_domain():
31-
assert vlan_group_name("a2-12-1.iad3.rackspace.net", mapping) == "a2-12-network"
32-
assert vlan_group_name("a2-12-1f.lon3.rackspace.net", mapping) == "a2-12-storage"
3346

47+
def test_vlan_group_name_pair_cab():
48+
assert vlan_group_names(
49+
[
50+
port("a1-1-1.abc1"),
51+
port("a1-2-1.abc1"),
52+
port("a1-1-1f.abc1"),
53+
port("a1-2-1f.abc1"),
54+
],
55+
mapping,
56+
) == {
57+
"a1-1-1.abc1": "a1-1/a1-2-network",
58+
"a1-2-1.abc1": "a1-1/a1-2-network",
59+
"a1-1-1f.abc1": "a1-1/a1-2-storage",
60+
"a1-2-1f.abc1": "a1-1/a1-2-storage",
61+
}
3462

35-
def test_vlan_group_name_case_insensitive():
36-
assert vlan_group_name("A2-12-1F", mapping) == "a2-12-storage"
37-
assert vlan_group_name("A2-12-1", mapping) == "a2-12-network"
63+
64+
def test_vlan_group_name_with_domain():
65+
assert vlan_group_names(
66+
[
67+
port("a1-1-1.abc1.domain"),
68+
port("a1-1-2.abc1.domain"),
69+
port("a1-1-1f.abc1.domain"),
70+
port("a1-1-2f.abc1.domain"),
71+
],
72+
mapping,
73+
) == {
74+
"a1-1-1.abc1.domain": "a1-1-network",
75+
"a1-1-2.abc1.domain": "a1-1-network",
76+
"a1-1-1f.abc1.domain": "a1-1-storage",
77+
"a1-1-2f.abc1.domain": "a1-1-storage",
78+
}
3879

3980

4081
def test_vlan_group_name_invalid_format():
4182
with pytest.raises(ValueError, match="Unknown switch name format"):
42-
vlan_group_name("invalid", mapping)
83+
vlan_group_names([port("invalid.abc1")], mapping)
4384

4485
with pytest.raises(ValueError, match="Unknown switch name format"):
45-
vlan_group_name("", mapping)
86+
vlan_group_names([port(".abc1")], mapping)
4687

4788

4889
def test_vlan_group_name_unknown_suffix():
49-
with pytest.raises(ValueError, match="Switch suffix 99 is not present"):
50-
vlan_group_name("a2-12-99", mapping)
90+
with pytest.raises(TopologyError, match="Switch suffix 99 is not present"):
91+
vlan_group_names([port("a1-1-99.abc1")], mapping)
92+
93+
with pytest.raises(TopologyError, match="Switch suffix 5f is not present"):
94+
vlan_group_names([port("a1-1-5f.abc1")], mapping)
95+
96+
with pytest.raises(TopologyError, match="Switch suffix xyz is not present"):
97+
vlan_group_names([port("a1-1-xyz.abc1")], mapping)
98+
99+
100+
def test_vlan_group_name_many_dc():
101+
with pytest.raises(TopologyError, match="multiple"):
102+
vlan_group_names(
103+
[
104+
port("a1-1-1.abc1.domain"),
105+
port("a1-1-1.xyz2.domain"),
106+
],
107+
mapping,
108+
)
51109

52-
with pytest.raises(ValueError, match="Switch suffix 5f is not present"):
53-
vlan_group_name("a2-12-5f", mapping)
54110

55-
with pytest.raises(ValueError, match="Switch suffix xyz is not present"):
56-
vlan_group_name("a2-12-xyz", mapping)
111+
def test_vlan_group_name_too_many_racks():
112+
with pytest.raises(TopologyError, match="more than two racks"):
113+
vlan_group_names(
114+
[
115+
port("a1-1-1.abc1.domain"),
116+
port("a1-2-1.abc1.domain"),
117+
port("a1-3-1.abc1.domain"),
118+
],
119+
mapping,
120+
)

0 commit comments

Comments
 (0)