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
=== modified file 'src/maasserver/api/tests/test_vlans.py'
--- src/maasserver/api/tests/test_vlans.py 2016-11-30 21:13:52 +0000
+++ src/maasserver/api/tests/test_vlans.py 2016-12-06 16:09:53 +0000
@@ -107,6 +107,50 @@
107 self.assertEqual(mtu, response_data['mtu'])107 self.assertEqual(mtu, response_data['mtu'])
108 self.assertEqual(relay_vlan.vid, response_data['relay_vlan']['vid'])108 self.assertEqual(relay_vlan.vid, response_data['relay_vlan']['vid'])
109109
110 def test_create_without_space(self):
111 self.become_admin()
112 fabric = factory.make_Fabric()
113 vlan_name = factory.make_name("fabric")
114 vid = random.randint(1, 1000)
115 mtu = random.randint(552, 1500)
116 uri = get_vlans_uri(fabric)
117 response = self.client.post(uri, {
118 "name": vlan_name,
119 "vid": vid,
120 "mtu": mtu,
121 })
122 self.assertEqual(
123 http.client.OK, response.status_code, response.content)
124 response_data = json.loads(
125 response.content.decode(settings.DEFAULT_CHARSET))
126 self.assertEqual(vlan_name, response_data['name'])
127 self.assertEqual(vid, response_data['vid'])
128 self.assertEqual(mtu, response_data['mtu'])
129 self.assertEqual(None, response_data['space'])
130
131 def test_create_with_space(self):
132 self.become_admin()
133 fabric = factory.make_Fabric()
134 vlan_name = factory.make_name("fabric")
135 vid = random.randint(1, 1000)
136 mtu = random.randint(552, 1500)
137 space = factory.make_Space()
138 uri = get_vlans_uri(fabric)
139 response = self.client.post(uri, {
140 "name": vlan_name,
141 "vid": vid,
142 "mtu": mtu,
143 "space": space.id,
144 })
145 self.assertEqual(
146 http.client.OK, response.status_code, response.content)
147 response_data = json.loads(
148 response.content.decode(settings.DEFAULT_CHARSET))
149 self.assertEqual(vlan_name, response_data['name'])
150 self.assertEqual(vid, response_data['vid'])
151 self.assertEqual(mtu, response_data['mtu'])
152 self.assertEqual(space.name, response_data['space'])
153
110 def test_create_admin_only(self):154 def test_create_admin_only(self):
111 fabric = factory.make_Fabric()155 fabric = factory.make_Fabric()
112 vlan_name = factory.make_name("fabric")156 vlan_name = factory.make_name("fabric")
@@ -176,6 +220,24 @@
176 "resource_uri": Equals(get_vlan_uri(vlan)),220 "resource_uri": Equals(get_vlan_uri(vlan)),
177 }))221 }))
178222
223 def test_read_with_space(self):
224 space = factory.make_Space()
225 vlan = factory.make_VLAN(space=space)
226 uri = get_vlan_uri(vlan, vlan.fabric)
227 response = self.client.get(uri)
228
229 self.assertEqual(
230 http.client.OK, response.status_code, response.content)
231 parsed_vlan = json.loads(
232 response.content.decode(settings.DEFAULT_CHARSET))
233 self.assertThat(parsed_vlan, ContainsDict({
234 "id": Equals(vlan.id),
235 "name": Equals(vlan.get_name()),
236 "vid": Equals(vlan.vid),
237 "space": Equals(space.get_name()),
238 "resource_uri": Equals(get_vlan_uri(vlan)),
239 }))
240
179 def test_read_404_when_bad_id(self):241 def test_read_404_when_bad_id(self):
180 fabric = factory.make_Fabric()242 fabric = factory.make_Fabric()
181 uri = reverse(243 uri = reverse(
182244
=== modified file 'src/maasserver/api/vlans.py'
--- src/maasserver/api/vlans.py 2016-11-30 21:13:52 +0000
+++ src/maasserver/api/vlans.py 2016-12-06 16:09:53 +0000
@@ -27,6 +27,7 @@
27 'dhcp_on',27 'dhcp_on',
28 'external_dhcp',28 'external_dhcp',
29 'relay_vlan',29 'relay_vlan',
30 'space',
30)31)
3132
3233
@@ -55,6 +56,13 @@
55 else:56 else:
56 return None57 return None
5758
59 @classmethod
60 def space(handler, vlan):
61 if vlan.space:
62 return vlan.space.get_name()
63 else:
64 return None
65
58 def read(self, request, fabric_id):66 def read(self, request, fabric_id):
59 """List all VLANs belonging to fabric.67 """List all VLANs belonging to fabric.
6068
@@ -113,6 +121,13 @@
113 return None121 return None
114122
115 @classmethod123 @classmethod
124 def space(handler, vlan):
125 if vlan.space:
126 return vlan.space.get_name()
127 else:
128 return None
129
130 @classmethod
116 def fabric(cls, vlan):131 def fabric(cls, vlan):
117 """Return fabric name."""132 """Return fabric name."""
118 return vlan.fabric.get_name()133 return vlan.fabric.get_name()
119134
=== modified file 'src/maasserver/forms_vlan.py'
--- src/maasserver/forms_vlan.py 2016-11-30 16:42:37 +0000
+++ src/maasserver/forms_vlan.py 2016-12-06 16:09:53 +0000
@@ -11,7 +11,10 @@
11from django.core.exceptions import ValidationError11from django.core.exceptions import ValidationError
12from maasserver.fields import NodeChoiceField12from maasserver.fields import NodeChoiceField
13from maasserver.forms import MAASModelForm13from maasserver.forms import MAASModelForm
14from maasserver.models import RackController14from maasserver.models import (
15 RackController,
16 Space,
17)
15from maasserver.models.vlan import VLAN18from maasserver.models.vlan import VLAN
1619
1720
@@ -21,6 +24,9 @@
21 # Linux doesn't allow lower than 552 for the MTU.24 # Linux doesn't allow lower than 552 for the MTU.
22 mtu = forms.IntegerField(min_value=552, required=False)25 mtu = forms.IntegerField(min_value=552, required=False)
2326
27 space = forms.ModelChoiceField(
28 queryset=Space.objects.all(), required=False)
29
24 class Meta:30 class Meta:
25 model = VLAN31 model = VLAN
26 fields = (32 fields = (
@@ -32,6 +38,7 @@
32 'primary_rack',38 'primary_rack',
33 'secondary_rack',39 'secondary_rack',
34 'relay_vlan',40 'relay_vlan',
41 'space',
35 )42 )
3643
37 def __init__(self, *args, **kwargs):44 def __init__(self, *args, **kwargs):
@@ -134,16 +141,20 @@
134 "dhcp can only be turned on when a dynamic IP range is defined.")141 "dhcp can only be turned on when a dynamic IP range is defined.")
135142
136 def save(self):143 def save(self):
137 """Persist the interface into the database."""144 """Persist the VLAN into the database."""
138 interface = super(VLANForm, self).save(commit=False)145 vlan = super(VLANForm, self).save(commit=False)
139 if self.fabric is not None:146 if self.fabric is not None:
140 interface.fabric = self.fabric147 vlan.fabric = self.fabric
148 if ('space' in self.data and
149 not self.cleaned_data.get('space')):
150 # 'space' is being cleared.
151 vlan.space = None
141 if ('relay_vlan' in self.data and152 if ('relay_vlan' in self.data and
142 not self.cleaned_data.get('relay_vlan')):153 not self.cleaned_data.get('relay_vlan')):
143 # relay_vlan is being cleared.154 # 'relay_vlan' is being cleared.
144 interface.relay_vlan = None155 vlan.relay_vlan = None
145 if interface.dhcp_on:156 if vlan.dhcp_on:
146 # relay_vlan cannot be set when dhcp is on.157 # 'relay_vlan' cannot be set when dhcp is on.
147 interface.relay_vlan = None158 vlan.relay_vlan = None
148 interface.save()159 vlan.save()
149 return interface160 return vlan
150161
=== modified file 'src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py'
--- src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py 2016-12-05 14:56:57 +0000
+++ src/maasserver/migrations/builtin/maasserver/0096_set_default_vlan_field.py 2016-12-06 16:09:53 +0000
@@ -6,7 +6,6 @@
6 models,6 models,
7)7)
8import django.db.models.deletion8import django.db.models.deletion
9import maasserver.models.subnet
109
1110
12class Migration(migrations.Migration):11class Migration(migrations.Migration):
@@ -19,6 +18,6 @@
19 migrations.AlterField(18 migrations.AlterField(
20 model_name='subnet',19 model_name='subnet',
21 name='vlan',20 name='vlan',
22 field=models.ForeignKey(to='maasserver.VLAN', default=maasserver.models.subnet.get_default_vlan, on_delete=django.db.models.deletion.PROTECT),21 field=models.ForeignKey(to='maasserver.VLAN', default=lambda: 0, on_delete=django.db.models.deletion.PROTECT),
23 ),22 ),
24 ]23 ]
2524
=== added file 'src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py'
--- src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/migrations/builtin/maasserver/0098_add_space_to_vlan.py 2016-12-06 16:09:53 +0000
@@ -0,0 +1,24 @@
1# -*- coding: utf-8 -*-
2from __future__ import unicode_literals
3
4from django.db import (
5 migrations,
6 models,
7)
8import django.db.models.deletion
9import maasserver.models.subnet
10
11
12class Migration(migrations.Migration):
13
14 dependencies = [
15 ('maasserver', '0097_node_chassis_storage_hints'),
16 ]
17
18 operations = [
19 migrations.AddField(
20 model_name='vlan',
21 name='space',
22 field=models.ForeignKey(blank=True, null=True, to='maasserver.Space', on_delete=django.db.models.deletion.SET_NULL),
23 ),
24 ]
025
=== added file 'src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py'
--- src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/migrations/builtin/maasserver/0099_set_default_vlan_field.py 2016-12-06 16:09:53 +0000
@@ -0,0 +1,24 @@
1# -*- coding: utf-8 -*-
2from __future__ import unicode_literals
3
4from django.db import (
5 migrations,
6 models,
7)
8import django.db.models.deletion
9import maasserver.models.subnet
10
11
12class Migration(migrations.Migration):
13
14 dependencies = [
15 ('maasserver', '0098_add_space_to_vlan'),
16 ]
17
18 operations = [
19 migrations.AlterField(
20 model_name='subnet',
21 name='vlan',
22 field=models.ForeignKey(to='maasserver.VLAN', on_delete=django.db.models.deletion.PROTECT, default=maasserver.models.subnet.get_default_vlan),
23 ),
24 ]
025
=== modified file 'src/maasserver/models/vlan.py'
--- src/maasserver/models/vlan.py 2016-12-01 14:12:32 +0000
+++ src/maasserver/models/vlan.py 2016-12-06 16:09:53 +0000
@@ -19,6 +19,7 @@
19 IntegerField,19 IntegerField,
20 Manager,20 Manager,
21 Q,21 Q,
22 SET_NULL,
22 TextField,23 TextField,
23)24)
24from django.db.models.query import QuerySet25from django.db.models.query import QuerySet
@@ -174,6 +175,9 @@
174 'self', null=True, blank=True, editable=True,175 'self', null=True, blank=True, editable=True,
175 related_name='relay_vlans', on_delete=deletion.SET_NULL)176 related_name='relay_vlans', on_delete=deletion.SET_NULL)
176177
178 space = ForeignKey(
179 'Space', editable=True, blank=True, null=True, on_delete=SET_NULL)
180
177 def __str__(self):181 def __str__(self):
178 return "%s.%s" % (self.fabric.get_name(), self.get_name())182 return "%s.%s" % (self.fabric.get_name(), self.get_name())
179183
180184
=== modified file 'src/maasserver/static/partials/vlan-details.html'
--- src/maasserver/static/partials/vlan-details.html 2016-12-06 07:32:14 +0000
+++ src/maasserver/static/partials/vlan-details.html 2016-12-06 16:09:53 +0000
@@ -232,6 +232,9 @@
232 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>232 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>
233 <maas-obj-field type="text" key="mtu" label="MTU" placeholder="VLAN MTU"233 <maas-obj-field type="text" key="mtu" label="MTU" placeholder="VLAN MTU"
234 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>234 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>
235 <maas-obj-field type="options" key="space" label="Space" placeholder="(not in a space)" placeholder-enabled="true"
236 options="space.id as space.name for space in vlanDetails.spaces"
237 label-width="two" input-width="three"></maas-obj-field>
235 <maas-obj-field type="textarea" key="description" label="Description" placeholder="VLAN description"238 <maas-obj-field type="textarea" key="description" label="Description" placeholder="VLAN description"
236 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>239 label-width="two" input-width="three" blur-on-enter="true"></maas-obj-field>
237 </fieldset>240 </fieldset>
238241
=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py 2016-12-06 09:34:06 +0000
+++ src/maasserver/testing/factory.py 2016-12-06 16:09:53 +0000
@@ -1037,7 +1037,7 @@
1037 "Could not generate vid in fabric %s" % fabric)1037 "Could not generate vid in fabric %s" % fabric)
10381038
1039 def make_VLAN(1039 def make_VLAN(
1040 self, name=None, vid=None, fabric=None, dhcp_on=False,1040 self, name=None, vid=None, fabric=None, dhcp_on=False, space=None,
1041 primary_rack=None, secondary_rack=None, relay_vlan=None):1041 primary_rack=None, secondary_rack=None, relay_vlan=None):
1042 assert vid != 0, "VID=0 VLANs are auto-created"1042 assert vid != 0, "VID=0 VLANs are auto-created"
1043 if fabric is None:1043 if fabric is None:
@@ -1046,7 +1046,7 @@
1046 # Don't create the vid=0 VLAN, it's auto-created.1046 # Don't create the vid=0 VLAN, it's auto-created.
1047 vid = self._get_available_vid(fabric)1047 vid = self._get_available_vid(fabric)
1048 vlan = VLAN(1048 vlan = VLAN(
1049 name=name, vid=vid, fabric=fabric, dhcp_on=dhcp_on,1049 name=name, vid=vid, fabric=fabric, dhcp_on=dhcp_on, space=space,
1050 primary_rack=primary_rack, secondary_rack=secondary_rack,1050 primary_rack=primary_rack, secondary_rack=secondary_rack,
1051 relay_vlan=relay_vlan)1051 relay_vlan=relay_vlan)
1052 vlan.save()1052 vlan.save()
10531053
=== modified file 'src/maasserver/tests/test_forms_vlan.py'
--- src/maasserver/tests/test_forms_vlan.py 2016-11-30 16:42:37 +0000
+++ src/maasserver/tests/test_forms_vlan.py 2016-12-06 16:09:53 +0000
@@ -266,6 +266,39 @@
266 vlan = reload_object(vlan)266 vlan = reload_object(vlan)
267 self.assertIsNone(vlan.relay_vlan)267 self.assertIsNone(vlan.relay_vlan)
268268
269 def test_update_sets_space(self):
270 vlan = factory.make_VLAN()
271 space = factory.make_Space()
272 form = VLANForm(instance=vlan, data={
273 "space": space.id,
274 })
275 self.assertTrue(form.is_valid(), form.errors)
276 form.save()
277 vlan = reload_object(vlan)
278 self.assertEquals(space.id, vlan.space.id)
279
280 def test_update_clears_space_when_None(self):
281 space = factory.make_Space()
282 vlan = factory.make_VLAN(space=space)
283 form = VLANForm(instance=vlan, data={
284 "space": None,
285 })
286 self.assertTrue(form.is_valid(), form.errors)
287 form.save()
288 vlan = reload_object(vlan)
289 self.assertIsNone(vlan.space)
290
291 def test_update_clears_space_vlan_when_empty(self):
292 space = factory.make_Space()
293 vlan = factory.make_VLAN(space=space)
294 form = VLANForm(instance=vlan, data={
295 "space": "",
296 })
297 self.assertTrue(form.is_valid(), form.errors)
298 form.save()
299 vlan = reload_object(vlan)
300 self.assertIsNone(vlan.space)
301
269 def test_update_disables_relay_vlan_when_dhcp_turned_on(self):302 def test_update_disables_relay_vlan_when_dhcp_turned_on(self):
270 relay_vlan = factory.make_VLAN()303 relay_vlan = factory.make_VLAN()
271 vlan = factory.make_VLAN(relay_vlan=relay_vlan)304 vlan = factory.make_VLAN(relay_vlan=relay_vlan)
272305
=== modified file 'src/maasserver/websockets/handlers/tests/test_vlan.py'
--- src/maasserver/websockets/handlers/tests/test_vlan.py 2016-12-06 08:04:18 +0000
+++ src/maasserver/websockets/handlers/tests/test_vlan.py 2016-12-06 16:09:53 +0000
@@ -36,6 +36,7 @@
36 "vid": vlan.vid,36 "vid": vlan.vid,
37 "mtu": vlan.mtu,37 "mtu": vlan.mtu,
38 "fabric": vlan.fabric_id,38 "fabric": vlan.fabric_id,
39 "space": vlan.space_id,
39 "updated": dehydrate_datetime(vlan.updated),40 "updated": dehydrate_datetime(vlan.updated),
40 "created": dehydrate_datetime(vlan.created),41 "created": dehydrate_datetime(vlan.created),
41 "dhcp_on": vlan.dhcp_on,42 "dhcp_on": vlan.dhcp_on,