Merge lp:~blake-rouse/maas/fix-1495849 into lp:~maas-committers/maas/trunk
- fix-1495849
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Blake Rouse | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 4265 | ||||
Proposed branch: | lp:~blake-rouse/maas/fix-1495849 | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
290 lines (+199/-9) 4 files modified
src/maasserver/api/subnets.py (+9/-2) src/maasserver/api/tests/test_subnets.py (+0/-2) src/maasserver/forms_subnet.py (+64/-2) src/maasserver/tests/test_forms_subnet.py (+126/-3) |
||||
To merge this branch: | bzr merge lp:~blake-rouse/maas/fix-1495849 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andres Rodriguez (community) | Approve | ||
Review via email: mp+271141@code.launchpad.net |
Commit message
Improve the subnet API to give better parameters to make creating subnets easier.
Description of the change
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~blake-rouse/maas/fix-1495849 into lp:maas failed. Below is the output from the failed tests.
Ign http://
Ign http://
Hit http://
Hit http://
Ign http://
Hit http://
Get:1 http://
Hit http://
Hit http://
Get:2 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Get:3 http://
Get:4 http://
Get:5 http://
Get:6 http://
Hit http://
Hit http://
Ign http://
Ign http://
Fetched 1,365 kB in 3s (438 kB/s)
Reading package lists...
sudo DEBIAN_
--
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~blake-rouse/maas/fix-1495849 into lp:maas failed. Below is the output from the failed tests.
Ign http://
Hit http://
Ign http://
Hit http://
Ign http://
Hit http://
Get:1 http://
Hit http://
Get:2 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Get:3 http://
Get:4 http://
Get:5 http://
Get:6 http://
Hit http://
Hit http://
Ign http://
Ign http://
Fetched 1,365 kB in 3s (404 kB/s)
Reading package lists...
sudo DEBIAN_
--
Preview Diff
1 | === modified file 'src/maasserver/api/subnets.py' |
2 | --- src/maasserver/api/subnets.py 2015-09-01 19:21:50 +0000 |
3 | +++ src/maasserver/api/subnets.py 2015-09-15 16:27:58 +0000 |
4 | @@ -55,8 +55,15 @@ |
5 | """Create a subnet. |
6 | |
7 | :param name: Name of the subnet. |
8 | - :param vlan: VLAN this subnet belongs to. |
9 | - :param space: Space this subnet is in. |
10 | + :param fabric: Fabric for the subnet. Defaults to the fabric the |
11 | + provided VLAN belongs to or defaults to the default fabric. |
12 | + :param vlan: VLAN this subnet belongs to. Defaults to the default |
13 | + VLAN for the provided fabric or defaults to the default VLAN in |
14 | + the default fabric. |
15 | + :param vid: VID of the VLAN this subnet belongs to. Only used when |
16 | + vlan is not provided. Picks the VLAN with this VID in the provided |
17 | + fabric or the default fabric if one is not given. |
18 | + :param space: Space this subnet is in. Defaults to the default space. |
19 | :param cidr: The network CIDR for this subnet. |
20 | :param gateway_ip: The gateway IP address for this subnet. |
21 | :param dns_servers: Comma-seperated list of DNS servers for this \ |
22 | |
23 | === modified file 'src/maasserver/api/tests/test_subnets.py' |
24 | --- src/maasserver/api/tests/test_subnets.py 2015-09-02 02:56:11 +0000 |
25 | +++ src/maasserver/api/tests/test_subnets.py 2015-09-15 16:27:58 +0000 |
26 | @@ -111,8 +111,6 @@ |
27 | self.assertEqual( |
28 | httplib.BAD_REQUEST, response.status_code, response.content) |
29 | self.assertEqual({ |
30 | - "vlan": ["This field is required."], |
31 | - "space": ["This field is required."], |
32 | "cidr": ["This field is required."], |
33 | }, json.loads(response.content)) |
34 | |
35 | |
36 | === modified file 'src/maasserver/forms_subnet.py' |
37 | --- src/maasserver/forms_subnet.py 2015-09-02 02:56:11 +0000 |
38 | +++ src/maasserver/forms_subnet.py 2015-09-15 16:27:58 +0000 |
39 | @@ -18,19 +18,28 @@ |
40 | |
41 | from django import forms |
42 | from maasserver.forms import MAASModelForm |
43 | +from maasserver.models.fabric import Fabric |
44 | from maasserver.models.space import Space |
45 | from maasserver.models.subnet import Subnet |
46 | from maasserver.models.vlan import VLAN |
47 | +from maasserver.utils.forms import set_form_error |
48 | +from maasserver.utils.orm import get_one |
49 | |
50 | |
51 | class SubnetForm(MAASModelForm): |
52 | """Subnet creation/edition form.""" |
53 | |
54 | + fabric = forms.ModelChoiceField( |
55 | + queryset=Fabric.objects.all(), required=False) |
56 | + |
57 | vlan = forms.ModelChoiceField( |
58 | - queryset=VLAN.objects.all(), required=True) |
59 | + queryset=VLAN.objects.all(), required=False) |
60 | + |
61 | + vid = forms.IntegerField( |
62 | + min_value=0, max_value=4095, required=False) |
63 | |
64 | space = forms.ModelChoiceField( |
65 | - queryset=Space.objects.all(), required=True) |
66 | + queryset=Space.objects.all(), required=False) |
67 | |
68 | class Meta: |
69 | model = Subnet |
70 | @@ -49,6 +58,16 @@ |
71 | |
72 | def clean(self): |
73 | cleaned_data = super(SubnetForm, self).clean() |
74 | + cleaned_data = self._clean_name(cleaned_data) |
75 | + if self.instance.id is None: |
76 | + # We only allow the helpers when creating. When updating we require |
77 | + # the VLAN specifically. This is because we cannot make a correct |
78 | + # determination on what should be done in this case. |
79 | + cleaned_data = self._clean_vlan(cleaned_data) |
80 | + cleaned_data = self._clean_space(cleaned_data) |
81 | + return cleaned_data |
82 | + |
83 | + def _clean_name(self, cleaned_data): |
84 | name = cleaned_data.get("name", None) |
85 | instance_name_and_cidr_match = ( |
86 | self.instance.id is not None and |
87 | @@ -62,3 +81,46 @@ |
88 | # Update the subnet to have the same name as its cidr. |
89 | cleaned_data["name"] = cleaned_data["cidr"] |
90 | return cleaned_data |
91 | + |
92 | + def _clean_vlan(self, cleaned_data): |
93 | + fabric = cleaned_data.get("fabric", None) |
94 | + vlan = cleaned_data.get("vlan", None) |
95 | + vid = cleaned_data.get("vid", None) |
96 | + if fabric is None and vlan is None: |
97 | + if not vid: |
98 | + cleaned_data["vlan"] = ( |
99 | + Fabric.objects.get_default_fabric().get_default_vlan()) |
100 | + else: |
101 | + vlan = get_one( |
102 | + VLAN.objects.filter( |
103 | + fabric=Fabric.objects.get_default_fabric(), vid=vid)) |
104 | + if vlan is None: |
105 | + set_form_error( |
106 | + self, "vid", |
107 | + "No VLAN with vid %s in default fabric." % vid) |
108 | + else: |
109 | + cleaned_data["vlan"] = vlan |
110 | + elif fabric is not None: |
111 | + if vlan is None: |
112 | + if not vid: |
113 | + cleaned_data["vlan"] = fabric.get_default_vlan() |
114 | + else: |
115 | + vlan = get_one(VLAN.objects.filter(fabric=fabric, vid=vid)) |
116 | + if vlan is None: |
117 | + set_form_error( |
118 | + self, "vid", |
119 | + "No VLAN with vid %s in fabric %s." % ( |
120 | + vid, fabric)) |
121 | + else: |
122 | + cleaned_data["vlan"] = vlan |
123 | + elif vlan.fabric_id != fabric.id: |
124 | + set_form_error( |
125 | + self, "vlan", |
126 | + "VLAN %s is not in fabric %s." % (vlan, fabric)) |
127 | + return cleaned_data |
128 | + |
129 | + def _clean_space(self, cleaned_data): |
130 | + space = cleaned_data.get("space", None) |
131 | + if space is None: |
132 | + cleaned_data["space"] = Space.objects.get_default_space() |
133 | + return cleaned_data |
134 | |
135 | === modified file 'src/maasserver/tests/test_forms_subnet.py' |
136 | --- src/maasserver/tests/test_forms_subnet.py 2015-09-02 02:56:11 +0000 |
137 | +++ src/maasserver/tests/test_forms_subnet.py 2015-09-15 16:27:58 +0000 |
138 | @@ -15,6 +15,8 @@ |
139 | __all__ = [] |
140 | |
141 | from maasserver.forms_subnet import SubnetForm |
142 | +from maasserver.models.fabric import Fabric |
143 | +from maasserver.models.space import Space |
144 | from maasserver.testing.factory import factory |
145 | from maasserver.testing.orm import reload_object |
146 | from maasserver.testing.testcase import MAASServerTestCase |
147 | @@ -23,12 +25,10 @@ |
148 | |
149 | class TestSubnetForm(MAASServerTestCase): |
150 | |
151 | - def test__requires_vlan_space_cidr(self): |
152 | + def test__requires_cidr(self): |
153 | form = SubnetForm({}) |
154 | self.assertFalse(form.is_valid(), form.errors) |
155 | self.assertEquals({ |
156 | - "vlan": ["This field is required."], |
157 | - "space": ["This field is required."], |
158 | "cidr": ["This field is required."], |
159 | }, form.errors) |
160 | |
161 | @@ -75,6 +75,129 @@ |
162 | subnet, MatchesStructure.byEquality( |
163 | name=cidr, vlan=vlan, space=space, cidr=cidr)) |
164 | |
165 | + def test__creates_subnet_in_default_space(self): |
166 | + vlan = factory.make_VLAN() |
167 | + network = factory.make_ip4_or_6_network() |
168 | + cidr = unicode(network.cidr) |
169 | + form = SubnetForm({ |
170 | + "vlan": vlan.id, |
171 | + "cidr": cidr, |
172 | + }) |
173 | + self.assertTrue(form.is_valid(), form.errors) |
174 | + subnet = form.save() |
175 | + self.assertThat( |
176 | + subnet, MatchesStructure.byEquality( |
177 | + name=cidr, vlan=vlan, cidr=cidr, |
178 | + space=Space.objects.get_default_space())) |
179 | + |
180 | + def test__creates_subnet_in_default_fabric_and_vlan(self): |
181 | + network = factory.make_ip4_or_6_network() |
182 | + cidr = unicode(network.cidr) |
183 | + form = SubnetForm({ |
184 | + "cidr": cidr, |
185 | + }) |
186 | + self.assertTrue(form.is_valid(), form.errors) |
187 | + subnet = form.save() |
188 | + self.assertThat( |
189 | + subnet, MatchesStructure.byEquality( |
190 | + name=cidr, cidr=cidr, |
191 | + vlan=Fabric.objects.get_default_fabric().get_default_vlan(), |
192 | + space=Space.objects.get_default_space())) |
193 | + |
194 | + def test__creates_subnet_in_default_vlan_in_fabric(self): |
195 | + fabric = factory.make_Fabric() |
196 | + network = factory.make_ip4_or_6_network() |
197 | + cidr = unicode(network.cidr) |
198 | + form = SubnetForm({ |
199 | + "cidr": cidr, |
200 | + "fabric": fabric.id, |
201 | + }) |
202 | + self.assertTrue(form.is_valid(), form.errors) |
203 | + subnet = form.save() |
204 | + self.assertThat( |
205 | + subnet, MatchesStructure.byEquality( |
206 | + name=cidr, cidr=cidr, |
207 | + vlan=fabric.get_default_vlan(), |
208 | + space=Space.objects.get_default_space())) |
209 | + |
210 | + def test__creates_subnet_in_default_fabric_with_vid(self): |
211 | + vlan = factory.make_VLAN(fabric=Fabric.objects.get_default_fabric()) |
212 | + network = factory.make_ip4_or_6_network() |
213 | + cidr = unicode(network.cidr) |
214 | + form = SubnetForm({ |
215 | + "cidr": cidr, |
216 | + "vid": vlan.vid, |
217 | + }) |
218 | + self.assertTrue(form.is_valid(), form.errors) |
219 | + subnet = form.save() |
220 | + self.assertThat( |
221 | + subnet, MatchesStructure.byEquality( |
222 | + name=cidr, cidr=cidr, |
223 | + vlan=vlan, |
224 | + space=Space.objects.get_default_space())) |
225 | + |
226 | + def test__creates_subnet_in_fabric_with_vid(self): |
227 | + fabric = factory.make_Fabric() |
228 | + vlan = factory.make_VLAN(fabric=fabric) |
229 | + network = factory.make_ip4_or_6_network() |
230 | + cidr = unicode(network.cidr) |
231 | + form = SubnetForm({ |
232 | + "cidr": cidr, |
233 | + "fabric": fabric.id, |
234 | + "vid": vlan.vid, |
235 | + }) |
236 | + self.assertTrue(form.is_valid(), form.errors) |
237 | + subnet = form.save() |
238 | + self.assertThat( |
239 | + subnet, MatchesStructure.byEquality( |
240 | + name=cidr, cidr=cidr, |
241 | + vlan=vlan, |
242 | + space=Space.objects.get_default_space())) |
243 | + |
244 | + def test__error_for_unknown_vid_in_default_fabric(self): |
245 | + fabric = factory.make_Fabric() |
246 | + vlan = factory.make_VLAN(fabric=fabric) |
247 | + network = factory.make_ip4_or_6_network() |
248 | + cidr = unicode(network.cidr) |
249 | + form = SubnetForm({ |
250 | + "cidr": cidr, |
251 | + "vid": vlan.vid, |
252 | + }) |
253 | + self.assertFalse(form.is_valid(), form.errors) |
254 | + self.assertEquals({ |
255 | + "vid": ["No VLAN with vid %s in default fabric." % vlan.vid] |
256 | + }, form.errors) |
257 | + |
258 | + def test__error_for_unknown_vid_in_fabric(self): |
259 | + fabric = factory.make_Fabric() |
260 | + vlan = factory.make_VLAN(fabric=Fabric.objects.get_default_fabric()) |
261 | + network = factory.make_ip4_or_6_network() |
262 | + cidr = unicode(network.cidr) |
263 | + form = SubnetForm({ |
264 | + "cidr": cidr, |
265 | + "fabric": fabric.id, |
266 | + "vid": vlan.vid, |
267 | + }) |
268 | + self.assertFalse(form.is_valid(), form.errors) |
269 | + self.assertEquals({ |
270 | + "vid": ["No VLAN with vid %s in fabric %s." % (vlan.vid, fabric)] |
271 | + }, form.errors) |
272 | + |
273 | + def test__error_for_vlan_not_in_fabric(self): |
274 | + fabric = factory.make_Fabric() |
275 | + vlan = factory.make_VLAN(fabric=Fabric.objects.get_default_fabric()) |
276 | + network = factory.make_ip4_or_6_network() |
277 | + cidr = unicode(network.cidr) |
278 | + form = SubnetForm({ |
279 | + "cidr": cidr, |
280 | + "fabric": fabric.id, |
281 | + "vlan": vlan.id, |
282 | + }) |
283 | + self.assertFalse(form.is_valid(), form.errors) |
284 | + self.assertEquals({ |
285 | + "vlan": ["VLAN %s is not in fabric %s." % (vlan, fabric)] |
286 | + }, form.errors) |
287 | + |
288 | def test__doest_require_vlan_space_or_cidr_on_update(self): |
289 | subnet = factory.make_Subnet() |
290 | form = SubnetForm(instance=subnet, data={}) |
lgtm!