Merge lp:~blake-rouse/maas/force-untagged-api into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4731
Proposed branch: lp:~blake-rouse/maas/force-untagged-api
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~blake-rouse/maas/rack-nic-fabric-change
Diff against target: 840 lines (+227/-91)
4 files modified
src/maasserver/api/tests/test_interfaces.py (+21/-13)
src/maasserver/forms_interface.py (+55/-12)
src/maasserver/tests/test_forms_interface.py (+137/-57)
src/maasserver/websockets/handlers/tests/test_machine.py (+14/-9)
To merge this branch: bzr merge lp:~blake-rouse/maas/force-untagged-api
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+288026@code.launchpad.net

Commit message

Prevent allowing tagged VLAN from being attached to a physical or bond interface. Prevent untagged VLAN from being attached to a VLAN interface. This causes the API to match what the UI does.

Description of the change

Not having the API not match the UI is wrong and invalid. Its either we support one way or the other way, we should not support 50% one way and 50% another way. That makes for a confusing and incomplete product.

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Please see my comments here:

https://code.launchpad.net/~blake-rouse/maas/rack-nic-fabric-change/+merge/287852

Most of these validations are okay, but the ones that force the model to require physical interfaces to be on the default ("untagged") VLAN are deal-breakers for me.

I understand that we are making MAAS work out-of-the-box with switch fabrics where all ports always have the same default VLAN. But this change goes a step further and forces that to be true. The underlying model was designed to handle both scenarios, so forcing the issue in this way prevents a large percentage of customers from using MAAS, with no possible workaround. (I would argue that it is also a regression, since MAAS 1.8 supports this. MAAS 1.9 and 1.10 support this as well, though it is not the default behavior.)

review: Disapprove
Revision history for this message
Blake Rouse (blake-rouse) wrote :

My comments are documented in the bug. https://bugs.launchpad.net/maas/+bug/1552923

Revision history for this message
Mike Pontillo (mpontillo) wrote :

