Merge ~ltrager/maas:lp1874917 into maas:master

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: 00efbf67dd2d36e2ecd5fed61807f9271e035f10
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:lp1874917
Merge into: maas:master
Diff against target: 151 lines (+82/-5)
3 files modified
src/maasserver/models/bmc.py (+2/-1)
src/metadataserver/builtin_scripts/hooks.py (+27/-4)
src/metadataserver/builtin_scripts/tests/test_hooks.py (+53/-0)
Reviewer Review Type Date Requested Status
Newell Jensen (community) Approve
MAAS Lander Approve
Review via email: mp+382958@code.launchpad.net

Commit message

LP: #1874917 - Skip network data from Controllers and Pods if duplicate MACs detected.

Controllers and Pods send commissioning information from a deployed
machine. If the machine is using a bond multiple interfaces will use
the same MAC address. Since MAAS identifies interfaces by MAC skip
updating interface information.

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b lp1874917 lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/7457/console
COMMIT: 53f6e118aaa20cfb7a70375443dc757ccafd2e5a

review: Needs Fixing
~ltrager/maas:lp1874917 updated
5476114... by Lee Trager

Fix division by 0 error

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b lp1874917 lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 5476114b203d32a6d2e5391b98b1dfa1c616f6ad

review: Approve
~ltrager/maas:lp1874917 updated
00efbf6... by Lee Trager

Fix showing system_id for assoicated machine.

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b lp1874917 lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 00efbf67dd2d36e2ecd5fed61807f9271e035f10

