Merge lp:~mpontillo/maas/l2-spaces--phase1 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: 5594
Proposed branch: lp:~mpontillo/maas/l2-spaces--phase1
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 376 lines (+191/-15)
11 files modified
src/maasserver/api/tests/test_vlans.py (+62/-0)
src/maasserver/api/vlans.py (+15/-0)
src/maasserver/forms_vlan.py (+22/-11)
src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py (+1/-2)
src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py (+24/-0)
src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py (+24/-0)
src/maasserver/models/vlan.py (+4/-0)
src/maasserver/static/partials/vlan-details.html (+3/-0)
src/maasserver/testing/factory.py (+2/-2)
src/maasserver/tests/test_forms_vlan.py (+33/-0)
src/maasserver/websockets/handlers/tests/test_vlan.py (+1/-0)
To merge this branch: bzr merge lp:~mpontillo/maas/l2-spaces--phase1
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+312563@code.launchpad.net

Commit message

L2 spaces: Phase 1

 * Add 'space' reference to VLAN.
 * Fix failing migration due to reference to maasserver.models.
 * Allow modification via the Web UI and REST API.

Description of the change

Note: constraints will be done in a future branch.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

Seems good to me!

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

Thanks for the review.

The oddities you pointed out in the diff are not unique to this diff. (That is, I made the new code consistent with code that was already in those files - so I won't go back and tweak those in this MP.)

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_vlans.py'
2--- src/maasserver/api/tests/test_vlans.py 2016-11-30 21:13:52 +0000
3+++ src/maasserver/api/tests/test_vlans.py 2016-12-06 16:09:53 +0000
4@@ -107,6 +107,50 @@
5 self.assertEqual(mtu, response_data['mtu'])
6 self.assertEqual(relay_vlan.vid, response_data['relay_vlan']['vid'])
7
8+ def test_create_without_space(self):
9+ self.become_admin()
10+ fabric = factory.make_Fabric()
11+ vlan_name = factory.make_name("fabric")
12+ vid = random.randint(1, 1000)
13+ mtu = random.randint(552, 1500)
14+ uri = get_vlans_uri(fabric)
15+ response = self.client.post(uri, {
16+ "name": vlan_name,
17+ "vid": vid,
18+ "mtu": mtu,
19+ })
20+ self.assertEqual(
21+ http.client.OK, response.status_code, response.content)
22+ response_data = json.loads(
23+ response.content.decode(settings.DEFAULT_CHARSET))
24+ self.assertEqual(vlan_name, response_data['name'])
25+ self.assertEqual(vid, response_data['vid'])
26+ self.assertEqual(mtu, response_data['mtu'])
27+ self.assertEqual(None, response_data['space'])
28+
29+ def test_create_with_space(self):
30+ self.become_admin()
31+ fabric = factory.make_Fabric()
32+ vlan_name = factory.make_name("fabric")
33+ vid = random.randint(1, 1000)
34+ mtu = random.randint(552, 1500)
35+ space = factory.make_Space()
36+ uri = get_vlans_uri(fabric)
37+ response = self.client.post(uri, {
38+ "name": vlan_name,
39+ "vid": vid,
40+ "mtu": mtu,
41+ "space": space.id,
42+ })
43+ self.assertEqual(
44+ http.client.OK, response.status_code, response.content)
45+ response_data = json.loads(
46+ response.content.decode(settings.DEFAULT_CHARSET))
47+ self.assertEqual(vlan_name, response_data['name'])
48+ self.assertEqual(vid, response_data['vid'])
49+ self.assertEqual(mtu, response_data['mtu'])
50+ self.assertEqual(space.name, response_data['space'])
51+
52 def test_create_admin_only(self):
53 fabric = factory.make_Fabric()
54 vlan_name = factory.make_name("fabric")
55@@ -176,6 +220,24 @@
56 "resource_uri": Equals(get_vlan_uri(vlan)),
57 }))
58
59+ def test_read_with_space(self):
60+ space = factory.make_Space()
61+ vlan = factory.make_VLAN(space=space)
62+ uri = get_vlan_uri(vlan, vlan.fabric)
63+ response = self.client.get(uri)
64+
65+ self.assertEqual(
66+ http.client.OK, response.status_code, response.content)
67+ parsed_vlan = json.loads(
68+ response.content.decode(settings.DEFAULT_CHARSET))
69+ self.assertThat(parsed_vlan, ContainsDict({
70+ "id": Equals(vlan.id),
71+ "name": Equals(vlan.get_name()),
72+ "vid": Equals(vlan.vid),
73+ "space": Equals(space.get_name()),
74+ "resource_uri": Equals(get_vlan_uri(vlan)),
75+ }))
76+
77 def test_read_404_when_bad_id(self):
78 fabric = factory.make_Fabric()
79 uri = reverse(
80
81=== modified file 'src/maasserver/api/vlans.py'
82--- src/maasserver/api/vlans.py 2016-11-30 21:13:52 +0000
83+++ src/maasserver/api/vlans.py 2016-12-06 16:09:53 +0000
84@@ -27,6 +27,7 @@
85 'dhcp_on',
86 'external_dhcp',
87 'relay_vlan',
88+ 'space',
89 )
90
91
92@@ -55,6 +56,13 @@
93 else:
94 return None
95
96+ @classmethod
97+ def space(handler, vlan):
98+ if vlan.space:
99+ return vlan.space.get_name()
100+ else:
101+ return None
102+
103 def read(self, request, fabric_id):
104 """List all VLANs belonging to fabric.
105
106@@ -113,6 +121,13 @@
107 return None
108
109 @classmethod
110+ def space(handler, vlan):
111+ if vlan.space:
112+ return vlan.space.get_name()
113+ else:
114+ return None
115+
116+ @classmethod
117 def fabric(cls, vlan):
118 """Return fabric name."""
119 return vlan.fabric.get_name()
120
121=== modified file 'src/maasserver/forms_vlan.py'
122--- src/maasserver/forms_vlan.py 2016-11-30 16:42:37 +0000
123+++ src/maasserver/forms_vlan.py 2016-12-06 16:09:53 +0000
124@@ -11,7 +11,10 @@
125 from django.core.exceptions import ValidationError
126 from maasserver.fields import NodeChoiceField
127 from maasserver.forms import MAASModelForm
128-from maasserver.models import RackController
129+from maasserver.models import (
130+ RackController,
131+ Space,
132+)
133 from maasserver.models.vlan import VLAN
134
135
136@@ -21,6 +24,9 @@
137 # Linux doesn't allow lower than 552 for the MTU.
138 mtu = forms.IntegerField(min_value=552, required=False)
139
140+ space = forms.ModelChoiceField(
141+ queryset=Space.objects.all(), required=False)
142+
143 class Meta:
144 model = VLAN
145 fields = (
146@@ -32,6 +38,7 @@
147 'primary_rack',
148 'secondary_rack',
149 'relay_vlan',
150+ 'space',
151 )
152
153 def __init__(self, *args, **kwargs):
154@@ -134,16 +141,20 @@
155 "dhcp can only be turned on when a dynamic IP range is defined.")
156
157 def save(self):
158- """Persist the interface into the database."""
159- interface = super(VLANForm, self).save(commit=False)
160+ """Persist the VLAN into the database."""
161+ vlan = super(VLANForm, self).save(commit=False)
162 if self.fabric is not None:
163- interface.fabric = self.fabric
164+ vlan.fabric = self.fabric
165+ if ('space' in self.data and
166+ not self.cleaned_data.get('space')):
167+ # 'space' is being cleared.
168+ vlan.space = None
169 if ('relay_vlan' in self.data and
170 not self.cleaned_data.get('relay_vlan')):
171- # relay_vlan is being cleared.
172- interface.relay_vlan = None
173- if interface.dhcp_on:
174- # relay_vlan cannot be set when dhcp is on.
175- interface.relay_vlan = None
176- interface.save()
177- return interface
178+ # 'relay_vlan' is being cleared.
179+ vlan.relay_vlan = None
180+ if vlan.dhcp_on:
181+ # 'relay_vlan' cannot be set when dhcp is on.
182+ vlan.relay_vlan = None
183+ vlan.save()
184+ return vlan
185
186=== modified file 'src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py'
187--- src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py 2016-12-05 14:56:57 +0000
188+++ src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py 2016-12-06 16:09:53 +0000
189@@ -6,7 +6,6 @@
190 models,
191 )
192 import django.db.models.deletion
193-import maasserver.models.subnet
194
195
196 class Migration(migrations.Migration):
197@@ -19,6 +18,6 @@
198 migrations.AlterField(
199 model_name='subnet',
200 name='vlan',
201- field=models.ForeignKey(to='maasserver.VLAN', default=maasserver.models.subnet.get_default_vlan, on_delete=django.db.models.deletion.PROTECT),
202+ field=models.ForeignKey(to='maasserver.VLAN', default=lambda: 0, on_delete=django.db.models.deletion.PROTECT),
203 ),
204 ]
205
206=== added file 'src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py'
207--- src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py 1970-01-01 00:00:00 +0000
208+++ src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py 2016-12-06 16:09:53 +0000
209@@ -0,0 +1,24 @@
210+# -*- coding: utf-8 -*-
211+from __future__ import unicode_literals
212+
213+from django.db import (
214+ migrations,
215+ models,
216+)
217+import django.db.models.deletion
218+import maasserver.models.subnet
219+
220+
221+class Migration(migrations.Migration):
222+
223+ dependencies = [
224+ ('maasserver', '0097_node_chassis_storage_hints'),
225+ ]
226+
227+ operations = [
228+ migrations.AddField(
229+ model_name='vlan',
230+ name='space',
231+ field=models.ForeignKey(blank=True, null=True, to='maasserver.Space', on_delete=django.db.models.deletion.SET_NULL),
232+ ),
233+ ]
234
235=== added file 'src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py'
236--- src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py 1970-01-01 00:00:00 +0000
237+++ src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py 2016-12-06 16:09:53 +0000
238@@ -0,0 +1,24 @@
239+# -*- coding: utf-8 -*-
240+from __future__ import unicode_literals
241+
242+from django.db import (
243+ migrations,
244+ models,
245+)
246+import django.db.models.deletion
247+import maasserver.models.subnet
248+
249+
250+class Migration(migrations.Migration):
251+
252+ dependencies = [
253+ ('maasserver', '0098_add_space_to_vlan'),
254+ ]
255+
256+ operations = [
257+ migrations.AlterField(
258+ model_name='subnet',
259+ name='vlan',
260+ field=models.ForeignKey(to='maasserver.VLAN', on_delete=django.db.models.deletion.PROTECT, default=maasserver.models.subnet.get_default_vlan),
261+ ),
262+ ]
263
264=== modified file 'src/maasserver/models/vlan.py'
265--- src/maasserver/models/vlan.py 2016-12-01 14:12:32 +0000
266+++ src/maasserver/models/vlan.py 2016-12-06 16:09:53 +0000
267@@ -19,6 +19,7 @@
268 IntegerField,
269 Manager,
270 Q,
271+ SET_NULL,
272 TextField,
273 )
274 from django.db.models.query import QuerySet
275@@ -174,6 +175,9 @@
276 'self', null=True, blank=True, editable=True,
277 related_name='relay_vlans', on_delete=deletion.SET_NULL)
278
279+ space = ForeignKey(
280+ 'Space', editable=True, blank=True, null=True, on_delete=SET_NULL)
281+
282 def __str__(self):
283 return "%s.%s" % (self.fabric.get_name(), self.get_name())
284
285
286=== modified file 'src/maasserver/static/partials/vlan-details.html'
287--- src/maasserver/static/partials/vlan-details.html 2016-12-06 07:32:14 +0000
288+++ src/maasserver/static/partials/vlan-details.html 2016-12-06 16:09:53 +0000
289@@ -232,6 +232,9 @@
290 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>
291 <maas-obj-field type="text" key="mtu" label="MTU" placeholder="VLAN MTU"
292 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>
293+ <maas-obj-field type="options" key="space" label="Space" placeholder="(not in a space)" placeholder-enabled="true"
294+ options="space.id as space.name for space in vlanDetails.spaces"
295+ label-width="two" input-width="three"></maas-obj-field>
296 <maas-obj-field type="textarea" key="description" label="Description" placeholder="VLAN description"
297 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>
298 </fieldset>
299
300=== modified file 'src/maasserver/testing/factory.py'
301--- src/maasserver/testing/factory.py 2016-12-06 09:34:06 +0000
302+++ src/maasserver/testing/factory.py 2016-12-06 16:09:53 +0000
303@@ -1037,7 +1037,7 @@
304 "Could not generate vid in fabric %s" % fabric)
305
306 def make_VLAN(
307- self, name=None, vid=None, fabric=None, dhcp_on=False,
308+ self, name=None, vid=None, fabric=None, dhcp_on=False, space=None,
309 primary_rack=None, secondary_rack=None, relay_vlan=None):
310 assert vid != 0, "VID=0 VLANs are auto-created"
311 if fabric is None:
312@@ -1046,7 +1046,7 @@
313 # Don't create the vid=0 VLAN, it's auto-created.
314 vid = self._get_available_vid(fabric)
315 vlan = VLAN(
316- name=name, vid=vid, fabric=fabric, dhcp_on=dhcp_on,
317+ name=name, vid=vid, fabric=fabric, dhcp_on=dhcp_on, space=space,
318 primary_rack=primary_rack, secondary_rack=secondary_rack,
319 relay_vlan=relay_vlan)
320 vlan.save()
321
322=== modified file 'src/maasserver/tests/test_forms_vlan.py'
323--- src/maasserver/tests/test_forms_vlan.py 2016-11-30 16:42:37 +0000
324+++ src/maasserver/tests/test_forms_vlan.py 2016-12-06 16:09:53 +0000
325@@ -266,6 +266,39 @@
326 vlan = reload_object(vlan)
327 self.assertIsNone(vlan.relay_vlan)
328
329+ def test_update_sets_space(self):
330+ vlan = factory.make_VLAN()
331+ space = factory.make_Space()
332+ form = VLANForm(instance=vlan, data={
333+ "space": space.id,
334+ })
335+ self.assertTrue(form.is_valid(), form.errors)
336+ form.save()
337+ vlan = reload_object(vlan)
338+ self.assertEquals(space.id, vlan.space.id)
339+
340+ def test_update_clears_space_when_None(self):
341+ space = factory.make_Space()
342+ vlan = factory.make_VLAN(space=space)
343+ form = VLANForm(instance=vlan, data={
344+ "space": None,
345+ })
346+ self.assertTrue(form.is_valid(), form.errors)
347+ form.save()
348+ vlan = reload_object(vlan)
349+ self.assertIsNone(vlan.space)
350+
351+ def test_update_clears_space_vlan_when_empty(self):
352+ space = factory.make_Space()
353+ vlan = factory.make_VLAN(space=space)
354+ form = VLANForm(instance=vlan, data={
355+ "space": "",
356+ })
357+ self.assertTrue(form.is_valid(), form.errors)
358+ form.save()
359+ vlan = reload_object(vlan)
360+ self.assertIsNone(vlan.space)
361+
362 def test_update_disables_relay_vlan_when_dhcp_turned_on(self):
363 relay_vlan = factory.make_VLAN()
364 vlan = factory.make_VLAN(relay_vlan=relay_vlan)
365
366=== modified file 'src/maasserver/websockets/handlers/tests/test_vlan.py'
367--- src/maasserver/websockets/handlers/tests/test_vlan.py 2016-12-06 08:04:18 +0000
368+++ src/maasserver/websockets/handlers/tests/test_vlan.py 2016-12-06 16:09:53 +0000
369@@ -36,6 +36,7 @@
370 "vid": vlan.vid,
371 "mtu": vlan.mtu,
372 "fabric": vlan.fabric_id,
373+ "space": vlan.space_id,
374 "updated": dehydrate_datetime(vlan.updated),
375 "created": dehydrate_datetime(vlan.created),
376 "dhcp_on": vlan.dhcp_on,