I still strongly disagree with this additional validation. However, I am changing my vote to "Approve" based on discussions with our management team; the preferred approach is to add this validation despite the noted risks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/api/tests/test_interfaces.py'
--- src/maasserver/api/tests/test_interfaces.py 2016-02-26 18:39:26 +0000
+++ src/maasserver/api/tests/test_interfaces.py 2016-03-03 21:30:31 +0000
@@ -48,14 +48,14 @@
48def make_complex_interface(node, name=None):48def make_complex_interface(node, name=None):
49 """Makes interface with parents and children."""49 """Makes interface with parents and children."""
50 fabric = factory.make_Fabric()50 fabric = factory.make_Fabric()
51 vlan_5 = factory.make_VLAN(vid=5, fabric=fabric)51 untagged = fabric.get_default_vlan()
52 nic_0 = factory.make_Interface(52 nic_0 = factory.make_Interface(
53 INTERFACE_TYPE.PHYSICAL, vlan=vlan_5, node=node)53 INTERFACE_TYPE.PHYSICAL, vlan=untagged, node=node)
54 nic_1 = factory.make_Interface(54 nic_1 = factory.make_Interface(
55 INTERFACE_TYPE.PHYSICAL, vlan=vlan_5, node=node)55 INTERFACE_TYPE.PHYSICAL, vlan=untagged, node=node)
56 parents = [nic_0, nic_1]56 parents = [nic_0, nic_1]
57 bond_interface = factory.make_Interface(57 bond_interface = factory.make_Interface(
58 INTERFACE_TYPE.BOND, mac_address=nic_0.mac_address, vlan=vlan_5,58 INTERFACE_TYPE.BOND, mac_address=nic_0.mac_address, vlan=untagged,
59 parents=parents, name=name)59 parents=parents, name=name)
60 vlan_10 = factory.make_VLAN(vid=10, fabric=fabric)60 vlan_10 = factory.make_VLAN(vid=10, fabric=fabric)
61 vlan_nic_10 = factory.make_Interface(61 vlan_nic_10 = factory.make_Interface(
@@ -112,7 +112,8 @@
112 node = factory.make_Node(status=status)112 node = factory.make_Node(status=status)
113 mac = factory.make_mac_address()113 mac = factory.make_mac_address()
114 name = factory.make_name("eth")114 name = factory.make_name("eth")
115 vlan = factory.make_VLAN()115 fabric = factory.make_Fabric()
116 vlan = fabric.get_default_vlan()
116 tags = [117 tags = [
117 factory.make_name("tag")118 factory.make_name("tag")
118 for _ in range(3)119 for _ in range(3)
@@ -145,7 +146,8 @@
145 owner=self.logged_in_user, parent=parent)146 owner=self.logged_in_user, parent=parent)
146 mac = factory.make_mac_address()147 mac = factory.make_mac_address()
147 name = factory.make_name("eth")148 name = factory.make_name("eth")
148 vlan = factory.make_VLAN()149 fabric = factory.make_Fabric()
150 vlan = fabric.get_default_vlan()
149 tags = [151 tags = [
150 factory.make_name("tag")152 factory.make_name("tag")
151 for _ in range(3)153 for _ in range(3)
@@ -178,7 +180,8 @@
178 node = factory.make_Node(status=status)180 node = factory.make_Node(status=status)
179 mac = factory.make_mac_address()181 mac = factory.make_mac_address()
180 name = factory.make_name("eth")182 name = factory.make_name("eth")
181 vlan = factory.make_VLAN()183 fabric = factory.make_Fabric()
184 vlan = fabric.get_default_vlan()
182 tags = [185 tags = [
183 factory.make_name("tag")186 factory.make_name("tag")
184 for _ in range(3)187 for _ in range(3)
@@ -274,7 +277,8 @@
274 interface_on_other_node = factory.make_Interface(277 interface_on_other_node = factory.make_Interface(
275 INTERFACE_TYPE.PHYSICAL)278 INTERFACE_TYPE.PHYSICAL)
276 name = factory.make_name("eth")279 name = factory.make_name("eth")
277 vlan = factory.make_VLAN()280 fabric = factory.make_Fabric()
281 vlan = fabric.get_default_vlan()
278 uri = get_interfaces_uri(node)282 uri = get_interfaces_uri(node)
279 response = self.client.post(uri, {283 response = self.client.post(uri, {
280 "op": "create_physical",284 "op": "create_physical",
@@ -294,7 +298,8 @@
294 self.become_admin()298 self.become_admin()
295 for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):299 for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
296 node = factory.make_Node(status=status)300 node = factory.make_Node(status=status)
297 vlan = factory.make_VLAN()301 fabric = factory.make_Fabric()
302 vlan = fabric.get_default_vlan()
298 parent_1_iface = factory.make_Interface(303 parent_1_iface = factory.make_Interface(
299 INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=node)304 INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=node)
300 parent_2_iface = factory.make_Interface(305 parent_2_iface = factory.make_Interface(
@@ -398,7 +403,7 @@
398 self.assertEqual(403 self.assertEqual(
399 http.client.CONFLICT, response.status_code, response.content)404 http.client.CONFLICT, response.status_code, response.content)
400405
401 def test_create_bond_requires_name_vlan_and_parents(self):406 def test_create_bond_requires_name_and_parents(self):
402 self.become_admin()407 self.become_admin()
403 node = factory.make_Node(status=NODE_STATUS.READY)408 node = factory.make_Node(status=NODE_STATUS.READY)
404 uri = get_interfaces_uri(node)409 uri = get_interfaces_uri(node)
@@ -411,7 +416,6 @@
411 self.assertEqual({416 self.assertEqual({
412 "mac_address": ["This field cannot be blank."],417 "mac_address": ["This field cannot be blank."],
413 "name": ["This field is required."],418 "name": ["This field is required."],
414 "vlan": ["This field is required."],
415 "parents": ["A Bond interface must have one or more parents."],419 "parents": ["A Bond interface must have one or more parents."],
416 }, json_load_bytes(response.content))420 }, json_load_bytes(response.content))
417421
@@ -635,7 +639,8 @@
635 interface = factory.make_Interface(639 interface = factory.make_Interface(
636 INTERFACE_TYPE.PHYSICAL, node=node)640 INTERFACE_TYPE.PHYSICAL, node=node)
637 new_name = factory.make_name("name")641 new_name = factory.make_name("name")
638 new_vlan = factory.make_VLAN()642 new_fabric = factory.make_Fabric()
643 new_vlan = new_fabric.get_default_vlan()
639 uri = get_interface_uri(interface)644 uri = get_interface_uri(interface)
640 response = self.client.put(uri, {645 response = self.client.put(uri, {
641 "name": new_name,646 "name": new_name,
@@ -654,7 +659,8 @@
654 interface = factory.make_Interface(659 interface = factory.make_Interface(
655 INTERFACE_TYPE.PHYSICAL, node=device)660 INTERFACE_TYPE.PHYSICAL, node=device)
656 new_name = factory.make_name("name")661 new_name = factory.make_name("name")
657 new_vlan = factory.make_VLAN()662 new_fabric = factory.make_Fabric()
663 new_vlan = new_fabric.get_default_vlan()
658 uri = get_interface_uri(interface)664 uri = get_interface_uri(interface)
659 response = self.client.put(uri, {665 response = self.client.put(uri, {
660 "name": new_name,666 "name": new_name,
@@ -689,9 +695,11 @@
689 node)695 node)
690 physical_interface = factory.make_Interface(696 physical_interface = factory.make_Interface(
691 INTERFACE_TYPE.PHYSICAL, node=node)697 INTERFACE_TYPE.PHYSICAL, node=node)
698 new_vlan = factory.make_VLAN(fabric=physical_interface.vlan.fabric)
692 uri = get_interface_uri(vlan_10)699 uri = get_interface_uri(vlan_10)
693 response = self.client.put(uri, {700 response = self.client.put(uri, {
694 "parent": physical_interface.id,701 "parent": physical_interface.id,
702 "vlan": new_vlan.id,
695 })703 })
696 self.assertEqual(704 self.assertEqual(
697 http.client.OK, response.status_code, response.content)705 http.client.OK, response.status_code, response.content)
698706
=== modified file 'src/maasserver/forms_interface.py'
--- src/maasserver/forms_interface.py 2015-12-01 18:12:59 +0000
+++ src/maasserver/forms_interface.py 2016-03-03 21:30:31 +0000
@@ -186,6 +186,13 @@
186 if len(parents) > 0:186 if len(parents) > 0:
187 raise ValidationError("A physical interface cannot have parents.")187 raise ValidationError("A physical interface cannot have parents.")
188188
189 def clean_vlan(self):
190 new_vlan = self.cleaned_data.get('vlan')
191 if new_vlan and new_vlan.fabric.get_default_vlan() != new_vlan:
192 raise ValidationError(
193 "A physical interface can only belong to an untagged VLAN.")
194 return new_vlan
195
189 def clean(self):196 def clean(self):
190 cleaned_data = super(PhysicalInterfaceForm, self).clean()197 cleaned_data = super(PhysicalInterfaceForm, self).clean()
191 new_name = cleaned_data.get('name')198 new_name = cleaned_data.get('name')
@@ -223,11 +230,25 @@
223 "in a bond.")230 "in a bond.")
224 return parents231 return parents
225232
233 def clean_vlan(self):
234 new_vlan = self.cleaned_data.get('vlan')
235 if new_vlan and new_vlan.fabric.get_default_vlan() == new_vlan:
236 raise ValidationError(
237 "A VLAN interface can only belong to a tagged VLAN.")
238 return new_vlan
239
226 def clean(self):240 def clean(self):
227 cleaned_data = super(VLANInterfaceForm, self).clean()241 cleaned_data = super(VLANInterfaceForm, self).clean()
228 if self.fields_ok(['vlan', 'parents']):242 if self.fields_ok(['vlan', 'parents']):
229 new_vlan = self.cleaned_data.get('vlan')243 new_vlan = self.cleaned_data.get('vlan')
230 if new_vlan:244 if new_vlan:
245 # VLAN needs to be the in the same fabric as the parent.
246 parent = self.cleaned_data.get('parents')[0]
247 if parent.vlan.fabric_id != new_vlan.fabric_id:
248 set_form_error(
249 self, "vlan",
250 "A VLAN interface can only belong to a tagged VLAN on "
251 "the same fabric as its parent interface.")
231 name = build_vlan_interface_name(252 name = build_vlan_interface_name(
232 self.cleaned_data.get('parents').first(), new_vlan)253 self.cleaned_data.get('parents').first(), new_vlan)
233 self.clean_interface_name_uniqueness(name)254 self.clean_interface_name_uniqueness(name)
@@ -271,6 +292,15 @@
271 'name',292 'name',
272 )293 )
273294
295 def __init__(self, *args, **kwargs):
296 super(BondInterfaceForm, self).__init__(*args, **kwargs)
297 # Allow VLAN to be blank when creating.
298 instance = kwargs.get("instance", None)
299 if instance is not None and instance.id is not None:
300 self.fields['vlan'].required = True
301 else:
302 self.fields['vlan'].required = False
303
274 def clean_parents(self):304 def clean_parents(self):
275 parents = self.get_clean_parents()305 parents = self.get_clean_parents()
276 if parents is None:306 if parents is None:
@@ -280,9 +310,16 @@
280 "A Bond interface must have one or more parents.")310 "A Bond interface must have one or more parents.")
281 return parents311 return parents
282312
313 def clean_vlan(self):
314 new_vlan = self.cleaned_data.get('vlan')
315 if new_vlan and new_vlan.fabric.get_default_vlan() != new_vlan:
316 raise ValidationError(
317 "A bond interface can only belong to an untagged VLAN.")
318 return new_vlan
319
283 def clean(self):320 def clean(self):
284 cleaned_data = super(BondInterfaceForm, self).clean()321 cleaned_data = super(BondInterfaceForm, self).clean()
285 if self.fields_ok(['parents']):322 if self.fields_ok(['vlan', 'parents']):
286 parents = self.cleaned_data.get('parents')323 parents = self.cleaned_data.get('parents')
287 # Set the mac_address if its missing and the interface is being324 # Set the mac_address if its missing and the interface is being
288 # created.325 # created.
@@ -323,6 +360,23 @@
323 self, 'parents',360 self, 'parents',
324 "%s is already in-use by another interface." % (361 "%s is already in-use by another interface." % (
325 ', '.join(sorted(parents_with_other_children))))362 ', '.join(sorted(parents_with_other_children))))
363
364 # When creating the bond set VLAN to the same as the parents
365 # and check that the parents all belong to the same VLAN.
366 if self.instance.id is None:
367 vlan = self.cleaned_data.get('vlan')
368 if vlan is None:
369 vlan = parents[0].vlan
370 self.cleaned_data['vlan'] = vlan
371 parent_vlans = {
372 parent.vlan
373 for parent in parents
374 }
375 if parent_vlans != set([vlan]):
376 set_form_error(
377 self, 'parents',
378 "All parents must belong to the same VLAN.")
379
326 return cleaned_data380 return cleaned_data
327381
328 def set_extra_parameters(self, interface, created):382 def set_extra_parameters(self, interface, created):
@@ -346,17 +400,6 @@
346 elif created:400 elif created:
347 interface.params[bond_field] = self.fields[bond_field].initial401 interface.params[bond_field] = self.fields[bond_field].initial
348402
349 def save(self, *args, **kwargs):
350 """Persist the interface into the database."""
351 created = self.instance.id is None
352 interface = super(BondInterfaceForm, self).save()
353 if created:
354 # Bond was created we remove all the links on the parent interfaces
355 # and ensure that the bond has atleast a LINK_UP.
356 for parent in interface.parents.all():
357 parent.clear_all_links(clearing_config=True)
358 return interface
359
360403
361INTERFACE_FORM_MAPPING = {404INTERFACE_FORM_MAPPING = {
362 INTERFACE_TYPE.PHYSICAL: PhysicalInterfaceForm,405 INTERFACE_TYPE.PHYSICAL: PhysicalInterfaceForm,
363406
=== modified file 'src/maasserver/tests/test_forms_interface.py'
--- src/maasserver/tests/test_forms_interface.py 2015-12-01 18:12:59 +0000
+++ src/maasserver/tests/test_forms_interface.py 2016-03-03 21:30:31 +0000
@@ -25,6 +25,7 @@
25from maasserver.testing.factory import factory25from maasserver.testing.factory import factory
26from maasserver.testing.testcase import MAASServerTestCase26from maasserver.testing.testcase import MAASServerTestCase
27from maasserver.utils.forms import compose_invalid_choice_text27from maasserver.utils.forms import compose_invalid_choice_text
28from maasserver.utils.orm import reload_object
28from testtools import ExpectedException29from testtools import ExpectedException
29from testtools.matchers import MatchesStructure30from testtools.matchers import MatchesStructure
3031
@@ -58,7 +59,8 @@
58 node = factory.make_Node()59 node = factory.make_Node()
59 mac_address = factory.make_mac_address()60 mac_address = factory.make_mac_address()
60 interface_name = 'eth0'61 interface_name = 'eth0'
61 vlan = factory.make_VLAN()62 fabric = factory.make_Fabric()
63 vlan = fabric.get_default_vlan()
62 tags = [64 tags = [
63 factory.make_name("tag")65 factory.make_name("tag")
64 for _ in range(3)66 for _ in range(3)
@@ -84,7 +86,8 @@
84 node = factory.make_Node()86 node = factory.make_Node()
85 mac_address = factory.make_mac_address()87 mac_address = factory.make_mac_address()
86 interface_name = 'eth0'88 interface_name = 'eth0'
87 vlan = factory.make_VLAN()89 fabric = factory.make_Fabric()
90 vlan = fabric.get_default_vlan()
88 tags = [91 tags = [
89 factory.make_name("tag")92 factory.make_name("tag")
90 for _ in range(3)93 for _ in range(3)
@@ -104,7 +107,8 @@
104107
105 def test__requires_mac_address(self):108 def test__requires_mac_address(self):
106 interface_name = 'eth0'109 interface_name = 'eth0'
107 vlan = factory.make_VLAN()110 fabric = factory.make_Fabric()
111 vlan = fabric.get_default_vlan()
108 form = PhysicalInterfaceForm(112 form = PhysicalInterfaceForm(
109 node=factory.make_Node(),113 node=factory.make_Node(),
110 data={114 data={
@@ -119,7 +123,9 @@
119 form.errors['mac_address'][0])123 form.errors['mac_address'][0])
120124
121 def test_rejects_interface_with_duplicate_name(self):125 def test_rejects_interface_with_duplicate_name(self):
122 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)126 fabric = factory.make_Fabric()
127 vlan = fabric.get_default_vlan()
128 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, vlan=vlan)
123 mac_address = factory.make_mac_address()129 mac_address = factory.make_mac_address()
124 form = PhysicalInterfaceForm(130 form = PhysicalInterfaceForm(
125 node=interface.node,131 node=interface.node,
@@ -135,9 +141,30 @@
135 "already has an interface named '%s'." % interface.name,141 "already has an interface named '%s'." % interface.name,
136 form.errors['name'][0])142 form.errors['name'][0])
137143
144 def test_rejects_interface_on_tagged_vlan(self):
145 fabric = factory.make_Fabric()
146 interface = factory.make_Interface(
147 INTERFACE_TYPE.PHYSICAL, vlan=fabric.get_default_vlan())
148 vlan = factory.make_VLAN(fabric=fabric)
149 mac_address = factory.make_mac_address()
150 form = PhysicalInterfaceForm(
151 node=interface.node,
152 data={
153 'name': factory.make_name("eth"),
154 'mac_address': mac_address,
155 'vlan': vlan.id,
156 })
157 self.assertFalse(form.is_valid(), form.errors)
158 self.assertItemsEqual(
159 ['vlan'], form.errors.keys(), form.errors)
160 self.assertIn(
161 "A physical interface can only belong to an untagged VLAN.",
162 form.errors['vlan'][0])
163
138 def test__rejects_parents(self):164 def test__rejects_parents(self):
139 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)165 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
140 vlan = factory.make_VLAN()166 fabric = factory.make_Fabric()
167 vlan = fabric.get_default_vlan()
141 form = PhysicalInterfaceForm(168 form = PhysicalInterfaceForm(
142 node=parent.node,169 node=parent.node,
143 data={170 data={
@@ -157,7 +184,8 @@
157 interface = factory.make_Interface(184 interface = factory.make_Interface(
158 INTERFACE_TYPE.PHYSICAL, name='eth0')185 INTERFACE_TYPE.PHYSICAL, name='eth0')
159 new_name = 'eth1'186 new_name = 'eth1'
160 new_vlan = factory.make_VLAN(vid=33)187 new_fabric = factory.make_Fabric()
188 new_vlan = new_fabric.get_default_vlan()
161 form = PhysicalInterfaceForm(189 form = PhysicalInterfaceForm(
162 instance=interface,190 instance=interface,
163 data={191 data={
@@ -178,7 +206,8 @@
178 node = factory.make_Node()206 node = factory.make_Node()
179 mac_address = factory.make_mac_address()207 mac_address = factory.make_mac_address()
180 interface_name = 'eth0'208 interface_name = 'eth0'
181 vlan = factory.make_VLAN()209 fabric = factory.make_Fabric()
210 vlan = fabric.get_default_vlan()
182 tags = [211 tags = [
183 factory.make_name("tag")212 factory.make_name("tag")
184 for _ in range(3)213 for _ in range(3)
@@ -217,7 +246,8 @@
217 "autoconf": autoconf,246 "autoconf": autoconf,
218 }247 }
219 new_name = 'eth1'248 new_name = 'eth1'
220 new_vlan = factory.make_VLAN(vid=33)249 new_fabric = factory.make_Fabric()
250 new_vlan = new_fabric.get_default_vlan()
221 form = PhysicalInterfaceForm(251 form = PhysicalInterfaceForm(
222 instance=interface,252 instance=interface,
223 data={253 data={
@@ -290,7 +320,7 @@
290320
291 def test__creates_vlan_interface(self):321 def test__creates_vlan_interface(self):
292 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)322 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
293 vlan = factory.make_VLAN(vid=10)323 vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
294 form = VLANInterfaceForm(324 form = VLANInterfaceForm(
295 node=parent.node,325 node=parent.node,
296 data={326 data={
@@ -308,7 +338,7 @@
308338
309 def test__create_ensures_link_up(self):339 def test__create_ensures_link_up(self):
310 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)340 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
311 vlan = factory.make_VLAN(vid=10)341 vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
312 form = VLANInterfaceForm(342 form = VLANInterfaceForm(
313 node=parent.node,343 node=parent.node,
314 data={344 data={
@@ -321,13 +351,10 @@
321 interface.ip_addresses.filter(alloc_type=IPADDRESS_TYPE.STICKY))351 interface.ip_addresses.filter(alloc_type=IPADDRESS_TYPE.STICKY))
322352
323 def test_rejects_interface_with_duplicate_name(self):353 def test_rejects_interface_with_duplicate_name(self):
324 vlan = factory.make_VLAN(vid=10)354 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
325 parent = factory.make_Interface(355 vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
326 INTERFACE_TYPE.PHYSICAL,
327 vlan=vlan)
328 interface = factory.make_Interface(356 interface = factory.make_Interface(
329 INTERFACE_TYPE.VLAN,357 INTERFACE_TYPE.VLAN, vlan=vlan, parents=[parent])
330 vlan=vlan, parents=[parent])
331 form = VLANInterfaceForm(358 form = VLANInterfaceForm(
332 node=parent.node,359 node=parent.node,
333 data={360 data={
@@ -341,6 +368,22 @@
341 "already has an interface named '%s'." % interface.name,368 "already has an interface named '%s'." % interface.name,
342 form.errors['name'][0])369 form.errors['name'][0])
343370
371 def test_rejects_interface_on_default_fabric(self):
372 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
373 vlan = parent.vlan.fabric.get_default_vlan()
374 form = VLANInterfaceForm(
375 node=parent.node,
376 data={
377 'vlan': vlan.id,
378 'parents': [parent.id],
379 })
380 self.assertFalse(form.is_valid(), form.errors)
381 self.assertItemsEqual(
382 ['vlan'], form.errors.keys(), form.errors)
383 self.assertIn(
384 "A VLAN interface can only belong to a tagged VLAN.",
385 form.errors['vlan'][0])
386
344 def test__rejects_no_parents(self):387 def test__rejects_no_parents(self):
345 vlan = factory.make_VLAN(vid=10)388 vlan = factory.make_VLAN(vid=10)
346 form = VLANInterfaceForm(389 form = VLANInterfaceForm(
@@ -356,13 +399,14 @@
356399
357 def test__rejects_vlan_parent(self):400 def test__rejects_vlan_parent(self):
358 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)401 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
402 vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
359 vlan_parent = factory.make_Interface(403 vlan_parent = factory.make_Interface(
360 INTERFACE_TYPE.VLAN, parents=[parent])404 INTERFACE_TYPE.VLAN, vlan=vlan, parents=[parent])
361 vlan = factory.make_VLAN(vid=10)405 other_vlan = factory.make_VLAN(fabric=parent.vlan.fabric, vid=11)
362 form = VLANInterfaceForm(406 form = VLANInterfaceForm(
363 node=parent.node,407 node=parent.node,
364 data={408 data={
365 'vlan': vlan.id,409 'vlan': other_vlan.id,
366 'parents': [vlan_parent.id],410 'parents': [vlan_parent.id],
367 })411 })
368 self.assertFalse(form.is_valid(), form.errors)412 self.assertFalse(form.is_valid(), form.errors)
@@ -371,10 +415,27 @@
371 "VLAN interface can't have another VLAN interface as parent.",415 "VLAN interface can't have another VLAN interface as parent.",
372 form.errors['parents'][0])416 form.errors['parents'][0])
373417
418 def test__rejects_vlan_not_on_same_fabric(self):
419 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
420 factory.make_VLAN(fabric=parent.vlan.fabric, vid=10)
421 other_vlan = factory.make_VLAN()
422 form = VLANInterfaceForm(
423 node=parent.node,
424 data={
425 'vlan': other_vlan.id,
426 'parents': [parent.id],
427 })
428 self.assertFalse(form.is_valid(), form.errors)
429 self.assertItemsEqual(['vlan'], form.errors.keys())
430 self.assertIn(
431 "A VLAN interface can only belong to a tagged VLAN on "
432 "the same fabric as its parent interface.",
433 form.errors['vlan'][0])
434
374 def test__rejects_parent_on_bond(self):435 def test__rejects_parent_on_bond(self):
375 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)436 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
376 factory.make_Interface(INTERFACE_TYPE.BOND, parents=[parent])437 bond = factory.make_Interface(INTERFACE_TYPE.BOND, parents=[parent])
377 vlan = factory.make_VLAN(vid=10)438 vlan = factory.make_VLAN(fabric=bond.vlan.fabric, vid=10)
378 form = VLANInterfaceForm(439 form = VLANInterfaceForm(
379 node=parent.node,440 node=parent.node,
380 data={441 data={
@@ -408,7 +469,7 @@
408 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)469 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
409 interface = factory.make_Interface(470 interface = factory.make_Interface(
410 INTERFACE_TYPE.VLAN, parents=[parent])471 INTERFACE_TYPE.VLAN, parents=[parent])
411 new_vlan = factory.make_VLAN(vid=33)472 new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric, vid=33)
412 form = VLANInterfaceForm(473 form = VLANInterfaceForm(
413 instance=interface,474 instance=interface,
414 data={475 data={
@@ -429,15 +490,13 @@
429 def test__error_with_invalid_bond_mode(self):490 def test__error_with_invalid_bond_mode(self):
430 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)491 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
431 parent2 = factory.make_Interface(492 parent2 = factory.make_Interface(
432 INTERFACE_TYPE.PHYSICAL, node=parent1.node)493 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
433 interface_name = factory.make_name()494 interface_name = factory.make_name()
434 vlan = factory.make_VLAN(vid=10)
435 bond_mode = factory.make_name("bond_mode")495 bond_mode = factory.make_name("bond_mode")
436 form = BondInterfaceForm(496 form = BondInterfaceForm(
437 node=parent1.node,497 node=parent1.node,
438 data={498 data={
439 'name': interface_name,499 'name': interface_name,
440 'vlan': vlan.id,
441 'parents': [parent1.id, parent2.id],500 'parents': [parent1.id, parent2.id],
442 'bond_mode': bond_mode,501 'bond_mode': bond_mode,
443 })502 })
@@ -451,14 +510,12 @@
451 def test__creates_bond_interface(self):510 def test__creates_bond_interface(self):
452 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)511 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
453 parent2 = factory.make_Interface(512 parent2 = factory.make_Interface(
454 INTERFACE_TYPE.PHYSICAL, node=parent1.node)513 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
455 interface_name = factory.make_name()514 interface_name = factory.make_name()
456 vlan = factory.make_VLAN(vid=10)
457 form = BondInterfaceForm(515 form = BondInterfaceForm(
458 node=parent1.node,516 node=parent1.node,
459 data={517 data={
460 'name': interface_name,518 'name': interface_name,
461 'vlan': vlan.id,
462 'parents': [parent1.id, parent2.id],519 'parents': [parent1.id, parent2.id],
463 })520 })
464 self.assertTrue(form.is_valid(), form.errors)521 self.assertTrue(form.is_valid(), form.errors)
@@ -475,15 +532,13 @@
475 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)532 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
476 parent1.ensure_link_up()533 parent1.ensure_link_up()
477 parent2 = factory.make_Interface(534 parent2 = factory.make_Interface(
478 INTERFACE_TYPE.PHYSICAL, node=parent1.node)535 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
479 parent2.ensure_link_up()536 parent2.ensure_link_up()
480 interface_name = factory.make_name()537 interface_name = factory.make_name()
481 vlan = factory.make_VLAN(vid=10)
482 form = BondInterfaceForm(538 form = BondInterfaceForm(
483 node=parent1.node,539 node=parent1.node,
484 data={540 data={
485 'name': interface_name,541 'name': interface_name,
486 'vlan': vlan.id,
487 'parents': [parent1.id, parent2.id],542 'parents': [parent1.id, parent2.id],
488 })543 })
489 self.assertTrue(form.is_valid(), form.errors)544 self.assertTrue(form.is_valid(), form.errors)
@@ -502,14 +557,12 @@
502 def test__creates_bond_interface_with_parent_mac_address(self):557 def test__creates_bond_interface_with_parent_mac_address(self):
503 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)558 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
504 parent2 = factory.make_Interface(559 parent2 = factory.make_Interface(
505 INTERFACE_TYPE.PHYSICAL, node=parent1.node)560 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
506 interface_name = factory.make_name()561 interface_name = factory.make_name()
507 vlan = factory.make_VLAN(vid=10)
508 form = BondInterfaceForm(562 form = BondInterfaceForm(
509 node=parent1.node,563 node=parent1.node,
510 data={564 data={
511 'name': interface_name,565 'name': interface_name,
512 'vlan': vlan.id,
513 'parents': [parent1.id, parent2.id],566 'parents': [parent1.id, parent2.id],
514 'mac_address': parent1.mac_address,567 'mac_address': parent1.mac_address,
515 })568 })
@@ -525,14 +578,12 @@
525 def test__creates_bond_interface_with_default_bond_params(self):578 def test__creates_bond_interface_with_default_bond_params(self):
526 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)579 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
527 parent2 = factory.make_Interface(580 parent2 = factory.make_Interface(
528 INTERFACE_TYPE.PHYSICAL, node=parent1.node)581 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
529 interface_name = factory.make_name()582 interface_name = factory.make_name()
530 vlan = factory.make_VLAN(vid=10)
531 form = BondInterfaceForm(583 form = BondInterfaceForm(
532 node=parent1.node,584 node=parent1.node,
533 data={585 data={
534 'name': interface_name,586 'name': interface_name,
535 'vlan': vlan.id,
536 'parents': [parent1.id, parent2.id],587 'parents': [parent1.id, parent2.id],
537 })588 })
538 self.assertTrue(form.is_valid(), form.errors)589 self.assertTrue(form.is_valid(), form.errors)
@@ -549,9 +600,8 @@
549 def test__creates_bond_interface_with_bond_params(self):600 def test__creates_bond_interface_with_bond_params(self):
550 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)601 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
551 parent2 = factory.make_Interface(602 parent2 = factory.make_Interface(
552 INTERFACE_TYPE.PHYSICAL, node=parent1.node)603 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
553 interface_name = factory.make_name()604 interface_name = factory.make_name()
554 vlan = factory.make_VLAN(vid=10)
555 bond_mode = factory.pick_choice(BOND_MODE_CHOICES)605 bond_mode = factory.pick_choice(BOND_MODE_CHOICES)
556 bond_miimon = random.randint(0, 1000)606 bond_miimon = random.randint(0, 1000)
557 bond_downdelay = random.randint(0, 1000)607 bond_downdelay = random.randint(0, 1000)
@@ -563,7 +613,6 @@
563 node=parent1.node,613 node=parent1.node,
564 data={614 data={
565 'name': interface_name,615 'name': interface_name,
566 'vlan': vlan.id,
567 'parents': [parent1.id, parent2.id],616 'parents': [parent1.id, parent2.id],
568 'bond_mode': bond_mode,617 'bond_mode': bond_mode,
569 'bond_miimon': bond_miimon,618 'bond_miimon': bond_miimon,
@@ -584,13 +633,11 @@
584 }, interface.params)633 }, interface.params)
585634
586 def test__rejects_no_parents(self):635 def test__rejects_no_parents(self):
587 vlan = factory.make_VLAN(vid=10)
588 interface_name = factory.make_name()636 interface_name = factory.make_name()
589 form = BondInterfaceForm(637 form = BondInterfaceForm(
590 node=factory.make_Node(),638 node=factory.make_Node(),
591 data={639 data={
592 'name': interface_name,640 'name': interface_name,
593 'vlan': vlan.id,
594 })641 })
595 self.assertFalse(form.is_valid(), form.errors)642 self.assertFalse(form.is_valid(), form.errors)
596 self.assertItemsEqual(['parents', 'mac_address'], form.errors.keys())643 self.assertItemsEqual(['parents', 'mac_address'], form.errors.keys())
@@ -598,21 +645,37 @@
598 "A Bond interface must have one or more parents.",645 "A Bond interface must have one or more parents.",
599 form.errors['parents'][0])646 form.errors['parents'][0])
600647
648 def test__rejects_when_vlan_not_untagged(self):
649 interface_name = factory.make_name()
650 parent = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
651 vlan = factory.make_VLAN(fabric=parent.vlan.fabric)
652 form = BondInterfaceForm(
653 node=parent.node,
654 data={
655 'name': interface_name,
656 'parents': [parent.id],
657 'mac_address': parent.mac_address,
658 'vlan': vlan.id,
659 })
660 self.assertFalse(form.is_valid(), form.errors)
661 self.assertItemsEqual(['vlan'], form.errors.keys())
662 self.assertIn(
663 "A bond interface can only belong to an untagged VLAN.",
664 form.errors['vlan'][0])
665
601 def test__rejects_when_parents_already_have_children(self):666 def test__rejects_when_parents_already_have_children(self):
602 node = factory.make_Node()667 node = factory.make_Node()
603 parent1 = factory.make_Interface(668 parent1 = factory.make_Interface(
604 INTERFACE_TYPE.PHYSICAL, node=node, name="eth0")669 INTERFACE_TYPE.PHYSICAL, node=node, name="eth0")
605 factory.make_Interface(INTERFACE_TYPE.VLAN, parents=[parent1])670 factory.make_Interface(INTERFACE_TYPE.VLAN, parents=[parent1])
606 parent2 = factory.make_Interface(671 parent2 = factory.make_Interface(
607 INTERFACE_TYPE.PHYSICAL, node=node, name="eth1")672 INTERFACE_TYPE.PHYSICAL, node=node, name="eth1", vlan=parent1.vlan)
608 factory.make_Interface(INTERFACE_TYPE.VLAN, parents=[parent2])673 factory.make_Interface(INTERFACE_TYPE.VLAN, parents=[parent2])
609 vlan = factory.make_VLAN(vid=10)
610 interface_name = factory.make_name()674 interface_name = factory.make_name()
611 form = BondInterfaceForm(675 form = BondInterfaceForm(
612 node=node,676 node=node,
613 data={677 data={
614 'name': interface_name,678 'name': interface_name,
615 'vlan': vlan.id,
616 'parents': [parent1.id, parent2.id]679 'parents': [parent1.id, parent2.id]
617 })680 })
618 self.assertFalse(form.is_valid(), form.errors)681 self.assertFalse(form.is_valid(), form.errors)
@@ -620,17 +683,36 @@
620 "eth0, eth1 is already in-use by another interface.",683 "eth0, eth1 is already in-use by another interface.",
621 form.errors['parents'][0])684 form.errors['parents'][0])
622685
686 def test__rejects_when_parents_not_in_same_vlan(self):
687 node = factory.make_Node()
688 parent1 = factory.make_Interface(
689 INTERFACE_TYPE.PHYSICAL, node=node, name="eth0")
690 parent2 = factory.make_Interface(
691 INTERFACE_TYPE.PHYSICAL, node=node, name="eth1")
692 interface_name = factory.make_name()
693 form = BondInterfaceForm(
694 node=node,
695 data={
696 'name': interface_name,
697 'parents': [parent1.id, parent2.id]
698 })
699 self.assertFalse(form.is_valid(), form.errors)
700 self.assertEquals(
701 "All parents must belong to the same VLAN.",
702 form.errors['parents'][0])
703
623 def test__edits_interface(self):704 def test__edits_interface(self):
624 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)705 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
625 parent2 = factory.make_Interface(706 parent2 = factory.make_Interface(
626 INTERFACE_TYPE.PHYSICAL, node=parent1.node)707 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
627 interface = factory.make_Interface(708 interface = factory.make_Interface(
628 INTERFACE_TYPE.BOND,709 INTERFACE_TYPE.BOND,
629 parents=[parent1, parent2])710 parents=[parent1, parent2])
630 new_vlan = factory.make_VLAN(vid=33)711 new_fabric = factory.make_Fabric()
712 new_vlan = new_fabric.get_default_vlan()
631 new_name = factory.make_name()713 new_name = factory.make_name()
632 new_parent = factory.make_Interface(714 new_parent = factory.make_Interface(
633 INTERFACE_TYPE.PHYSICAL, node=parent1.node)715 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
634 form = BondInterfaceForm(716 form = BondInterfaceForm(
635 instance=interface,717 instance=interface,
636 data={718 data={
@@ -647,6 +729,10 @@
647 vlan=new_vlan, type=INTERFACE_TYPE.BOND))729 vlan=new_vlan, type=INTERFACE_TYPE.BOND))
648 self.assertItemsEqual(730 self.assertItemsEqual(
649 [parent1, parent2, new_parent], interface.parents.all())731 [parent1, parent2, new_parent], interface.parents.all())
732 self.assertItemsEqual([new_vlan], set(
733 reload_object(parent).vlan
734 for parent in [parent1, parent2, new_parent]
735 ))
650736
651 def test__edits_interface_removes_parents(self):737 def test__edits_interface_removes_parents(self):
652 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)738 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
@@ -704,7 +790,7 @@
704 def test__edit_doesnt_overwrite_params(self):790 def test__edit_doesnt_overwrite_params(self):
705 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)791 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
706 parent2 = factory.make_Interface(792 parent2 = factory.make_Interface(
707 INTERFACE_TYPE.PHYSICAL, node=parent1.node)793 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
708 interface = factory.make_Interface(794 interface = factory.make_Interface(
709 INTERFACE_TYPE.BOND,795 INTERFACE_TYPE.BOND,
710 parents=[parent1, parent2])796 parents=[parent1, parent2])
@@ -724,12 +810,10 @@
724 "bond_xmit_hash_policy": bond_xmit_hash_policy,810 "bond_xmit_hash_policy": bond_xmit_hash_policy,
725 }811 }
726 interface.save()812 interface.save()
727 new_vlan = factory.make_VLAN(vid=33)
728 new_name = factory.make_name()813 new_name = factory.make_name()
729 form = BondInterfaceForm(814 form = BondInterfaceForm(
730 instance=interface,815 instance=interface,
731 data={816 data={
732 'vlan': new_vlan.id,
733 'name': new_name,817 'name': new_name,
734 })818 })
735 self.assertTrue(form.is_valid(), form.errors)819 self.assertTrue(form.is_valid(), form.errors)
@@ -746,7 +830,7 @@
746 def test__edit_does_overwrite_params(self):830 def test__edit_does_overwrite_params(self):
747 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)831 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
748 parent2 = factory.make_Interface(832 parent2 = factory.make_Interface(
749 INTERFACE_TYPE.PHYSICAL, node=parent1.node)833 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
750 interface = factory.make_Interface(834 interface = factory.make_Interface(
751 INTERFACE_TYPE.BOND,835 INTERFACE_TYPE.BOND,
752 parents=[parent1, parent2])836 parents=[parent1, parent2])
@@ -766,7 +850,6 @@
766 "bond_xmit_hash_policy": bond_xmit_hash_policy,850 "bond_xmit_hash_policy": bond_xmit_hash_policy,
767 }851 }
768 interface.save()852 interface.save()
769 new_vlan = factory.make_VLAN(vid=33)
770 new_name = factory.make_name()853 new_name = factory.make_name()
771 new_bond_mode = factory.pick_choice(BOND_MODE_CHOICES)854 new_bond_mode = factory.pick_choice(BOND_MODE_CHOICES)
772 new_bond_miimon = random.randint(0, 1000)855 new_bond_miimon = random.randint(0, 1000)
@@ -778,7 +861,6 @@
778 form = BondInterfaceForm(861 form = BondInterfaceForm(
779 instance=interface,862 instance=interface,
780 data={863 data={
781 'vlan': new_vlan.id,
782 'name': new_name,864 'name': new_name,
783 'bond_mode': new_bond_mode,865 'bond_mode': new_bond_mode,
784 'bond_miimon': new_bond_miimon,866 'bond_miimon': new_bond_miimon,
@@ -801,7 +883,7 @@
801 def test__edit_allows_zero_params(self):883 def test__edit_allows_zero_params(self):
802 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)884 parent1 = factory.make_Interface(INTERFACE_TYPE.PHYSICAL)
803 parent2 = factory.make_Interface(885 parent2 = factory.make_Interface(
804 INTERFACE_TYPE.PHYSICAL, node=parent1.node)886 INTERFACE_TYPE.PHYSICAL, node=parent1.node, vlan=parent1.vlan)
805 interface = factory.make_Interface(887 interface = factory.make_Interface(
806 INTERFACE_TYPE.BOND,888 INTERFACE_TYPE.BOND,
807 parents=[parent1, parent2])889 parents=[parent1, parent2])
@@ -821,7 +903,6 @@
821 "bond_xmit_hash_policy": bond_xmit_hash_policy,903 "bond_xmit_hash_policy": bond_xmit_hash_policy,
822 }904 }
823 interface.save()905 interface.save()
824 new_vlan = factory.make_VLAN(vid=33)
825 new_name = factory.make_name()906 new_name = factory.make_name()
826 new_bond_mode = factory.pick_choice(BOND_MODE_CHOICES)907 new_bond_mode = factory.pick_choice(BOND_MODE_CHOICES)
827 new_bond_miimon = 0908 new_bond_miimon = 0
@@ -833,7 +914,6 @@
833 form = BondInterfaceForm(914 form = BondInterfaceForm(
834 instance=interface,915 instance=interface,
835 data={916 data={
836 'vlan': new_vlan.id,
837 'name': new_name,917 'name': new_name,
838 'bond_mode': new_bond_mode,918 'bond_mode': new_bond_mode,
839 'bond_miimon': new_bond_miimon,919 'bond_miimon': new_bond_miimon,
840920
=== modified file 'src/maasserver/websockets/handlers/tests/test_machine.py'
--- src/maasserver/websockets/handlers/tests/test_machine.py 2016-03-02 10:23:02 +0000
+++ src/maasserver/websockets/handlers/tests/test_machine.py 2016-03-03 21:30:31 +0000
@@ -1843,7 +1843,8 @@
1843 handler = MachineHandler(user, {})1843 handler = MachineHandler(user, {})
1844 name = factory.make_name("eth")1844 name = factory.make_name("eth")
1845 mac_address = factory.make_mac_address()1845 mac_address = factory.make_mac_address()
1846 vlan = factory.make_VLAN()1846 fabric = factory.make_Fabric()
1847 vlan = fabric.get_default_vlan()
1847 handler.create_physical({1848 handler.create_physical({
1848 "system_id": node.system_id,1849 "system_id": node.system_id,
1849 "name": name,1850 "name": name,
@@ -1860,7 +1861,8 @@
1860 handler = MachineHandler(user, {})1861 handler = MachineHandler(user, {})
1861 name = factory.make_name("eth")1862 name = factory.make_name("eth")
1862 mac_address = factory.make_mac_address()1863 mac_address = factory.make_mac_address()
1863 vlan = factory.make_VLAN()1864 fabric = factory.make_Fabric()
1865 vlan = fabric.get_default_vlan()
1864 subnet = factory.make_Subnet(vlan=vlan)1866 subnet = factory.make_Subnet(vlan=vlan)
1865 handler.create_physical({1867 handler.create_physical({
1866 "system_id": node.system_id,1868 "system_id": node.system_id,
@@ -1882,7 +1884,8 @@
1882 handler = MachineHandler(user, {})1884 handler = MachineHandler(user, {})
1883 name = factory.make_name("eth")1885 name = factory.make_name("eth")
1884 mac_address = factory.make_mac_address()1886 mac_address = factory.make_mac_address()
1885 vlan = factory.make_VLAN()1887 fabric = factory.make_Fabric()
1888 vlan = fabric.get_default_vlan()
1886 handler.create_physical({1889 handler.create_physical({
1887 "system_id": node.system_id,1890 "system_id": node.system_id,
1888 "name": name,1891 "name": name,
@@ -1902,7 +1905,8 @@
1902 handler = MachineHandler(user, {})1905 handler = MachineHandler(user, {})
1903 name = factory.make_name("eth")1906 name = factory.make_name("eth")
1904 mac_address = factory.make_mac_address()1907 mac_address = factory.make_mac_address()
1905 vlan = factory.make_VLAN()1908 fabric = factory.make_Fabric()
1909 vlan = fabric.get_default_vlan()
1906 subnet = factory.make_Subnet(vlan=vlan)1910 subnet = factory.make_Subnet(vlan=vlan)
1907 handler.create_physical({1911 handler.create_physical({
1908 "system_id": node.system_id,1912 "system_id": node.system_id,
@@ -1923,7 +1927,7 @@
1923 node = factory.make_Node()1927 node = factory.make_Node()
1924 handler = MachineHandler(user, {})1928 handler = MachineHandler(user, {})
1925 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)1929 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
1926 new_vlan = factory.make_VLAN()1930 new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
1927 handler.create_vlan({1931 handler.create_vlan({
1928 "system_id": node.system_id,1932 "system_id": node.system_id,
1929 "parent": interface.id,1933 "parent": interface.id,
@@ -1939,7 +1943,7 @@
1939 node = factory.make_Node()1943 node = factory.make_Node()
1940 handler = MachineHandler(user, {})1944 handler = MachineHandler(user, {})
1941 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)1945 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
1942 new_vlan = factory.make_VLAN()1946 new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
1943 new_subnet = factory.make_Subnet(vlan=new_vlan)1947 new_subnet = factory.make_Subnet(vlan=new_vlan)
1944 handler.create_vlan({1948 handler.create_vlan({
1945 "system_id": node.system_id,1949 "system_id": node.system_id,
@@ -1961,7 +1965,7 @@
1961 node = factory.make_Node()1965 node = factory.make_Node()
1962 handler = MachineHandler(user, {})1966 handler = MachineHandler(user, {})
1963 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)1967 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
1964 new_vlan = factory.make_VLAN()1968 new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
1965 handler.create_vlan({1969 handler.create_vlan({
1966 "system_id": node.system_id,1970 "system_id": node.system_id,
1967 "parent": interface.id,1971 "parent": interface.id,
@@ -1981,7 +1985,7 @@
1981 node = factory.make_Node()1985 node = factory.make_Node()
1982 handler = MachineHandler(user, {})1986 handler = MachineHandler(user, {})
1983 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)1987 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
1984 new_vlan = factory.make_VLAN()1988 new_vlan = factory.make_VLAN(fabric=interface.vlan.fabric)
1985 new_subnet = factory.make_Subnet(vlan=new_vlan)1989 new_subnet = factory.make_Subnet(vlan=new_vlan)
1986 handler.create_vlan({1990 handler.create_vlan({
1987 "system_id": node.system_id,1991 "system_id": node.system_id,
@@ -2041,7 +2045,8 @@
2041 handler = MachineHandler(user, {})2045 handler = MachineHandler(user, {})
2042 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)2046 interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL, node=node)
2043 new_name = factory.make_name("name")2047 new_name = factory.make_name("name")
2044 new_vlan = factory.make_VLAN()2048 new_fabric = factory.make_Fabric()
2049 new_vlan = new_fabric.get_default_vlan()
2045 handler.update_interface({2050 handler.update_interface({
2046 "system_id": node.system_id,2051 "system_id": node.system_id,
2047 "interface_id": interface.id,2052 "interface_id": interface.id,