Merge lp:~mpontillo/maas/allow-physical-interfaces-on-vlans-with-known-tag--bug-1678339 into lp:~maas-committers/maas/trunk

Proposed by Mike Pontillo
Status: Merged
Approved by: Mike Pontillo
Approved revision: no longer in the source branch.
Merged at revision: 6087
Proposed branch: lp:~mpontillo/maas/allow-physical-interfaces-on-vlans-with-known-tag--bug-1678339
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 764 lines (+103/-161)
4 files modified
src/maasserver/api/tests/test_interfaces.py (+13/-22)
src/maasserver/forms/interface.py (+2/-21)
src/maasserver/forms/tests/test_interface.py (+65/-94)
src/maasserver/websockets/handlers/tests/test_machine.py (+23/-24)
To merge this branch: bzr merge lp:~mpontillo/maas/allow-physical-interfaces-on-vlans-with-known-tag--bug-1678339
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+325774@code.launchpad.net

Commit message

Allow physical (and bond) interfaces to be placed on VLANs with a known 802.1q tag.

Description of the change

This was preventing users with moderately complex networks from using the MAAS 2.2 release with DHCP relay, since nodes on the relay VLANs by definition are not "untagged" from the rack controller's point of view.

(The bug also occurs in situations without DHCP relay, as the linked bug description shows.)

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/tests/test_interfaces.py'
2--- src/maasserver/api/tests/test_interfaces.py 2017-04-20 22:41:52 +0000
3+++ src/maasserver/api/tests/test_interfaces.py 2017-06-15 21:08:15 +0000
4@@ -79,14 +79,14 @@
5 def make_complex_interface(node, name=None):
6 """Makes interface with parents and children."""
7 fabric = factory.make_Fabric()
8- untagged = fabric.get_default_vlan()
9+ vlan_5 = factory.make_VLAN(vid=5, fabric=fabric)
10 nic_0 = factory.make_Interface(
11- INTERFACE_TYPE.PHYSICAL, vlan=untagged, node=node)
12+ INTERFACE_TYPE.PHYSICAL, vlan=vlan_5, node=node)
13 nic_1 = factory.make_Interface(
14- INTERFACE_TYPE.PHYSICAL, vlan=untagged, node=node)
15+ INTERFACE_TYPE.PHYSICAL, vlan=vlan_5, node=node)
16 parents = [nic_0, nic_1]
17 bond_interface = factory.make_Interface(
18- INTERFACE_TYPE.BOND, mac_address=nic_0.mac_address, vlan=untagged,
19+ INTERFACE_TYPE.BOND, mac_address=nic_0.mac_address, vlan=vlan_5,
20 parents=parents, name=name)
21 vlan_10 = factory.make_VLAN(vid=10, fabric=fabric)
22 vlan_nic_10 = factory.make_Interface(
23@@ -179,8 +179,7 @@
24 node = factory.make_Node(status=status)
25 mac = factory.make_mac_address()
26 name = factory.make_name("eth")
27- fabric = factory.make_Fabric()
28- vlan = fabric.get_default_vlan()
29+ vlan = factory.make_VLAN()
30 tags = [
31 factory.make_name("tag")
32 for _ in range(3)
33@@ -213,8 +212,7 @@
34 owner=self.user, parent=parent)
35 mac = factory.make_mac_address()
36 name = factory.make_name("eth")
37- fabric = factory.make_Fabric()
38- vlan = fabric.get_default_vlan()
39+ vlan = factory.make_VLAN()
40 tags = [
41 factory.make_name("tag")
42 for _ in range(3)
43@@ -247,8 +245,7 @@
44 node = factory.make_Node(status=status)
45 mac = factory.make_mac_address()
46 name = factory.make_name("eth")
47- fabric = factory.make_Fabric()
48- vlan = fabric.get_default_vlan()
49+ vlan = factory.make_VLAN()
50 tags = [
51 factory.make_name("tag")
52 for _ in range(3)
53@@ -327,8 +324,7 @@
54 interface_on_other_node = factory.make_Interface(
55 INTERFACE_TYPE.PHYSICAL)
56 name = factory.make_name("eth")
57- fabric = factory.make_Fabric()
58- vlan = fabric.get_default_vlan()
59+ vlan = factory.make_VLAN()
60 uri = get_interfaces_uri(node)
61 response = self.client.post(uri, {
62 "op": "create_physical",
63@@ -348,8 +344,7 @@
64 self.become_admin()
65 for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
66 node = factory.make_Node(status=status)
67- fabric = factory.make_Fabric()
68- vlan = fabric.get_default_vlan()
69+ vlan = factory.make_VLAN()
70 parent_1_iface = factory.make_Interface(
71 INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=node)
72 parent_2_iface = factory.make_Interface(
73@@ -438,7 +433,7 @@
74 self.assertEqual(
75 http.client.CONFLICT, response.status_code, response.content)
76
77- def test_create_bond_requires_name_and_parents(self):
78+ def test_create_bond_requires_name_vlan_and_parents(self):
79 self.become_admin()
80 node = factory.make_Node(status=NODE_STATUS.READY)
81 uri = get_interfaces_uri(node)
82@@ -941,8 +936,7 @@
83 interface = factory.make_Interface(
84 INTERFACE_TYPE.PHYSICAL, node=node)
85 new_name = factory.make_name("name")
86- new_fabric = factory.make_Fabric()
87- new_vlan = new_fabric.get_default_vlan()
88+ new_vlan = factory.make_VLAN()
89 uri = get_interface_uri(interface)
90 response = self.client.put(uri, {
91 "name": new_name,
92@@ -961,8 +955,7 @@
93 interface = factory.make_Interface(
94 INTERFACE_TYPE.PHYSICAL, node=device)
95 new_name = factory.make_name("name")
96- new_fabric = factory.make_Fabric()
97- new_vlan = new_fabric.get_default_vlan()
98+ new_vlan = factory.make_VLAN()
99 uri = get_interface_uri(interface)
100 response = self.client.put(uri, {
101 "name": new_name,
102@@ -996,12 +989,10 @@
103 bond, [nic_0, nic_1], [vlan_10, vlan_11] = make_complex_interface(
104 node)
105 physical_interface = factory.make_Interface(
106- INTERFACE_TYPE.PHYSICAL, node=node)
107- new_vlan = factory.make_VLAN(fabric=physical_interface.vlan.fabric)
108+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=nic_0.vlan)
109 uri = get_interface_uri(vlan_10)
110 response = self.client.put(uri, {
111 "parent": physical_interface.id,
112- "vlan": new_vlan.id,
113 })
114 self.assertEqual(
115 http.client.OK, response.status_code, response.content)
116
117=== modified file 'src/maasserver/forms/interface.py'
118--- src/maasserver/forms/interface.py 2017-04-05 22:50:03 +0000
119+++ src/maasserver/forms/interface.py 2017-06-15 21:08:15 +0000
120@@ -252,18 +252,6 @@
121 if len(parents) > 0:
122 raise ValidationError("A physical interface cannot have parents.")
123
124- def clean_vlan(self):
125- new_vlan = self.cleaned_data.get('vlan')
126- if new_vlan and new_vlan.fabric.get_default_vlan() != new_vlan:
127- # A device's physical interface can be connected to a tagged VLAN.
128- # This is because a container or VM could be bridged on the machine
129- # to a tagged VLAN interface. See lp:1572070 for details.
130- if self.node.node_type != NODE_TYPE.DEVICE:
131- raise ValidationError(
132- "A physical interface can only belong to an "
133- "untagged VLAN.")
134- return new_vlan
135-
136 def clean(self):
137 cleaned_data = super(PhysicalInterfaceForm, self).clean()
138 new_name = cleaned_data.get('name')
139@@ -313,7 +301,7 @@
140 not created and new_vlan is None and vlan_was_set):
141 raise ValidationError(
142 "A VLAN interface must be connected to a tagged VLAN.")
143- if new_vlan and new_vlan.fabric.get_default_vlan() == new_vlan:
144+ if new_vlan and new_vlan.vid == 0:
145 raise ValidationError(
146 "A VLAN interface can only belong to a tagged VLAN.")
147 return new_vlan
148@@ -455,16 +443,9 @@
149 'name',
150 )
151
152- def clean_vlan(self):
153- new_vlan = self.cleaned_data.get('vlan')
154- if new_vlan and new_vlan.fabric.get_default_vlan() != new_vlan:
155- raise ValidationError(
156- "A bond interface can only belong to an untagged VLAN.")
157- return new_vlan
158-
159 def clean(self):
160 cleaned_data = super().clean()
161- if self.fields_ok(['vlan', 'parents']):
162+ if self.fields_ok(['parents']):
163 parents = self.cleaned_data.get('parents')
164 # Set the mac_address if its missing and the interface is being
165 # created.
166
167=== modified file 'src/maasserver/forms/tests/test_interface.py'
168--- src/maasserver/forms/tests/test_interface.py 2017-04-05 23:39:23 +0000
169+++ src/maasserver/forms/tests/test_interface.py 2017-06-15 21:08:15 +0000
170@@ -30,7 +30,6 @@
171 from maasserver.testing.factory import factory
172 from maasserver.testing.testcase import MAASServerTestCase
173 from maasserver.utils.forms import compose_invalid_choice_text
174-from maasserver.utils.orm import reload_object
175 from testtools import ExpectedException
176 from testtools.matchers import MatchesStructure
177
178@@ -133,8 +132,7 @@
179 node = factory.make_Node()
180 mac_address = factory.make_mac_address()
181 interface_name = 'eth0'
182- fabric = factory.make_Fabric()
183- vlan = fabric.get_default_vlan()
184+ vlan = factory.make_VLAN()
185 tags = [
186 factory.make_name("tag")
187 for _ in range(3)
188@@ -211,8 +209,7 @@
189 node = factory.make_Node()
190 mac_address = factory.make_mac_address()
191 interface_name = 'eth0'
192- fabric = factory.make_Fabric()
193- vlan = fabric.get_default_vlan()
194+ vlan = factory.make_VLAN()
195 tags = [
196 factory.make_name("tag")
197 for _ in range(3)
198@@ -232,8 +229,7 @@
199
200 def test__requires_mac_address(self):
201 interface_name = 'eth0'
202- fabric = factory.make_Fabric()
203- vlan = fabric.get_default_vlan()
204+ vlan = factory.make_VLAN()
205 form = PhysicalInterfaceForm(
206 node=factory.make_Node(),
207 data={
208@@ -248,9 +244,7 @@
209 form.errors['mac_address'][0])
210
211 def test_rejects_interface_with_duplicate_name(self):
212- fabric = factory.make_Fabric()
213- vlan = fabric.get_default_vlan()
214- interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
215+ interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
216 mac_address = factory.make_mac_address()
217 form = PhysicalInterfaceForm(
218 node=interface.node,
219@@ -266,26 +260,6 @@
220 "already has an interface named '%s'." % interface.name,
221 form.errors['name'][0])
222
223- def test_rejects_interface_on_tagged_vlan(self):
224- fabric = factory.make_Fabric()
225- interface = factory.make_Interface(
226- INTERFACE_TYPE.PHYSICAL, vlan=fabric.get_default_vlan())
227- vlan = factory.make_VLAN(fabric=fabric)
228- mac_address = factory.make_mac_address()
229- form = PhysicalInterfaceForm(
230- node=interface.node,
231- data={
232- 'name': factory.make_name("eth"),
233- 'mac_address': mac_address,
234- 'vlan': vlan.id,
235- })
236- self.assertFalse(form.is_valid(), dict(form.errors))
237- self.assertItemsEqual(
238- ['vlan'], form.errors.keys(), form.errors)
239- self.assertIn(
240- "A physical interface can only belong to an untagged VLAN.",
241- form.errors['vlan'][0])
242-
243 def test_allows_interface_on_tagged_vlan_for_device(self):
244 device = factory.make_Device()
245 fabric = factory.make_Fabric()
246@@ -307,8 +281,7 @@
247
248 def test__rejects_parents(self):
249 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
250- fabric = factory.make_Fabric()
251- vlan = fabric.get_default_vlan()
252+ vlan = factory.make_VLAN()
253 form = PhysicalInterfaceForm(
254 node=parent.node,
255 data={
256@@ -328,8 +301,7 @@
257 interface = factory.make_Interface(
258 INTERFACE_TYPE.PHYSICAL, name='eth0')
259 new_name = 'eth1'
260- new_fabric = factory.make_Fabric()
261- new_vlan = new_fabric.get_default_vlan()
262+ new_vlan = factory.make_VLAN(vid=33)
263 form = PhysicalInterfaceForm(
264 instance=interface,
265 data={
266@@ -390,8 +362,7 @@
267 node = factory.make_Node()
268 mac_address = factory.make_mac_address()
269 interface_name = 'eth0'
270- fabric = factory.make_Fabric()
271- vlan = fabric.get_default_vlan()
272+ vlan = factory.make_VLAN()
273 tags = [
274 factory.make_name("tag")
275 for _ in range(3)
276@@ -430,8 +401,7 @@
277 "autoconf": autoconf,
278 }
279 new_name = 'eth1'
280- new_fabric = factory.make_Fabric()
281- new_vlan = new_fabric.get_default_vlan()
282+ new_vlan = factory.make_VLAN(vid=33)
283 form = PhysicalInterfaceForm(
284 instance=interface,
285 data={
286@@ -503,8 +473,8 @@
287 class VLANInterfaceFormTest(MAASServerTestCase):
288
289 def test__creates_vlan_interface(self):
290- parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
291- vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
292+ vlan = factory.make_VLAN(vid=10)
293+ parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
294 form = VLANInterfaceForm(
295 node=parent.node,
296 data={
297@@ -521,8 +491,8 @@
298 self.assertItemsEqual([parent], interface.parents.all())
299
300 def test__create_ensures_link_up(self):
301- parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
302- vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
303+ vlan = factory.make_VLAN(vid=10)
304+ parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
305 form = VLANInterfaceForm(
306 node=parent.node,
307 data={
308@@ -549,10 +519,13 @@
309 form.errors['vlan'][0])
310
311 def test_rejects_interface_with_duplicate_name(self):
312- parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
313- vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
314+ vlan = factory.make_VLAN(vid=10)
315+ parent = factory.make_Interface(
316+ INTERFACE_TYPE.PHYSICAL,
317+ vlan=vlan)
318 interface = factory.make_Interface(
319- INTERFACE_TYPE.VLAN, vlan=vlan, parents=[parent])
320+ INTERFACE_TYPE.VLAN,
321+ vlan=vlan, parents=[parent])
322 form = VLANInterfaceForm(
323 node=parent.node,
324 data={
325@@ -597,14 +570,13 @@
326
327 def test__rejects_vlan_parent(self):
328 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
329- vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
330 vlan_parent = factory.make_Interface(
331- INTERFACE_TYPE.VLAN, vlan=vlan, parents=[parent])
332- other_vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=11)
333+ INTERFACE_TYPE.VLAN, parents=[parent])
334+ vlan = factory.make_VLAN(vid=10)
335 form = VLANInterfaceForm(
336 node=parent.node,
337 data={
338- 'vlan': other_vlan.id,
339+ 'vlan': vlan.id,
340 'parents': [vlan_parent.id],
341 })
342 self.assertFalse(form.is_valid(), dict(form.errors))
343@@ -646,8 +618,8 @@
344
345 def test__rejects_parent_on_bond(self):
346 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
347- bond = factory.make_Interface(INTERFACE_TYPE.BOND, parents=[parent])
348- vlan = factory.make_VLAN(fabric=bond.vlan.fabric, vid=10)
349+ factory.make_Interface(INTERFACE_TYPE.BOND, parents=[parent])
350+ vlan = factory.make_VLAN(vid=10)
351 form = VLANInterfaceForm(
352 node=parent.node,
353 data={
354@@ -682,7 +654,7 @@
355 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
356 interface = factory.make_Interface(
357 INTERFACE_TYPE.VLAN, parents=[parent])
358- new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric, vid=33)
359+ new_vlan = factory.make_VLAN(vid=33)
360 form = VLANInterfaceForm(
361 instance=interface,
362 data={
363@@ -701,15 +673,17 @@
364 class BondInterfaceFormTest(MAASServerTestCase):
365
366 def test__error_with_invalid_bond_mode(self):
367- parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
368+ vlan = factory.make_VLAN(vid=10)
369+ parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
370 parent2 = factory.make_Interface(
371- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
372+ INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=vlan)
373 interface_name = factory.make_name()
374 bond_mode = factory.make_name("bond_mode")
375 form = BondInterfaceForm(
376 node=parent1.node,
377 data={
378 'name': interface_name,
379+ 'vlan': vlan.id,
380 'parents': [parent1.id, parent2.id],
381 'bond_mode': bond_mode,
382 })
383@@ -721,14 +695,16 @@
384 }, form.errors)
385
386 def test__creates_bond_interface(self):
387- parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
388+ vlan = factory.make_VLAN(vid=10)
389+ parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
390 parent2 = factory.make_Interface(
391- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
392+ INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=vlan)
393 interface_name = factory.make_name()
394 form = BondInterfaceForm(
395 node=parent1.node,
396 data={
397 'name': interface_name,
398+ 'vlan': vlan.id,
399 'parents': [parent1.id, parent2.id],
400 })
401 self.assertTrue(form.is_valid(), dict(form.errors))
402@@ -743,16 +719,18 @@
403 self.assertItemsEqual([parent1, parent2], interface.parents.all())
404
405 def test__create_removes_parent_links_and_sets_link_up_on_bond(self):
406- parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
407+ vlan = factory.make_VLAN(vid=10)
408+ parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
409 parent1.ensure_link_up()
410 parent2 = factory.make_Interface(
411- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
412+ INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=vlan)
413 parent2.ensure_link_up()
414 interface_name = factory.make_name()
415 form = BondInterfaceForm(
416 node=parent1.node,
417 data={
418 'name': interface_name,
419+ 'vlan': vlan.id,
420 'parents': [parent1.id, parent2.id],
421 })
422 self.assertTrue(form.is_valid(), dict(form.errors))
423@@ -769,14 +747,16 @@
424 interface.ip_addresses.filter(alloc_type=IPADDRESS_TYPE.STICKY))
425
426 def test__creates_bond_interface_with_parent_mac_address(self):
427- parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
428+ vlan = factory.make_VLAN(vid=10)
429+ parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
430 parent2 = factory.make_Interface(
431- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
432+ INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=vlan)
433 interface_name = factory.make_name()
434 form = BondInterfaceForm(
435 node=parent1.node,
436 data={
437 'name': interface_name,
438+ 'vlan': vlan.id,
439 'parents': [parent1.id, parent2.id],
440 'mac_address': parent1.mac_address,
441 })
442@@ -790,14 +770,16 @@
443 self.assertItemsEqual([parent1, parent2], interface.parents.all())
444
445 def test__creates_bond_interface_with_default_bond_params(self):
446- parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
447+ vlan = factory.make_VLAN(vid=10)
448+ parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
449 parent2 = factory.make_Interface(
450- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
451+ INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=vlan)
452 interface_name = factory.make_name()
453 form = BondInterfaceForm(
454 node=parent1.node,
455 data={
456 'name': interface_name,
457+ 'vlan': vlan.id,
458 'parents': [parent1.id, parent2.id],
459 })
460 self.assertTrue(form.is_valid(), dict(form.errors))
461@@ -812,9 +794,10 @@
462 }, interface.params)
463
464 def test__creates_bond_interface_with_bond_params(self):
465- parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
466+ vlan = factory.make_VLAN(vid=10)
467+ parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
468 parent2 = factory.make_Interface(
469- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
470+ INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=vlan)
471 interface_name = factory.make_name()
472 bond_mode = factory.pick_choice(BOND_MODE_CHOICES)
473 bond_miimon = random.randint(0, 1000)
474@@ -827,6 +810,7 @@
475 node=parent1.node,
476 data={
477 'name': interface_name,
478+ 'vlan': vlan.id,
479 'parents': [parent1.id, parent2.id],
480 'bond_mode': bond_mode,
481 'bond_miimon': bond_miimon,
482@@ -847,11 +831,13 @@
483 }, interface.params)
484
485 def test__rejects_no_parents(self):
486+ vlan = factory.make_VLAN(vid=10)
487 interface_name = factory.make_name()
488 form = BondInterfaceForm(
489 node=factory.make_Node(),
490 data={
491 'name': interface_name,
492+ 'vlan': vlan.id,
493 })
494 self.assertFalse(form.is_valid(), dict(form.errors))
495 self.assertItemsEqual(['parents', 'mac_address'], form.errors.keys())
496@@ -859,37 +845,21 @@
497 "A bond interface must have one or more parents.",
498 form.errors['parents'][0])
499
500- def test__rejects_when_vlan_not_untagged(self):
501- interface_name = factory.make_name()
502- parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
503- vlan = factory.make_VLAN(fabric=parent.vlan.fabric)
504- form = BondInterfaceForm(
505- node=parent.node,
506- data={
507- 'name': interface_name,
508- 'parents': [parent.id],
509- 'mac_address': parent.mac_address,
510- 'vlan': vlan.id,
511- })
512- self.assertFalse(form.is_valid(), dict(form.errors))
513- self.assertItemsEqual(['vlan'], form.errors.keys())
514- self.assertIn(
515- "A bond interface can only belong to an untagged VLAN.",
516- form.errors['vlan'][0])
517-
518 def test__rejects_when_parents_already_have_children(self):
519 node = factory.make_Node()
520 parent1 = factory.make_Interface(
521 INTERFACE_TYPE.PHYSICAL, node=node, name="eth0")
522 factory.make_Interface(INTERFACE_TYPE.VLAN, parents=[parent1])
523 parent2 = factory.make_Interface(
524- INTERFACE_TYPE.PHYSICAL, node=node, name="eth1", vlan=parent1.vlan)
525+ INTERFACE_TYPE.PHYSICAL, node=node, name="eth1")
526 factory.make_Interface(INTERFACE_TYPE.VLAN, parents=[parent2])
527+ vlan = factory.make_VLAN(vid=10)
528 interface_name = factory.make_name()
529 form = BondInterfaceForm(
530 node=node,
531 data={
532 'name': interface_name,
533+ 'vlan': vlan.id,
534 'parents': [parent1.id, parent2.id]
535 })
536 self.assertFalse(form.is_valid(), dict(form.errors))
537@@ -918,15 +888,14 @@
538 def test__edits_interface(self):
539 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
540 parent2 = factory.make_Interface(
541- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
542+ INTERFACE_TYPE.PHYSICAL, node=parent1.node)
543 interface = factory.make_Interface(
544 INTERFACE_TYPE.BOND,
545 parents=[parent1, parent2])
546- new_fabric = factory.make_Fabric()
547- new_vlan = new_fabric.get_default_vlan()
548+ new_vlan = factory.make_VLAN(vid=33)
549 new_name = factory.make_name()
550 new_parent = factory.make_Interface(
551- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
552+ INTERFACE_TYPE.PHYSICAL, node=parent1.node)
553 form = BondInterfaceForm(
554 instance=interface,
555 data={
556@@ -943,10 +912,6 @@
557 vlan=new_vlan, type=INTERFACE_TYPE.BOND))
558 self.assertItemsEqual(
559 [parent1, parent2, new_parent], interface.parents.all())
560- self.assertItemsEqual([new_vlan], set(
561- reload_object(parent).vlan
562- for parent in [parent1, parent2, new_parent]
563- ))
564
565 def test__edits_interface_allows_disconnected(self):
566 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
567@@ -1023,7 +988,7 @@
568 def test__edit_doesnt_overwrite_params(self):
569 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
570 parent2 = factory.make_Interface(
571- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
572+ INTERFACE_TYPE.PHYSICAL, node=parent1.node)
573 interface = factory.make_Interface(
574 INTERFACE_TYPE.BOND,
575 parents=[parent1, parent2])
576@@ -1043,10 +1008,12 @@
577 "bond_xmit_hash_policy": bond_xmit_hash_policy,
578 }
579 interface.save()
580+ new_vlan = factory.make_VLAN(vid=33)
581 new_name = factory.make_name()
582 form = BondInterfaceForm(
583 instance=interface,
584 data={
585+ 'vlan': new_vlan.id,
586 'name': new_name,
587 })
588 self.assertTrue(form.is_valid(), dict(form.errors))
589@@ -1063,7 +1030,7 @@
590 def test__edit_does_overwrite_params(self):
591 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
592 parent2 = factory.make_Interface(
593- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
594+ INTERFACE_TYPE.PHYSICAL, node=parent1.node)
595 interface = factory.make_Interface(
596 INTERFACE_TYPE.BOND,
597 parents=[parent1, parent2])
598@@ -1083,6 +1050,7 @@
599 "bond_xmit_hash_policy": bond_xmit_hash_policy,
600 }
601 interface.save()
602+ new_vlan = factory.make_VLAN(vid=33)
603 new_name = factory.make_name()
604 new_bond_mode = factory.pick_choice(BOND_MODE_CHOICES)
605 new_bond_miimon = random.randint(0, 1000)
606@@ -1094,6 +1062,7 @@
607 form = BondInterfaceForm(
608 instance=interface,
609 data={
610+ 'vlan': new_vlan.id,
611 'name': new_name,
612 'bond_mode': new_bond_mode,
613 'bond_miimon': new_bond_miimon,
614@@ -1116,7 +1085,7 @@
615 def test__edit_allows_zero_params(self):
616 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
617 parent2 = factory.make_Interface(
618- INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
619+ INTERFACE_TYPE.PHYSICAL, node=parent1.node)
620 interface = factory.make_Interface(
621 INTERFACE_TYPE.BOND,
622 parents=[parent1, parent2])
623@@ -1136,6 +1105,7 @@
624 "bond_xmit_hash_policy": bond_xmit_hash_policy,
625 }
626 interface.save()
627+ new_vlan = factory.make_VLAN(vid=33)
628 new_name = factory.make_name()
629 new_bond_mode = factory.pick_choice(BOND_MODE_CHOICES)
630 new_bond_miimon = 0
631@@ -1147,6 +1117,7 @@
632 form = BondInterfaceForm(
633 instance=interface,
634 data={
635+ 'vlan': new_vlan.id,
636 'name': new_name,
637 'bond_mode': new_bond_mode,
638 'bond_miimon': new_bond_miimon,
639
640=== modified file 'src/maasserver/websockets/handlers/tests/test_machine.py'
641--- src/maasserver/websockets/handlers/tests/test_machine.py 2017-04-20 08:58:42 +0000
642+++ src/maasserver/websockets/handlers/tests/test_machine.py 2017-06-15 21:08:15 +0000
643@@ -2079,8 +2079,7 @@
644 handler = MachineHandler(user, {})
645 name = factory.make_name("eth")
646 mac_address = factory.make_mac_address()
647- fabric = factory.make_Fabric()
648- vlan = fabric.get_default_vlan()
649+ vlan = factory.make_VLAN()
650 handler.create_physical({
651 "system_id": node.system_id,
652 "name": name,
653@@ -2097,8 +2096,7 @@
654 handler = MachineHandler(user, {})
655 name = factory.make_name("eth")
656 mac_address = factory.make_mac_address()
657- fabric = factory.make_Fabric()
658- vlan = fabric.get_default_vlan()
659+ vlan = factory.make_VLAN()
660 subnet = factory.make_Subnet(vlan=vlan)
661 handler.create_physical({
662 "system_id": node.system_id,
663@@ -2120,8 +2118,7 @@
664 handler = MachineHandler(user, {})
665 name = factory.make_name("eth")
666 mac_address = factory.make_mac_address()
667- fabric = factory.make_Fabric()
668- vlan = fabric.get_default_vlan()
669+ vlan = factory.make_VLAN()
670 handler.create_physical({
671 "system_id": node.system_id,
672 "name": name,
673@@ -2141,8 +2138,7 @@
674 handler = MachineHandler(user, {})
675 name = factory.make_name("eth")
676 mac_address = factory.make_mac_address()
677- fabric = factory.make_Fabric()
678- vlan = fabric.get_default_vlan()
679+ vlan = factory.make_VLAN()
680 subnet = factory.make_Subnet(vlan=vlan)
681 handler.create_physical({
682 "system_id": node.system_id,
683@@ -2162,12 +2158,13 @@
684 user = factory.make_admin()
685 node = factory.make_Node()
686 handler = MachineHandler(user, {})
687- interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
688- new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
689+ vlan = factory.make_VLAN()
690+ interface = factory.make_Interface(
691+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan)
692 handler.create_vlan({
693 "system_id": node.system_id,
694 "parent": interface.id,
695- "vlan": new_vlan.id,
696+ "vlan": vlan.id,
697 })
698 vlan_interface = get_one(
699 Interface.objects.filter(
700@@ -2178,13 +2175,14 @@
701 user = factory.make_admin()
702 node = factory.make_Node()
703 handler = MachineHandler(user, {})
704- interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
705- new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
706- new_subnet = factory.make_Subnet(vlan=new_vlan)
707+ vlan = factory.make_VLAN()
708+ interface = factory.make_Interface(
709+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan)
710+ new_subnet = factory.make_Subnet(vlan=vlan)
711 handler.create_vlan({
712 "system_id": node.system_id,
713 "parent": interface.id,
714- "vlan": new_vlan.id,
715+ "vlan": vlan.id,
716 "mode": INTERFACE_LINK_TYPE.AUTO,
717 "subnet": new_subnet.id,
718 })
719@@ -2200,12 +2198,13 @@
720 user = factory.make_admin()
721 node = factory.make_Node()
722 handler = MachineHandler(user, {})
723- interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
724- new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
725+ vlan = factory.make_VLAN()
726+ interface = factory.make_Interface(
727+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan)
728 handler.create_vlan({
729 "system_id": node.system_id,
730 "parent": interface.id,
731- "vlan": new_vlan.id,
732+ "vlan": vlan.id,
733 "mode": INTERFACE_LINK_TYPE.LINK_UP,
734 })
735 vlan_interface = get_one(
736@@ -2220,13 +2219,14 @@
737 user = factory.make_admin()
738 node = factory.make_Node()
739 handler = MachineHandler(user, {})
740- interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
741- new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
742- new_subnet = factory.make_Subnet(vlan=new_vlan)
743+ vlan = factory.make_VLAN()
744+ interface = factory.make_Interface(
745+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan)
746+ new_subnet = factory.make_Subnet(vlan=vlan)
747 handler.create_vlan({
748 "system_id": node.system_id,
749 "parent": interface.id,
750- "vlan": new_vlan.id,
751+ "vlan": vlan.id,
752 "mode": INTERFACE_LINK_TYPE.LINK_UP,
753 "subnet": new_subnet.id,
754 })
755@@ -2317,8 +2317,7 @@
756 handler = MachineHandler(user, {})
757 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
758 new_name = factory.make_name("name")
759- new_fabric = factory.make_Fabric()
760- new_vlan = new_fabric.get_default_vlan()
761+ new_vlan = factory.make_VLAN()
762 handler.update_interface({
763 "system_id": node.system_id,
764 "interface_id": interface.id,