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
1=== modified file 'src/maasserver/api/tests/test_nodes.py'
2--- src/maasserver/api/tests/test_nodes.py 2014-09-22 05:33:12 +0000
3+++ src/maasserver/api/tests/test_nodes.py 2014-09-22 07:17:20 +0000
4@@ -30,7 +30,10 @@
5 )
6 from maasserver.exceptions import ClusterUnavailable
7 from maasserver.fields import MAC
8-from maasserver.models import Node
9+from maasserver.models import (
10+ Node,
11+ NodeGroup,
12+ )
13 from maasserver.models.node import RELEASABLE_STATUSES
14 from maasserver.models.user import (
15 create_auth_token,
16@@ -159,17 +162,29 @@
17
18 def test_POST_new_creates_node(self):
19 # The API allows a non-admin logged-in user to create a Node.
20+ hostname = factory.make_name('host')
21+ architecture = make_usable_architecture(self)
22+ macs = {
23+ factory.make_mac_address()
24+ for _ in range(random.randint(1, 2))
25+ }
26 response = self.client.post(
27 reverse('nodes_handler'),
28 {
29 'op': 'new',
30 'autodetect_nodegroup': '1',
31- 'hostname': factory.make_string(),
32- 'architecture': make_usable_architecture(self),
33- 'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],
34+ 'hostname': hostname,
35+ 'architecture': architecture,
36+ 'mac_addresses': macs,
37 })
38-
39 self.assertEqual(httplib.OK, response.status_code)
40+ system_id = json.loads(response.content)['system_id']
41+ node = Node.objects.get(system_id=system_id)
42+ self.expectThat(node.hostname, Equals(hostname))
43+ self.expectThat(node.architecture, Equals(architecture))
44+ self.expectThat(
45+ {mac.mac_address for mac in node.macaddress_set.all()},
46+ Equals(macs))
47
48 def test_POST_new_when_logged_in_creates_node_in_declared_state(self):
49 # When a user enlists a node, it goes into the New state.
50@@ -179,9 +194,9 @@
51 {
52 'op': 'new',
53 'autodetect_nodegroup': '1',
54- 'hostname': factory.make_string(),
55+ 'hostname': factory.make_name('host'),
56 'architecture': make_usable_architecture(self),
57- 'mac_addresses': ['aa:bb:cc:dd:ee:ff'],
58+ 'mac_addresses': [factory.make_mac_address()],
59 })
60 self.assertEqual(httplib.OK, response.status_code)
61 system_id = json.loads(response.content)['system_id']
62@@ -189,6 +204,41 @@
63 NODE_STATUS.NEW,
64 Node.objects.get(system_id=system_id).status)
65
66+ def test_POST_new_takes_default_for_disable_ipv4_from_given_cluster(self):
67+ default_disable_ipv4 = factory.pick_bool()
68+ cluster = factory.make_NodeGroup(
69+ default_disable_ipv4=default_disable_ipv4)
70+ response = self.client.post(
71+ reverse('nodes_handler'),
72+ {
73+ 'op': 'new',
74+ 'nodegroup': cluster.id,
75+ 'architecture': make_usable_architecture(self),
76+ 'mac_addresses': [factory.make_mac_address()],
77+ })
78+ self.assertEqual(httplib.OK, response.status_code)
79+ system_id = json.loads(response.content)['system_id']
80+ node = Node.objects.get(system_id=system_id)
81+ self.assertEqual(default_disable_ipv4, node.disable_ipv4)
82+
83+ def test_POST_new_takes_default_disable_ipv4_from_guessed_cluster(self):
84+ default_disable_ipv4 = factory.pick_bool()
85+ master_cluster = NodeGroup.objects.ensure_master()
86+ master_cluster.default_disable_ipv4 = default_disable_ipv4
87+ master_cluster.save()
88+ response = self.client.post(
89+ reverse('nodes_handler'),
90+ {
91+ 'op': 'new',
92+ 'autodetect_nodegroup': '1',
93+ 'architecture': make_usable_architecture(self),
94+ 'mac_addresses': [factory.make_mac_address()],
95+ })
96+ self.assertEqual(httplib.OK, response.status_code)
97+ system_id = json.loads(response.content)['system_id']
98+ node = Node.objects.get(system_id=system_id)
99+ self.assertEqual(default_disable_ipv4, node.disable_ipv4)
100+
101 def test_POST_new_when_no_RPC_to_cluster_defaults_empty_power(self):
102 # Test for bug 1305061, if there is no cluster RPC connection
103 # then make sure that power_type is defaulted to the empty
104
105=== modified file 'src/maasserver/forms.py'
106--- src/maasserver/forms.py 2014-09-17 13:18:15 +0000
107+++ src/maasserver/forms.py 2014-09-22 07:17:20 +0000
108@@ -283,8 +283,11 @@
109 # Even though it doesn't need it and doesn't use it, this form accepts
110 # a parameter named 'request' because it is used interchangingly
111 # with NodeAdminForm which actually uses this parameter.
112- if kwargs.get('instance') is None:
113- # Creating a new node. Offer choice of nodegroup.
114+
115+ # Are we creating a new node object?
116+ self.new_node = (kwargs.get('instance') is None)
117+ if self.new_node:
118+ # Offer choice of nodegroup.
119 self.fields['nodegroup'] = NodeGroupFormField(
120 required=False, empty_label="Default (master)")
121 self.set_up_architecture_field()
122@@ -372,6 +375,15 @@
123 def clean_distro_series(self):
124 return clean_distro_series_field(self, 'distro_series', 'osystem')
125
126+ def clean(self):
127+ cleaned_data = super(NodeForm, self).clean()
128+ if self.new_node and self.data.get('disable_ipv4') is None:
129+ # Creating a new node, without a value for disable_ipv4 given.
130+ # Take the default value from the node's cluster.
131+ nodegroup = cleaned_data['nodegroup']
132+ cleaned_data['disable_ipv4'] = nodegroup.default_disable_ipv4
133+ return cleaned_data
134+
135 def is_valid(self):
136 is_valid = super(NodeForm, self).is_valid()
137 if len(list_all_usable_architectures()) == 0:
138
139=== modified file 'src/maasserver/tests/test_forms_node.py'
140--- src/maasserver/tests/test_forms_node.py 2014-09-15 14:28:28 +0000
141+++ src/maasserver/tests/test_forms_node.py 2014-09-22 07:17:20 +0000
142@@ -262,6 +262,43 @@
143 form.instance.nodegroup = nodegroup
144 self.assertFalse(form.is_valid())
145
146+ def test_obeys_disable_ipv4_if_given(self):
147+ setting = factory.pick_bool()
148+ cluster = factory.make_NodeGroup(default_disable_ipv4=(not setting))
149+ form = NodeForm(
150+ data={
151+ 'nodegroup': cluster,
152+ 'architecture': make_usable_architecture(self),
153+ 'disable_ipv4': setting,
154+ })
155+ form.instance.nodegroup = cluster
156+ node = form.save()
157+ self.assertEqual(setting, node.disable_ipv4)
158+
159+ def test_takes_True_disable_ipv4_from_cluster_by_default(self):
160+ setting = True
161+ cluster = factory.make_NodeGroup(default_disable_ipv4=setting)
162+ form = NodeForm(
163+ data={
164+ 'nodegroup': cluster,
165+ 'architecture': make_usable_architecture(self),
166+ })
167+ form.instance.nodegroup = cluster
168+ node = form.save()
169+ self.assertEqual(setting, node.disable_ipv4)
170+
171+ def test_takes_False_disable_ipv4_from_cluster_by_default(self):
172+ setting = False
173+ cluster = factory.make_NodeGroup(default_disable_ipv4=setting)
174+ form = NodeForm(
175+ data={
176+ 'nodegroup': cluster,
177+ 'architecture': make_usable_architecture(self),
178+ })
179+ form.instance.nodegroup = cluster
180+ node = form.save()
181+ self.assertEqual(setting, node.disable_ipv4)
182+
183
184 class TestAdminNodeForm(MAASServerTestCase):
185