review: Approve
Revision history for this message
Newell Jensen (newell-jensen) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/models/bmc.py b/src/maasserver/models/bmc.py
2index a3aef32..cde8004 100644
3--- a/src/maasserver/models/bmc.py
4+++ b/src/maasserver/models/bmc.py
5@@ -642,7 +642,8 @@ class Pod(BMC):
6 interface = self.ip_address.get_interface()
7 if interface is not None:
8 return interface.node
9- return None
10+ else:
11+ return self.hints.nodes.first()
12
13 def sync_hints(self, discovered_hints):
14 """Sync the hints with `discovered_hints`."""
15diff --git a/src/metadataserver/builtin_scripts/hooks.py b/src/metadataserver/builtin_scripts/hooks.py
16index 801a4c1..ee5bd82 100644
17--- a/src/metadataserver/builtin_scripts/hooks.py
18+++ b/src/metadataserver/builtin_scripts/hooks.py
19@@ -35,6 +35,10 @@ from provisioningserver.utils.ipaddr import parse_ip_addr
20 logger = logging.getLogger(__name__)
21
22
23+class DuplicateMACs(Exception):
24+ """Exception for when duplicate MAC addresses are in commissioning data."""
25+
26+
27 SWITCH_TAG_NAME = "switch"
28 SWITCH_HARDWARE = [
29 # Seen on Facebook Wedge 40 switch:
30@@ -143,7 +147,13 @@ def _parse_interfaces(node, data):
31 link = ip_addr_info.get(interface["name"], {})
32 interface["ips"] = link.get("inet", []) + link.get("inet6", [])
33
34- interfaces[mac] = interface
35+ if mac in interfaces:
36+ raise DuplicateMACs(
37+ f"Duplicated MAC address({mac}) on "
38+ "{interfaces[mac]['name']} and {interface['name']}"
39+ )
40+ else:
41+ interfaces[mac] = interface
42
43 return interfaces
44
45@@ -248,7 +258,21 @@ def update_node_network_information(node, data, numa_nodes):
46 node.save(update_fields=["skip_networking"])
47 return
48
49- interfaces_info = _parse_interfaces(node, data)
50+ try:
51+ interfaces_info = _parse_interfaces(node, data)
52+ except DuplicateMACs:
53+ if node.is_controller or node.is_pod:
54+ # Controllers and Pods send commissioning information from a
55+ # deployed machine. If the machine is using a bond multiple
56+ # interfaces will use the same MAC address. Since MAAS identifies
57+ # interfaces by MAC skip updating interface information.
58+ # When MAAS gains the ability to model LXD's commissioning
59+ # information this can be removed.
60+ return
61+ else:
62+ # Duplicate MACs are not expected on machines, raise the
63+ # exception so this can be handled.
64+ raise
65 current_interfaces = set()
66
67 for mac, iface in interfaces_info.items():
68@@ -496,18 +520,17 @@ def _parse_cpuinfo(data):
69 current_average = 0
70 for socket in sockets:
71 current_average += socket.get("frequency", 0)
72- current_average /= len(sockets)
73 if current_average:
74 # Fall back on the current speed, round it to
75 # the nearest hundredth as the number may be
76 # effected by CPU scaling.
77+ current_average /= len(sockets)
78 cpu_speed = round(current_average / 100) * 100
79
80 return cpu_count, cpu_speed, cpu_model, numa_nodes
81
82
83 def _parse_memory(data, numa_nodes):
84-
85 total_memory = data.get("memory", {}).get("total", 0)
86 default_numa_node = {"numa_node": 0, "total": total_memory}
87 for memory_node in data.get("memory", {}).get(
88diff --git a/src/metadataserver/builtin_scripts/tests/test_hooks.py b/src/metadataserver/builtin_scripts/tests/test_hooks.py
89index 79474a2..c393f7d 100644
90--- a/src/metadataserver/builtin_scripts/tests/test_hooks.py
91+++ b/src/metadataserver/builtin_scripts/tests/test_hooks.py
92@@ -2414,6 +2414,59 @@ class TestUpdateNodeNetworkInformation(MAASServerTestCase):
93 self.assertIsNotNone(reload_object(boot_interface))
94 self.assertFalse(reload_object(node).skip_networking)
95
96+ def test__does_nothing_if_duplicate_mac_on_controller(self):
97+ mock_iface_get = self.patch(
98+ hooks_module.PhysicalInterface.objects, "get"
99+ )
100+ rack = factory.make_RackController()
101+ create_IPADDR_OUTPUT_NAME_script(rack, IP_ADDR_OUTPUT)
102+ mac = factory.make_mac_address()
103+ duplicate_mac_lxd_resources = deepcopy(SAMPLE_LXD_RESOURCES)
104+ for card in duplicate_mac_lxd_resources["network"]["cards"]:
105+ for port in card["ports"]:
106+ port["address"] = mac
107+ update_node_network_information(
108+ rack, duplicate_mac_lxd_resources, create_numa_nodes(rack)
109+ )
110+ self.assertThat(mock_iface_get, MockNotCalled())
111+
112+ def test__does_nothing_if_duplicate_mac_on_pod(self):
113+ self.useFixture(SignalsDisabled("podhints"))
114+ mock_iface_get = self.patch(
115+ hooks_module.PhysicalInterface.objects, "get"
116+ )
117+ pod = factory.make_Pod()
118+ node = factory.make_Node(
119+ status=NODE_STATUS.DEPLOYED, with_empty_script_sets=True
120+ )
121+ create_IPADDR_OUTPUT_NAME_script(node, IP_ADDR_OUTPUT)
122+ pod.hints.nodes.add(node)
123+ mac = factory.make_mac_address()
124+ duplicate_mac_lxd_resources = deepcopy(SAMPLE_LXD_RESOURCES)
125+ for card in duplicate_mac_lxd_resources["network"]["cards"]:
126+ for port in card["ports"]:
127+ port["address"] = mac
128+ update_node_network_information(
129+ node, duplicate_mac_lxd_resources, create_numa_nodes(node)
130+ )
131+ self.assertThat(mock_iface_get, MockNotCalled())
132+
133+ def test__raises_exception_if_duplicate_mac_on_machine(self):
134+ node = factory.make_Node()
135+ create_IPADDR_OUTPUT_NAME_script(node, IP_ADDR_OUTPUT)
136+ mac = factory.make_mac_address()
137+ duplicate_mac_lxd_resources = deepcopy(SAMPLE_LXD_RESOURCES)
138+ for card in duplicate_mac_lxd_resources["network"]["cards"]:
139+ for port in card["ports"]:
140+ port["address"] = mac
141+ self.assertRaises(
142+ hooks_module.DuplicateMACs,
143+ update_node_network_information,
144+ node,
145+ duplicate_mac_lxd_resources,
146+ create_numa_nodes(node),
147+ )
148+
149 def test__add_all_interfaces(self):
150 """Test a node that has no previously known interfaces on which we
151 need to add a series of interfaces.

Subscribers

People subscribed via source and target branches