Merge lp:~jtv/maas/take-node-disable-ipv4-from-nodegroup into lp:~maas-committers/maas/trunk

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 3051
Proposed branch: lp:~jtv/maas/take-node-disable-ipv4-from-nodegroup
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 184 lines (+108/-9)
3 files modified
src/maasserver/api/tests/test_nodes.py (+57/-7)
src/maasserver/forms.py (+14/-2)
src/maasserver/tests/test_forms_node.py (+37/-0)
To merge this branch: bzr merge lp:~jtv/maas/take-node-disable-ipv4-from-nodegroup
Reviewer Review Type Date Requested Status
Graham Binns (community) Approve
Review via email: mp+235426@code.launchpad.net

Commit message

Make Node.disable_ipv4 default to NodeGroup.default_disable_ipv4 (on the node's own nodegroup). This allows users to set cluster-wide default policies for whether IPv4 should be disabled on deployed nodes.

Description of the change

Doing this on the form seemed more appropriate to me than doing it on the model: this default value is basically a user-interface concept. Making such connections between model objects during model cleaning seems altogether too intricate.

The UI for disabling IPv4 is still hidden behind the REVEAL_IPv6 feature flag, and this new default setting does not have any UI at all yet. We can change that in a later branch.

While I was there I also updated some existing Node API tests with factory helpers we didn't have at the time, and made the basic test for creating a node through the API verify that the node actually gets created.

Jeroen

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
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_nodes.py'
--- src/maasserver/api/tests/test_nodes.py 2014-09-22 05:33:12 +0000
+++ src/maasserver/api/tests/test_nodes.py 2014-09-22 07:17:20 +0000
@@ -30,7 +30,10 @@
30 )30 )
31from maasserver.exceptions import ClusterUnavailable31from maasserver.exceptions import ClusterUnavailable
32from maasserver.fields import MAC32from maasserver.fields import MAC
33from maasserver.models import Node33from maasserver.models import (
34 Node,
35 NodeGroup,
36 )
34from maasserver.models.node import RELEASABLE_STATUSES37from maasserver.models.node import RELEASABLE_STATUSES
35from maasserver.models.user import (38from maasserver.models.user import (
36 create_auth_token,39 create_auth_token,
@@ -159,17 +162,29 @@
159162
160 def test_POST_new_creates_node(self):163 def test_POST_new_creates_node(self):
161 # The API allows a non-admin logged-in user to create a Node.164 # The API allows a non-admin logged-in user to create a Node.
165 hostname = factory.make_name('host')
166 architecture = make_usable_architecture(self)
167 macs = {
168 factory.make_mac_address()
169 for _ in range(random.randint(1, 2))
170 }
162 response = self.client.post(171 response = self.client.post(
163 reverse('nodes_handler'),172 reverse('nodes_handler'),
164 {173 {
165 'op': 'new',174 'op': 'new',
166 'autodetect_nodegroup': '1',175 'autodetect_nodegroup': '1',
167 'hostname': factory.make_string(),176 'hostname': hostname,
168 'architecture': make_usable_architecture(self),177 'architecture': architecture,
169 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],178 'mac_addresses': macs,
170 })179 })
171
172 self.assertEqual(httplib.OK, response.status_code)180 self.assertEqual(httplib.OK, response.status_code)
181 system_id = json.loads(response.content)['system_id']
182 node = Node.objects.get(system_id=system_id)
183 self.expectThat(node.hostname, Equals(hostname))
184 self.expectThat(node.architecture, Equals(architecture))
185 self.expectThat(
186 {mac.mac_address for mac in node.macaddress_set.all()},
187 Equals(macs))
173188
174 def test_POST_new_when_logged_in_creates_node_in_declared_state(self):189 def test_POST_new_when_logged_in_creates_node_in_declared_state(self):
175 # When a user enlists a node, it goes into the New state.190 # When a user enlists a node, it goes into the New state.
@@ -179,9 +194,9 @@
179 {194 {
180 'op': 'new',195 'op': 'new',
181 'autodetect_nodegroup': '1',196 'autodetect_nodegroup': '1',
182 'hostname': factory.make_string(),197 'hostname': factory.make_name('host'),
183 'architecture': make_usable_architecture(self),198 'architecture': make_usable_architecture(self),
184 'mac_addresses': ['aa:bb:cc:dd:ee:ff'],199 'mac_addresses': [factory.make_mac_address()],
185 })200 })
186 self.assertEqual(httplib.OK, response.status_code)201 self.assertEqual(httplib.OK, response.status_code)
187 system_id = json.loads(response.content)['system_id']202 system_id = json.loads(response.content)['system_id']
@@ -189,6 +204,41 @@
189 NODE_STATUS.NEW,204 NODE_STATUS.NEW,
190 Node.objects.get(system_id=system_id).status)205 Node.objects.get(system_id=system_id).status)
191206
207 def test_POST_new_takes_default_for_disable_ipv4_from_given_cluster(self):
208 default_disable_ipv4 = factory.pick_bool()
209 cluster = factory.make_NodeGroup(
210 default_disable_ipv4=default_disable_ipv4)
211 response = self.client.post(
212 reverse('nodes_handler'),
213 {
214 'op': 'new',
215 'nodegroup': cluster.id,
216 'architecture': make_usable_architecture(self),
217 'mac_addresses': [factory.make_mac_address()],
218 })
219 self.assertEqual(httplib.OK, response.status_code)
220 system_id = json.loads(response.content)['system_id']
221 node = Node.objects.get(system_id=system_id)
222 self.assertEqual(default_disable_ipv4, node.disable_ipv4)
223
224 def test_POST_new_takes_default_disable_ipv4_from_guessed_cluster(self):
225 default_disable_ipv4 = factory.pick_bool()
226 master_cluster = NodeGroup.objects.ensure_master()
227 master_cluster.default_disable_ipv4 = default_disable_ipv4
228 master_cluster.save()
229 response = self.client.post(
230 reverse('nodes_handler'),
231 {
232 'op': 'new',
233 'autodetect_nodegroup': '1',
234 'architecture': make_usable_architecture(self),
235 'mac_addresses': [factory.make_mac_address()],
236 })
237 self.assertEqual(httplib.OK, response.status_code)
238 system_id = json.loads(response.content)['system_id']
239 node = Node.objects.get(system_id=system_id)
240 self.assertEqual(default_disable_ipv4, node.disable_ipv4)
241
192 def test_POST_new_when_no_RPC_to_cluster_defaults_empty_power(self):242 def test_POST_new_when_no_RPC_to_cluster_defaults_empty_power(self):
193 # Test for bug 1305061, if there is no cluster RPC connection243 # Test for bug 1305061, if there is no cluster RPC connection
194 # then make sure that power_type is defaulted to the empty244 # then make sure that power_type is defaulted to the empty
195245
=== modified file 'src/maasserver/forms.py'
--- src/maasserver/forms.py 2014-09-17 13:18:15 +0000
+++ src/maasserver/forms.py 2014-09-22 07:17:20 +0000
@@ -283,8 +283,11 @@
283 # Even though it doesn't need it and doesn't use it, this form accepts283 # Even though it doesn't need it and doesn't use it, this form accepts
284 # a parameter named 'request' because it is used interchangingly284 # a parameter named 'request' because it is used interchangingly
285 # with NodeAdminForm which actually uses this parameter.285 # with NodeAdminForm which actually uses this parameter.
286 if kwargs.get('instance') is None:286
287 # Creating a new node. Offer choice of nodegroup.287 # Are we creating a new node object?
288 self.new_node = (kwargs.get('instance') is None)
289 if self.new_node:
290 # Offer choice of nodegroup.
288 self.fields['nodegroup'] = NodeGroupFormField(291 self.fields['nodegroup'] = NodeGroupFormField(
289 required=False, empty_label="Default (master)")292 required=False, empty_label="Default (master)")
290 self.set_up_architecture_field()293 self.set_up_architecture_field()
@@ -372,6 +375,15 @@
372 def clean_distro_series(self):375 def clean_distro_series(self):
373 return clean_distro_series_field(self, 'distro_series', 'osystem')376 return clean_distro_series_field(self, 'distro_series', 'osystem')
374377
378 def clean(self):
379 cleaned_data = super(NodeForm, self).clean()
380 if self.new_node and self.data.get('disable_ipv4') is None:
381 # Creating a new node, without a value for disable_ipv4 given.
382 # Take the default value from the node's cluster.
383 nodegroup = cleaned_data['nodegroup']
384 cleaned_data['disable_ipv4'] = nodegroup.default_disable_ipv4
385 return cleaned_data
386
375 def is_valid(self):387 def is_valid(self):
376 is_valid = super(NodeForm, self).is_valid()388 is_valid = super(NodeForm, self).is_valid()
377 if len(list_all_usable_architectures()) == 0:389 if len(list_all_usable_architectures()) == 0:
378390
=== modified file 'src/maasserver/tests/test_forms_node.py'
--- src/maasserver/tests/test_forms_node.py 2014-09-15 14:28:28 +0000
+++ src/maasserver/tests/test_forms_node.py 2014-09-22 07:17:20 +0000
@@ -262,6 +262,43 @@
262 form.instance.nodegroup = nodegroup262 form.instance.nodegroup = nodegroup
263 self.assertFalse(form.is_valid())263 self.assertFalse(form.is_valid())
264264
265 def test_obeys_disable_ipv4_if_given(self):
266 setting = factory.pick_bool()
267 cluster = factory.make_NodeGroup(default_disable_ipv4=(not setting))
268 form = NodeForm(
269 data={
270 'nodegroup': cluster,
271 'architecture': make_usable_architecture(self),
272 'disable_ipv4': setting,
273 })
274 form.instance.nodegroup = cluster
275 node = form.save()
276 self.assertEqual(setting, node.disable_ipv4)
277
278 def test_takes_True_disable_ipv4_from_cluster_by_default(self):
279 setting = True
280 cluster = factory.make_NodeGroup(default_disable_ipv4=setting)
281 form = NodeForm(
282 data={
283 'nodegroup': cluster,
284 'architecture': make_usable_architecture(self),
285 })
286 form.instance.nodegroup = cluster
287 node = form.save()
288 self.assertEqual(setting, node.disable_ipv4)
289
290 def test_takes_False_disable_ipv4_from_cluster_by_default(self):
291 setting = False
292 cluster = factory.make_NodeGroup(default_disable_ipv4=setting)
293 form = NodeForm(
294 data={
295 'nodegroup': cluster,
296 'architecture': make_usable_architecture(self),
297 })
298 form.instance.nodegroup = cluster
299 node = form.save()
300 self.assertEqual(setting, node.disable_ipv4)
301
265302
266class TestAdminNodeForm(MAASServerTestCase):303class TestAdminNodeForm(MAASServerTestCase):
267304