Merge ~bjornt/maas:bug-2043970-vlan-interfaces-3.5 into maas:3.5
- Git
- lp:~bjornt/maas
- bug-2043970-vlan-interfaces-3.5
- Merge into 3.5
Proposed by
Björn Tillenius
Status: | Merged |
---|---|
Approved by: | Björn Tillenius |
Approved revision: | 24117f0b806ca947144dfe1386a9d001485a4ce0 |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~bjornt/maas:bug-2043970-vlan-interfaces-3.5 |
Merge into: | maas:3.5 |
Diff against target: |
464 lines (+246/-80) 2 files modified
src/metadataserver/builtin_scripts/network.py (+65/-60) src/metadataserver/builtin_scripts/tests/test_network.py (+181/-20) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Björn Tillenius | Approve | ||
Review via email: mp+465138@code.launchpad.net |
Commit message
Bug #2043970: MAAS 3.2.9 creates for Calico Interfaces 80.000 fabrics
Redo the fix for bug #2043970.
In some cases we need to create VLANs/fabrics for interfaces that don't have
links. For example for VLAN interfaces, often it's the VLAN interface that has
an address, while the underlying physical interface often is without any
address. In that case, the physical interface should have a VLAN that is on the
same fabric as the VLAN interface.
Also removed the check whether a machine is a controller. A controller is not
special. It's a deployed machine. If Calico is installed on a controller, we
should not create useless fabrics.
(cherry picked from commit 94dac1082c3a395
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/metadataserver/builtin_scripts/network.py b/src/metadataserver/builtin_scripts/network.py | |||
2 | index 9282986..58f8120 100644 | |||
3 | --- a/src/metadataserver/builtin_scripts/network.py | |||
4 | +++ b/src/metadataserver/builtin_scripts/network.py | |||
5 | @@ -13,7 +13,7 @@ from maasserver.models.interface import ( | |||
6 | 13 | ) | 13 | ) |
7 | 14 | from maasserver.models.staticipaddress import StaticIPAddress | 14 | from maasserver.models.staticipaddress import StaticIPAddress |
8 | 15 | from maasserver.models.subnet import Subnet | 15 | from maasserver.models.subnet import Subnet |
10 | 16 | from maasserver.models.vlan import VLAN | 16 | from maasserver.models.vlan import DEFAULT_VID, VLAN |
11 | 17 | from maasserver.utils.orm import transactional | 17 | from maasserver.utils.orm import transactional |
12 | 18 | from provisioningserver.events import EVENT_TYPES | 18 | from provisioningserver.events import EVENT_TYPES |
13 | 19 | from provisioningserver.logger import get_maas_logger | 19 | from provisioningserver.logger import get_maas_logger |
14 | @@ -266,7 +266,7 @@ def update_physical_interface( | |||
15 | 266 | if hints is not None: | 266 | if hints is not None: |
16 | 267 | new_vlan = guess_vlan_from_hints(node, name, hints) | 267 | new_vlan = guess_vlan_from_hints(node, name, hints) |
17 | 268 | if new_vlan is None: | 268 | if new_vlan is None: |
19 | 269 | new_vlan = guess_vlan_for_interface(node, links) | 269 | new_vlan = guess_vlan_for_interface(node, interface, links) |
20 | 270 | if new_vlan is not None: | 270 | if new_vlan is not None: |
21 | 271 | interface.vlan = new_vlan | 271 | interface.vlan = new_vlan |
22 | 272 | update_fields.add("vlan") | 272 | update_fields.add("vlan") |
23 | @@ -362,16 +362,19 @@ def update_vlan_interface(node, name, network, links): | |||
24 | 362 | parent_nic = Interface.objects.get( | 362 | parent_nic = Interface.objects.get( |
25 | 363 | node_config=node.current_config, name=parent_name | 363 | node_config=node.current_config, name=parent_name |
26 | 364 | ) | 364 | ) |
27 | 365 | parent_fabric = None | ||
28 | 366 | if parent_nic.vlan is not None: | ||
29 | 367 | parent_fabric = parent_nic.vlan.fabric | ||
30 | 365 | links_vlan = get_interface_vlan_from_links(links) | 368 | links_vlan = get_interface_vlan_from_links(links) |
31 | 369 | interface = VLANInterface.objects.filter( | ||
32 | 370 | node_config=node.current_config, | ||
33 | 371 | name=name, | ||
34 | 372 | parents__id=parent_nic.id, | ||
35 | 373 | vlan__vid=vid, | ||
36 | 374 | ).first() | ||
37 | 366 | if links_vlan: | 375 | if links_vlan: |
38 | 367 | vlan = links_vlan | 376 | vlan = links_vlan |
46 | 368 | if parent_nic.vlan.fabric_id != vlan.fabric_id: | 377 | parent_fabric = vlan.fabric |
40 | 369 | # XXX: We should surface this error to the API and UI, since | ||
41 | 370 | # it's something the user needs to fix. | ||
42 | 371 | maaslog.error( | ||
43 | 372 | f"Interface '{parent_nic.name}' on controller '{node.hostname}' " | ||
44 | 373 | f"is not on the same fabric as VLAN interface '{name}'." | ||
45 | 374 | ) | ||
47 | 375 | if links_vlan.vid != vid: | 378 | if links_vlan.vid != vid: |
48 | 376 | maaslog.error( | 379 | maaslog.error( |
49 | 377 | f"VLAN interface '{name}' reports VLAN {vid} " | 380 | f"VLAN interface '{name}' reports VLAN {vid} " |
50 | @@ -379,41 +382,31 @@ def update_vlan_interface(node, name, network, links): | |||
51 | 379 | ) | 382 | ) |
52 | 380 | else: | 383 | else: |
53 | 381 | vlan = None | 384 | vlan = None |
54 | 385 | if interface is not None and interface.vlan is not None: | ||
55 | 386 | vlan = interface.vlan | ||
56 | 387 | parent_fabric = vlan.fabric | ||
57 | 388 | elif parent_fabric is None: | ||
58 | 389 | maaslog.info( | ||
59 | 390 | f"Unable to detect fabric VLAN Interface '{name}', using default" | ||
60 | 391 | ) | ||
61 | 392 | parent_fabric = Fabric.objects.get_default_fabric() | ||
62 | 393 | |||
63 | 394 | if parent_nic.vlan_id is None: | ||
64 | 395 | parent_vlan, _ = VLAN.objects.get_or_create( | ||
65 | 396 | fabric=parent_fabric, | ||
66 | 397 | vid=DEFAULT_VID, | ||
67 | 398 | ) | ||
68 | 399 | parent_nic.vlan = parent_vlan | ||
69 | 400 | parent_nic.save() | ||
70 | 382 | 401 | ||
71 | 383 | from metadataserver.builtin_scripts.hooks import HARDWARE_SYNC_ACTIONS | 402 | from metadataserver.builtin_scripts.hooks import HARDWARE_SYNC_ACTIONS |
72 | 384 | 403 | ||
104 | 385 | interface = VLANInterface.objects.filter( | 404 | if vlan is None: |
105 | 386 | node_config=node.current_config, | 405 | # Since no suitable VLAN is found, create a new one in the same |
106 | 387 | name=name, | 406 | # fabric as the parent interface. |
107 | 388 | parents__id=parent_nic.id, | 407 | vlan, _ = VLAN.objects.get_or_create(fabric=parent_fabric, vid=vid) |
77 | 389 | vlan__vid=vid, | ||
78 | 390 | ).first() | ||
79 | 391 | if interface is None: | ||
80 | 392 | if vlan is None: | ||
81 | 393 | # Since no suitable VLAN is found, create a new one in the same | ||
82 | 394 | # fabric as the parent interface. | ||
83 | 395 | if parent_nic.vlan: | ||
84 | 396 | vlan, _ = VLAN.objects.get_or_create( | ||
85 | 397 | fabric=parent_nic.vlan.fabric, vid=vid | ||
86 | 398 | ) | ||
87 | 399 | elif network["addresses"]: # use IP address to find VLAN | ||
88 | 400 | address = network["addresses"][0]["address"] | ||
89 | 401 | try: | ||
90 | 402 | subnet = Subnet.objects.get_subnet_for_ip(address) | ||
91 | 403 | except Subnet.DoesNotExist: | ||
92 | 404 | pass | ||
93 | 405 | else: | ||
94 | 406 | vlan, _ = VLAN.objects.get_or_create( | ||
95 | 407 | fabric=subnet.vlan.fabric, vid=vid | ||
96 | 408 | ) | ||
97 | 409 | if vlan is None: | ||
98 | 410 | maaslog.error( | ||
99 | 411 | f"Unable to detect fabric VLAN Interface '{name}', using default" | ||
100 | 412 | ) | ||
101 | 413 | vlan, _ = VLAN.objects.get_or_create( | ||
102 | 414 | fabric=Fabric.objects.get_default_fabric(), vid=vid | ||
103 | 415 | ) | ||
108 | 416 | 408 | ||
109 | 409 | if interface is None: | ||
110 | 417 | interface, created = VLANInterface.objects.get_or_create( | 410 | interface, created = VLANInterface.objects.get_or_create( |
111 | 418 | node_config=node.current_config, | 411 | node_config=node.current_config, |
112 | 419 | name=name, | 412 | name=name, |
113 | @@ -435,6 +428,14 @@ def update_vlan_interface(node, name, network, links): | |||
114 | 435 | node, interface, HARDWARE_SYNC_ACTIONS.UPDATED | 428 | node, interface, HARDWARE_SYNC_ACTIONS.UPDATED |
115 | 436 | ) | 429 | ) |
116 | 437 | 430 | ||
117 | 431 | if parent_nic.vlan.fabric_id != vlan.fabric_id: | ||
118 | 432 | # XXX: We should surface this error to the API and UI, since | ||
119 | 433 | # it's something the user needs to fix. | ||
120 | 434 | maaslog.error( | ||
121 | 435 | f"Interface '{parent_nic.name}' on controller '{node.hostname}' " | ||
122 | 436 | f"is not on the same fabric as VLAN interface '{name}'." | ||
123 | 437 | ) | ||
124 | 438 | |||
125 | 438 | update_links(node, interface, links, force_vlan=True) | 439 | update_links(node, interface, links, force_vlan=True) |
126 | 439 | return interface | 440 | return interface |
127 | 440 | 441 | ||
128 | @@ -507,10 +508,6 @@ def update_parent_vlans(node, interface, parent_nics, update_ip_addresses): | |||
129 | 507 | 508 | ||
130 | 508 | 509 | ||
131 | 509 | def auto_vlan_creation(node) -> bool: | 510 | def auto_vlan_creation(node) -> bool: |
132 | 510 | if node.is_controller: | ||
133 | 511 | # Always create controller's vlans | ||
134 | 512 | return True | ||
135 | 513 | |||
136 | 514 | if node.status == NODE_STATUS.DEPLOYED: | 511 | if node.status == NODE_STATUS.DEPLOYED: |
137 | 515 | # don't create empty vlan/fabric for interfaces discovered by HW sync, | 512 | # don't create empty vlan/fabric for interfaces discovered by HW sync, |
138 | 516 | # they cannot be used. | 513 | # they cannot be used. |
139 | @@ -519,25 +516,26 @@ def auto_vlan_creation(node) -> bool: | |||
140 | 519 | return Config.objects.get_config("auto_vlan_creation", True) | 516 | return Config.objects.get_config("auto_vlan_creation", True) |
141 | 520 | 517 | ||
142 | 521 | 518 | ||
144 | 522 | def guess_vlan_for_interface(node, links): | 519 | def guess_vlan_for_interface(node, interface, links): |
145 | 523 | # Make sure that the VLAN on the interface is correct. When | 520 | # Make sure that the VLAN on the interface is correct. When |
146 | 524 | # links exists on this interface we place it into the correct | 521 | # links exists on this interface we place it into the correct |
147 | 525 | # VLAN. If it cannot be determined and its a new interface it | 522 | # VLAN. If it cannot be determined and its a new interface it |
148 | 526 | # gets placed on its own fabric. | 523 | # gets placed on its own fabric. |
149 | 527 | new_vlan = get_interface_vlan_from_links(links) | 524 | new_vlan = get_interface_vlan_from_links(links) |
163 | 528 | if new_vlan is None and auto_vlan_creation(node): | 525 | if new_vlan is None: |
164 | 529 | # If the default VLAN on the default fabric has no interfaces | 526 | if links: |
165 | 530 | # associated with it, the first interface will be placed there | 527 | update_links(node, interface, links) |
166 | 531 | # (rather than creating a new fabric). | 528 | new_vlan = get_interface_vlan_from_links(links) |
167 | 532 | default_vlan = VLAN.objects.get_default_vlan() | 529 | elif auto_vlan_creation(node): |
168 | 533 | interfaces_on_default_vlan = Interface.objects.filter( | 530 | default_vlan = VLAN.objects.get_default_vlan() |
169 | 534 | vlan=default_vlan | 531 | interfaces_on_default_vlan = Interface.objects.filter( |
170 | 535 | ).exists() | 532 | vlan=default_vlan |
171 | 536 | if not interfaces_on_default_vlan: | 533 | ).exists() |
172 | 537 | new_vlan = default_vlan | 534 | if not interfaces_on_default_vlan: |
173 | 538 | else: | 535 | new_vlan = default_vlan |
174 | 539 | new_fabric = Fabric.objects.create() | 536 | else: |
175 | 540 | new_vlan = new_fabric.get_default_vlan() | 537 | new_fabric = Fabric.objects.create() |
176 | 538 | new_vlan = new_fabric.get_default_vlan() | ||
177 | 541 | return new_vlan | 539 | return new_vlan |
178 | 542 | 540 | ||
179 | 543 | 541 | ||
180 | @@ -636,8 +634,15 @@ def update_links( | |||
181 | 636 | if use_interface_vlan and interface.vlan is not None: | 634 | if use_interface_vlan and interface.vlan is not None: |
182 | 637 | vlan = interface.vlan | 635 | vlan = interface.vlan |
183 | 638 | elif links: | 636 | elif links: |
186 | 639 | fabric = Fabric.objects.create() | 637 | default_vlan = VLAN.objects.get_default_vlan() |
187 | 640 | vlan = fabric.get_default_vlan() | 638 | interfaces_on_default_vlan = Interface.objects.filter( |
188 | 639 | vlan=default_vlan | ||
189 | 640 | ).exists() | ||
190 | 641 | if not interfaces_on_default_vlan: | ||
191 | 642 | vlan = default_vlan | ||
192 | 643 | else: | ||
193 | 644 | new_fabric = Fabric.objects.create() | ||
194 | 645 | vlan = new_fabric.get_default_vlan() | ||
195 | 641 | interface.vlan = vlan | 646 | interface.vlan = vlan |
196 | 642 | interface.save() | 647 | interface.save() |
197 | 643 | 648 | ||
198 | diff --git a/src/metadataserver/builtin_scripts/tests/test_network.py b/src/metadataserver/builtin_scripts/tests/test_network.py | |||
199 | index 214df73..24c1fa8 100644 | |||
200 | --- a/src/metadataserver/builtin_scripts/tests/test_network.py | |||
201 | +++ b/src/metadataserver/builtin_scripts/tests/test_network.py | |||
202 | @@ -87,7 +87,9 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
203 | 87 | eth0 = node.current_config.interface_set.get(name="eth0") | 87 | eth0 = node.current_config.interface_set.get(name="eth0") |
204 | 88 | self.assertEqual(eth0.numa_node, node.default_numanode) | 88 | self.assertEqual(eth0.numa_node, node.default_numanode) |
205 | 89 | 89 | ||
207 | 90 | def test_dont_create_default_vlan_for_deployed_machines(self): | 90 | def test_dont_create_default_vlan_for_missing_links_deployed_machines( |
208 | 91 | self, | ||
209 | 92 | ): | ||
210 | 91 | node = factory.make_Machine(status=NODE_STATUS.DEPLOYED) | 93 | node = factory.make_Machine(status=NODE_STATUS.DEPLOYED) |
211 | 92 | data = FakeCommissioningData() | 94 | data = FakeCommissioningData() |
212 | 93 | data_eth0 = data.create_physical_network( | 95 | data_eth0 = data.create_physical_network( |
213 | @@ -101,6 +103,174 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
214 | 101 | ) | 103 | ) |
215 | 102 | self.assertIsNone(eth0.vlan) | 104 | self.assertIsNone(eth0.vlan) |
216 | 103 | 105 | ||
217 | 106 | def test_vlan_interfaces_with_known_link_deployed_machine(self): | ||
218 | 107 | node = factory.make_Machine(status=NODE_STATUS.DEPLOYED) | ||
219 | 108 | vlan123 = factory.make_VLAN(vid=123) | ||
220 | 109 | vlan456 = factory.make_VLAN(vid=456, fabric=vlan123.fabric) | ||
221 | 110 | factory.make_Subnet(cidr="10.10.10.0/24", vlan=vlan123) | ||
222 | 111 | factory.make_Subnet(cidr="10.10.20.0/24", vlan=vlan456) | ||
223 | 112 | data = FakeCommissioningData() | ||
224 | 113 | data_eth0 = data.create_physical_network( | ||
225 | 114 | "eth0", | ||
226 | 115 | mac_address="11:11:11:11:11:11", | ||
227 | 116 | ) | ||
228 | 117 | data_eth0.state = "up" | ||
229 | 118 | vlan_network123 = data.create_vlan_network( | ||
230 | 119 | "eth0.123", parent=data_eth0, vid=123 | ||
231 | 120 | ) | ||
232 | 121 | vlan_network123.addresses = [LXDAddress("10.10.10.10", 24)] | ||
233 | 122 | vlan_network456 = data.create_vlan_network( | ||
234 | 123 | "eth0.456", parent=data_eth0, vid=456 | ||
235 | 124 | ) | ||
236 | 125 | vlan_network456.addresses = [LXDAddress("10.10.20.10", 24)] | ||
237 | 126 | self.update_interfaces(node, data) | ||
238 | 127 | eth0 = PhysicalInterface.objects.get( | ||
239 | 128 | name="eth0", node_config=node.current_config | ||
240 | 129 | ) | ||
241 | 130 | eth0_vlan123 = Interface.objects.get( | ||
242 | 131 | name="eth0.123", node_config=node.current_config | ||
243 | 132 | ) | ||
244 | 133 | eth0_vlan456 = Interface.objects.get( | ||
245 | 134 | name="eth0.456", node_config=node.current_config | ||
246 | 135 | ) | ||
247 | 136 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan123.type) | ||
248 | 137 | self.assertEqual(123, eth0_vlan123.vlan.vid) | ||
249 | 138 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan456.type) | ||
250 | 139 | self.assertEqual(456, eth0_vlan456.vlan.vid) | ||
251 | 140 | self.assertEqual( | ||
252 | 141 | eth0_vlan123.vlan.fabric_id, eth0_vlan456.vlan.fabric_id | ||
253 | 142 | ) | ||
254 | 143 | self.assertIsNotNone(eth0.vlan_id) | ||
255 | 144 | self.assertNotIn( | ||
256 | 145 | eth0.vlan_id, [eth0_vlan456.vlan_id, eth0_vlan123.vlan_id] | ||
257 | 146 | ) | ||
258 | 147 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan123.vlan.fabric_id) | ||
259 | 148 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan456.vlan.fabric_id) | ||
260 | 149 | |||
261 | 150 | def test_vlan_interfaces_with_new_known_link_deployed_machine(self): | ||
262 | 151 | node = factory.make_Machine(status=NODE_STATUS.DEPLOYED) | ||
263 | 152 | vlan456 = factory.make_VLAN(vid=456) | ||
264 | 153 | factory.make_Subnet(cidr="10.10.20.0/24", vlan=vlan456) | ||
265 | 154 | data = FakeCommissioningData() | ||
266 | 155 | data_eth0 = data.create_physical_network( | ||
267 | 156 | "eth0", | ||
268 | 157 | mac_address="11:11:11:11:11:11", | ||
269 | 158 | ) | ||
270 | 159 | data_eth0.state = "up" | ||
271 | 160 | vlan_network123 = data.create_vlan_network( | ||
272 | 161 | "eth0.123", parent=data_eth0, vid=123 | ||
273 | 162 | ) | ||
274 | 163 | vlan_network123.addresses = [LXDAddress("10.10.10.10", 24)] | ||
275 | 164 | vlan_network456 = data.create_vlan_network( | ||
276 | 165 | "eth0.456", parent=data_eth0, vid=456 | ||
277 | 166 | ) | ||
278 | 167 | vlan_network456.addresses = [LXDAddress("10.10.20.10", 24)] | ||
279 | 168 | self.update_interfaces(node, data) | ||
280 | 169 | eth0 = PhysicalInterface.objects.get( | ||
281 | 170 | name="eth0", node_config=node.current_config | ||
282 | 171 | ) | ||
283 | 172 | eth0_vlan123 = Interface.objects.get( | ||
284 | 173 | name="eth0.123", node_config=node.current_config | ||
285 | 174 | ) | ||
286 | 175 | eth0_vlan456 = Interface.objects.get( | ||
287 | 176 | name="eth0.456", node_config=node.current_config | ||
288 | 177 | ) | ||
289 | 178 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan123.type) | ||
290 | 179 | self.assertEqual(123, eth0_vlan123.vlan.vid) | ||
291 | 180 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan456.type) | ||
292 | 181 | self.assertEqual(456, eth0_vlan456.vlan.vid) | ||
293 | 182 | self.assertEqual( | ||
294 | 183 | eth0_vlan123.vlan.fabric_id, eth0_vlan456.vlan.fabric_id | ||
295 | 184 | ) | ||
296 | 185 | self.assertIsNotNone(eth0.vlan_id) | ||
297 | 186 | self.assertNotIn( | ||
298 | 187 | eth0.vlan_id, [eth0_vlan456.vlan_id, eth0_vlan123.vlan_id] | ||
299 | 188 | ) | ||
300 | 189 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan123.vlan.fabric_id) | ||
301 | 190 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan456.vlan.fabric_id) | ||
302 | 191 | |||
303 | 192 | def test_vlan_interfaces_with_new_unknown_link_deployed_machine(self): | ||
304 | 193 | node = factory.make_Machine(status=NODE_STATUS.DEPLOYED) | ||
305 | 194 | vlan123 = factory.make_VLAN(vid=123) | ||
306 | 195 | factory.make_Subnet(cidr="10.10.10.0/24", vlan=vlan123) | ||
307 | 196 | data = FakeCommissioningData() | ||
308 | 197 | data_eth0 = data.create_physical_network( | ||
309 | 198 | "eth0", | ||
310 | 199 | mac_address="11:11:11:11:11:11", | ||
311 | 200 | ) | ||
312 | 201 | data_eth0.state = "up" | ||
313 | 202 | vlan_network123 = data.create_vlan_network( | ||
314 | 203 | "eth0.123", parent=data_eth0, vid=123 | ||
315 | 204 | ) | ||
316 | 205 | vlan_network123.addresses = [LXDAddress("10.10.10.10", 24)] | ||
317 | 206 | vlan_network456 = data.create_vlan_network( | ||
318 | 207 | "eth0.456", parent=data_eth0, vid=456 | ||
319 | 208 | ) | ||
320 | 209 | vlan_network456.addresses = [LXDAddress("10.10.20.10", 24)] | ||
321 | 210 | self.update_interfaces(node, data) | ||
322 | 211 | eth0 = PhysicalInterface.objects.get( | ||
323 | 212 | name="eth0", node_config=node.current_config | ||
324 | 213 | ) | ||
325 | 214 | eth0_vlan123 = Interface.objects.get( | ||
326 | 215 | name="eth0.123", node_config=node.current_config | ||
327 | 216 | ) | ||
328 | 217 | eth0_vlan456 = Interface.objects.get( | ||
329 | 218 | name="eth0.456", node_config=node.current_config | ||
330 | 219 | ) | ||
331 | 220 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan123.type) | ||
332 | 221 | self.assertEqual(123, eth0_vlan123.vlan.vid) | ||
333 | 222 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan456.type) | ||
334 | 223 | self.assertEqual(456, eth0_vlan456.vlan.vid) | ||
335 | 224 | self.assertEqual( | ||
336 | 225 | eth0_vlan123.vlan.fabric_id, eth0_vlan456.vlan.fabric_id | ||
337 | 226 | ) | ||
338 | 227 | self.assertIsNotNone(eth0.vlan_id) | ||
339 | 228 | self.assertNotIn( | ||
340 | 229 | eth0.vlan_id, [eth0_vlan456.vlan_id, eth0_vlan123.vlan_id] | ||
341 | 230 | ) | ||
342 | 231 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan123.vlan.fabric_id) | ||
343 | 232 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan456.vlan.fabric_id) | ||
344 | 233 | |||
345 | 234 | def test_vlan_interfaces_with_unknown_link_deployed_machine(self): | ||
346 | 235 | node = factory.make_Machine(status=NODE_STATUS.DEPLOYED) | ||
347 | 236 | data = FakeCommissioningData() | ||
348 | 237 | data_eth0 = data.create_physical_network( | ||
349 | 238 | "eth0", | ||
350 | 239 | mac_address="11:11:11:11:11:11", | ||
351 | 240 | ) | ||
352 | 241 | data_eth0.state = "up" | ||
353 | 242 | vlan_network123 = data.create_vlan_network( | ||
354 | 243 | "eth0.123", parent=data_eth0, vid=123 | ||
355 | 244 | ) | ||
356 | 245 | vlan_network123.addresses = [LXDAddress("10.10.10.10", 24)] | ||
357 | 246 | vlan_network456 = data.create_vlan_network( | ||
358 | 247 | "eth0.456", parent=data_eth0, vid=456 | ||
359 | 248 | ) | ||
360 | 249 | vlan_network456.addresses = [LXDAddress("10.10.20.10", 24)] | ||
361 | 250 | self.update_interfaces(node, data) | ||
362 | 251 | eth0 = PhysicalInterface.objects.get( | ||
363 | 252 | name="eth0", node_config=node.current_config | ||
364 | 253 | ) | ||
365 | 254 | eth0_vlan123 = Interface.objects.get( | ||
366 | 255 | name="eth0.123", node_config=node.current_config | ||
367 | 256 | ) | ||
368 | 257 | eth0_vlan456 = Interface.objects.get( | ||
369 | 258 | name="eth0.456", node_config=node.current_config | ||
370 | 259 | ) | ||
371 | 260 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan123.type) | ||
372 | 261 | self.assertEqual(123, eth0_vlan123.vlan.vid) | ||
373 | 262 | self.assertEqual(INTERFACE_TYPE.VLAN, eth0_vlan456.type) | ||
374 | 263 | self.assertEqual(456, eth0_vlan456.vlan.vid) | ||
375 | 264 | self.assertEqual( | ||
376 | 265 | eth0_vlan123.vlan.fabric_id, eth0_vlan456.vlan.fabric_id | ||
377 | 266 | ) | ||
378 | 267 | self.assertIsNotNone(eth0.vlan_id) | ||
379 | 268 | self.assertNotIn( | ||
380 | 269 | eth0.vlan_id, [eth0_vlan456.vlan_id, eth0_vlan123.vlan_id] | ||
381 | 270 | ) | ||
382 | 271 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan123.vlan.fabric_id) | ||
383 | 272 | self.assertEqual(eth0.vlan.fabric_id, eth0_vlan456.vlan.fabric_id) | ||
384 | 273 | |||
385 | 104 | def test_dont_create_default_vlan_if_disabled(self): | 274 | def test_dont_create_default_vlan_if_disabled(self): |
386 | 105 | Config.objects.set_config(name="auto_vlan_creation", value=False) | 275 | Config.objects.set_config(name="auto_vlan_creation", value=False) |
387 | 106 | node = factory.make_Machine(status=NODE_STATUS.NEW) | 276 | node = factory.make_Machine(status=NODE_STATUS.NEW) |
388 | @@ -138,9 +308,7 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
389 | 138 | self.assertEqual("11:11:11:11:11:11", eth0.mac_address) | 308 | self.assertEqual("11:11:11:11:11:11", eth0.mac_address) |
390 | 139 | self.assertTrue(eth0.enabled) | 309 | self.assertTrue(eth0.enabled) |
391 | 140 | self.assertTrue(eth0.link_connected) | 310 | self.assertTrue(eth0.link_connected) |
395 | 141 | self.assertEqual( | 311 | self.assertIsNone(eth0.vlan) |
393 | 142 | Fabric.objects.get_default_fabric().get_default_vlan(), eth0.vlan | ||
394 | 143 | ) | ||
396 | 144 | self.assertEqual([], list(eth0.parents.all())) | 312 | self.assertEqual([], list(eth0.parents.all())) |
397 | 145 | eth1 = PhysicalInterface.objects.get( | 313 | eth1 = PhysicalInterface.objects.get( |
398 | 146 | name="eth1", node_config=controller.current_config | 314 | name="eth1", node_config=controller.current_config |
399 | @@ -547,10 +715,9 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
400 | 547 | name="eth0", node_config=controller.current_config | 715 | name="eth0", node_config=controller.current_config |
401 | 548 | ) | 716 | ) |
402 | 549 | 717 | ||
403 | 550 | default_vlan = Fabric.objects.get_default_fabric().get_default_vlan() | ||
404 | 551 | self.assertEqual(INTERFACE_TYPE.PHYSICAL, eth0.type) | 718 | self.assertEqual(INTERFACE_TYPE.PHYSICAL, eth0.type) |
405 | 552 | self.assertEqual("11:11:11:11:11:11", eth0.mac_address) | 719 | self.assertEqual("11:11:11:11:11:11", eth0.mac_address) |
407 | 553 | self.assertEqual(default_vlan, eth0.vlan) | 720 | self.assertIsNone(eth0.vlan) |
408 | 554 | self.assertTrue(eth0.enabled) | 721 | self.assertTrue(eth0.enabled) |
409 | 555 | 722 | ||
410 | 556 | eth0_addresses = list(eth0.ip_addresses.all()) | 723 | eth0_addresses = list(eth0.ip_addresses.all()) |
411 | @@ -1103,13 +1270,13 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
412 | 1103 | maaslog.method_calls, | 1270 | maaslog.method_calls, |
413 | 1104 | [ | 1271 | [ |
414 | 1105 | call.error( | 1272 | call.error( |
415 | 1106 | f"Interface 'eth0' on controller '{controller.hostname}' " | ||
416 | 1107 | f"is not on the same fabric as VLAN interface '{vlan_interface.name}'." | ||
417 | 1108 | ), | ||
418 | 1109 | call.error( | ||
419 | 1110 | f"VLAN interface '{vlan_interface.name}' reports VLAN {vid_on_fabric} " | 1273 | f"VLAN interface '{vlan_interface.name}' reports VLAN {vid_on_fabric} " |
420 | 1111 | f"but links are on VLAN {other_vlan.vid}" | 1274 | f"but links are on VLAN {other_vlan.vid}" |
421 | 1112 | ), | 1275 | ), |
422 | 1276 | call.error( | ||
423 | 1277 | f"Interface 'eth0' on controller '{controller.hostname}' " | ||
424 | 1278 | f"is not on the same fabric as VLAN interface '{vlan_interface.name}'." | ||
425 | 1279 | ), | ||
426 | 1113 | ] | 1280 | ] |
427 | 1114 | * passes, | 1281 | * passes, |
428 | 1115 | ) | 1282 | ) |
429 | @@ -1270,13 +1437,13 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
430 | 1270 | maaslog.method_calls, | 1437 | maaslog.method_calls, |
431 | 1271 | [ | 1438 | [ |
432 | 1272 | call.error( | 1439 | call.error( |
433 | 1273 | f"Interface 'eth0' on controller '{controller.hostname}' " | ||
434 | 1274 | f"is not on the same fabric as VLAN interface '{vlan_interface.name}'." | ||
435 | 1275 | ), | ||
436 | 1276 | call.error( | ||
437 | 1277 | f"VLAN interface '{vlan_interface.name}' reports VLAN {other_vlan.vid} " | 1440 | f"VLAN interface '{vlan_interface.name}' reports VLAN {other_vlan.vid} " |
438 | 1278 | f"but links are on VLAN {new_vlan.vid}" | 1441 | f"but links are on VLAN {new_vlan.vid}" |
439 | 1279 | ), | 1442 | ), |
440 | 1443 | call.error( | ||
441 | 1444 | f"Interface 'eth0' on controller '{controller.hostname}' " | ||
442 | 1445 | f"is not on the same fabric as VLAN interface '{vlan_interface.name}'." | ||
443 | 1446 | ), | ||
444 | 1280 | ] | 1447 | ] |
445 | 1281 | * passes, | 1448 | * passes, |
446 | 1282 | ) | 1449 | ) |
447 | @@ -2224,17 +2391,11 @@ class TestUpdateInterfaces(MAASServerTestCase, UpdateInterfacesMixin): | |||
448 | 2224 | 2391 | ||
449 | 2225 | self.update_interfaces(controller, data) | 2392 | self.update_interfaces(controller, data) |
450 | 2226 | 2393 | ||
451 | 2227 | eth0 = get_one( | ||
452 | 2228 | PhysicalInterface.objects.filter( | ||
453 | 2229 | node_config=controller.current_config, name="eth0" | ||
454 | 2230 | ) | ||
455 | 2231 | ) | ||
456 | 2232 | eth1 = get_one( | 2394 | eth1 = get_one( |
457 | 2233 | PhysicalInterface.objects.filter( | 2395 | PhysicalInterface.objects.filter( |
458 | 2234 | node_config=controller.current_config, name="eth1" | 2396 | node_config=controller.current_config, name="eth1" |
459 | 2235 | ) | 2397 | ) |
460 | 2236 | ) | 2398 | ) |
461 | 2237 | self.assertIsNotNone(eth0.vlan) | ||
462 | 2238 | self.assertIsNone(eth1.vlan) | 2399 | self.assertIsNone(eth1.vlan) |
463 | 2239 | 2400 | ||
464 | 2240 | def test_subnet_seen_on_second_controller_does_not_create_fabric(self): | 2401 | def test_subnet_seen_on_second_controller_does_not_create_fabric(self): |
Self-approve backport