Merge lp:~julian-edwards/maas/enlist-nodegroup-bug-1274926 into lp:~maas-committers/maas/trunk
- enlist-nodegroup-bug-1274926
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Julian Edwards |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1928 |
Proposed branch: | lp:~julian-edwards/maas/enlist-nodegroup-bug-1274926 |
Merge into: | lp:~maas-committers/maas/trunk |
Diff against target: |
304 lines (+62/-0) 3 files modified
src/maasserver/api.py (+12/-0) src/maasserver/tests/test_api_enlistment.py (+47/-0) src/maasserver/tests/test_api_nodes.py (+3/-0) |
To merge this branch: | bzr merge lp:~julian-edwards/maas/enlist-nodegroup-bug-1274926 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeroen T. Vermeulen (community) | Approve | ||
Review via email: mp+205681@code.launchpad.net |
Commit message
Add a new parameter for node enlisting called "autodetect_
Description of the change
Julian Edwards (julian-edwards) wrote : | # |
Thanks for reviewing.
On Tuesday 11 Feb 2014 07:00:06 you wrote:
> Review: Approve
>
> Sensible change. I assume autodetection itself is already tested, in a test
> that needed no change. One thing that's a bit awkward (and I do see the
> XXX about it) is that the semantics of the autodetect_
> are only explained in the test. I think the representation of booleans is
> not very highly standardised, so it may be worth a note in the docstring
> even if the docstring does not cover all parameters.
I considered it but it felt daft to add just that one param and none of the
others, which is why I XXXed it for later! I'll stick it in the comment for
later inclusion in a decent docstring.
> For the error message in api.py, saying that the nodegroup parameter is
> missing may be too strong. There's a choice to be made. How about "one of
> nodegroup or autodetect_
The code doesn't enforce that though, it just enforces the former without the
latter.
I'll land this now and we can discuss a different message later, I gotta run.
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~julian-edwards/maas/enlist-nodegroup-bug-1274926 into lp:maas failed. Below is the output from the failed tests.
Ign http://
Hit http://
Ign http://
Hit http://
Ign http://
Get:1 http://
Hit http://
Get:2 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Get:3 http://
Ign http://
Ign http://
Get:4 http://
Get:5 http://
Get:6 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Ign http://
Ign http://
Ign http://
Ign http://
Fetched 14.7 MB in 5s (2,680 kB/s)
Reading package lists...
sudo DEBIAN_
--
Julian Edwards (julian-edwards) wrote : | # |
So it looks like tests for creating new nodes on the api are split between
test_api_
:/
Raphaël Badin (rvb) wrote : | # |
As discussed this morning, this change means earlier versions of maas-enlist will fail to register nodes (because the API call will not contain the 'autodetect_
Jorge Niedbalski (niedbalski) wrote : | # |
Hello guys,
Any way to workaround this ( using maasclient api) with pre-trusty versions?
Preview Diff
1 | === modified file 'src/maasserver/api.py' |
2 | --- src/maasserver/api.py 2014-02-11 08:23:05 +0000 |
3 | +++ src/maasserver/api.py 2014-02-11 23:37:14 +0000 |
4 | @@ -514,6 +514,13 @@ |
5 | # If 'nodegroup' is not explicitely specified, get the origin of the |
6 | # request to figure out which nodegroup the new node should be |
7 | # attached to. |
8 | + if request.data.get('autodetect_nodegroup', None) is None: |
9 | + # We insist on this to protect command-line API users who |
10 | + # are manually enlisting nodes. You can't use the origin's |
11 | + # IP address to indicate in which nodegroup the new node belongs. |
12 | + raise ValidationError( |
13 | + "'autodetect_nodegroup' must be specified if 'nodegroup' " |
14 | + "parameter missing") |
15 | nodegroup = find_nodegroup(request) |
16 | if nodegroup is not None: |
17 | altered_query_data['nodegroup'] = nodegroup |
18 | @@ -550,6 +557,11 @@ |
19 | the enlistment is done by a non-admin, the node is held in the |
20 | "Declared" state for approval by a MAAS admin. |
21 | """ |
22 | + # XXX 2014-02-11 bug=1278685 |
23 | + # There's no documentation here on what parameters can be passed! |
24 | + |
25 | + # Note that request.autodetect_nodegroup is treated as a |
26 | + # boolean; its presence indicates True. |
27 | return create_node(request) |
28 | |
29 | @operation(idempotent=True) |
30 | |
31 | === modified file 'src/maasserver/tests/test_api_enlistment.py' |
32 | --- src/maasserver/tests/test_api_enlistment.py 2014-02-01 04:04:37 +0000 |
33 | +++ src/maasserver/tests/test_api_enlistment.py 2014-02-11 23:37:14 +0000 |
34 | @@ -54,6 +54,7 @@ |
35 | reverse('nodes_handler'), |
36 | { |
37 | 'op': 'new', |
38 | + 'autodetect_nodegroup': '1', |
39 | 'hostname': 'diane', |
40 | 'architecture': architecture, |
41 | 'power_type': 'ether_wake', |
42 | @@ -76,6 +77,7 @@ |
43 | reverse('nodes_handler'), |
44 | { |
45 | 'op': 'new', |
46 | + 'autodetect_nodegroup': '1', |
47 | 'hostname': hostname, |
48 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
49 | 'power_type': 'ether_wake', |
50 | @@ -105,6 +107,7 @@ |
51 | reverse('nodes_handler'), |
52 | { |
53 | 'op': 'new', |
54 | + 'autodetect_nodegroup': '1', |
55 | 'hostname': hostname, |
56 | 'architecture': architecture, |
57 | 'power_type': 'ether_wake', |
58 | @@ -125,6 +128,7 @@ |
59 | reverse('nodes_handler'), |
60 | { |
61 | 'op': 'new', |
62 | + 'autodetect_nodegroup': '1', |
63 | 'hostname': 'diane', |
64 | 'architecture': architecture.split('/')[0], |
65 | 'power_type': 'ether_wake', |
66 | @@ -148,6 +152,7 @@ |
67 | reverse('nodes_handler'), |
68 | { |
69 | 'op': 'new', |
70 | + 'autodetect_nodegroup': '1', |
71 | 'hostname': 'diane', |
72 | 'architecture': architecture.split('/')[0], |
73 | 'subarchitecture': architecture.split('/')[1], |
74 | @@ -171,6 +176,7 @@ |
75 | reverse('nodes_handler'), |
76 | { |
77 | 'op': 'new', |
78 | + 'autodetect_nodegroup': '1', |
79 | 'hostname': 'diane', |
80 | 'architecture': architecture, |
81 | 'subarchitecture': architecture.split('/')[1], |
82 | @@ -192,6 +198,7 @@ |
83 | reverse('nodes_handler'), |
84 | { |
85 | 'op': 'new', |
86 | + 'autodetect_nodegroup': '1', |
87 | 'hostname': 'diane', |
88 | 'architecture': architecture, |
89 | 'after_commissioning_action': ( |
90 | @@ -209,6 +216,7 @@ |
91 | reverse('nodes_handler'), |
92 | { |
93 | 'op': 'new', |
94 | + 'autodetect_nodegroup': '1', |
95 | 'hostname': hostname, |
96 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
97 | 'mac_addresses': [factory.getRandomMACAddress()], |
98 | @@ -223,6 +231,7 @@ |
99 | reverse('nodes_handler'), |
100 | { |
101 | 'op': 'new', |
102 | + 'autodetect_nodegroup': '1', |
103 | 'architecture': architecture, |
104 | 'power_type': 'ether_wake', |
105 | 'mac_addresses': [factory.getRandomMACAddress()], |
106 | @@ -247,6 +256,26 @@ |
107 | "Unrecognised signature: POST None", |
108 | response.content) |
109 | |
110 | + def test_POST_new_fails_if_autodetect_nodegroup_required(self): |
111 | + # If new() is called with no nodegroup, we require the client to |
112 | + # explicitly also supply autodetect_nodegroup (with any value) |
113 | + # to force the autodetection. If it's not supplied then an error |
114 | + # is raised. |
115 | + architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES) |
116 | + response = self.client.post( |
117 | + reverse('nodes_handler'), |
118 | + { |
119 | + 'op': 'new', |
120 | + 'architecture': architecture, |
121 | + 'power_type': 'ether_wake', |
122 | + 'mac_addresses': [factory.getRandomMACAddress()], |
123 | + }) |
124 | + self.assertEqual(httplib.BAD_REQUEST, response.status_code) |
125 | + self.assertIn('text/plain', response['Content-Type']) |
126 | + self.assertEqual( |
127 | + "'autodetect_nodegroup' must be specified if 'nodegroup' " |
128 | + "parameter missing", response.content) |
129 | + |
130 | def test_POST_fails_if_mac_duplicated(self): |
131 | # Mac Addresses should be unique. |
132 | mac = 'aa:bb:cc:dd:ee:ff' |
133 | @@ -256,6 +285,7 @@ |
134 | reverse('nodes_handler'), |
135 | { |
136 | 'op': 'new', |
137 | + 'autodetect_nodegroup': '1', |
138 | 'architecture': architecture, |
139 | 'hostname': factory.getRandomString(), |
140 | 'mac_addresses': [mac], |
141 | @@ -275,6 +305,7 @@ |
142 | reverse('nodes_handler'), |
143 | { |
144 | 'op': 'invalid_operation', |
145 | + 'autodetect_nodegroup': '1', |
146 | 'hostname': 'diane', |
147 | 'mac_addresses': ['aa:bb:cc:dd:ee:ff', 'invalid'], |
148 | }) |
149 | @@ -291,6 +322,7 @@ |
150 | reverse('nodes_handler'), |
151 | { |
152 | 'op': 'new', |
153 | + 'autodetect_nodegroup': '1', |
154 | 'hostname': 'diane', |
155 | 'mac_addresses': ['aa:bb:cc:dd:ee:ff', 'invalid'], |
156 | }) |
157 | @@ -309,6 +341,7 @@ |
158 | reverse('nodes_handler'), |
159 | { |
160 | 'op': 'new', |
161 | + 'autodetect_nodegroup': '1', |
162 | 'hostname': 'diane', |
163 | 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], |
164 | 'architecture': 'invalid-architecture', |
165 | @@ -342,6 +375,7 @@ |
166 | reverse('nodes_handler'), |
167 | { |
168 | 'op': 'new', |
169 | + 'autodetect_nodegroup': '1', |
170 | 'hostname': hostname_with_domain, |
171 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
172 | 'power_type': 'ether_wake', |
173 | @@ -366,6 +400,7 @@ |
174 | reverse('nodes_handler'), |
175 | { |
176 | 'op': 'new', |
177 | + 'autodetect_nodegroup': '1', |
178 | 'hostname': hostname_without_domain, |
179 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
180 | 'power_type': 'ether_wake', |
181 | @@ -388,6 +423,7 @@ |
182 | reverse('nodes_handler'), |
183 | data={ |
184 | 'op': 'new', |
185 | + 'autodetect_nodegroup': '1', |
186 | 'hostname': factory.make_name('hostname'), |
187 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
188 | 'power_type': 'ether_wake', |
189 | @@ -407,6 +443,7 @@ |
190 | reverse('nodes_handler'), |
191 | data={ |
192 | 'op': 'new', |
193 | + 'autodetect_nodegroup': '1', |
194 | 'hostname': factory.make_name('hostname'), |
195 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
196 | 'power_type': 'ether_wake', |
197 | @@ -438,6 +475,7 @@ |
198 | reverse('nodes_handler'), |
199 | { |
200 | 'op': 'new', |
201 | + 'autodetect_nodegroup': '1', |
202 | 'hostname': factory.getRandomString(), |
203 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
204 | 'after_commissioning_action': ( |
205 | @@ -470,6 +508,7 @@ |
206 | reverse('nodes_handler'), |
207 | { |
208 | 'op': 'new', |
209 | + 'autodetect_nodegroup': '1', |
210 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
211 | 'hostname': factory.getRandomString(), |
212 | 'after_commissioning_action': ( |
213 | @@ -535,6 +574,7 @@ |
214 | response = self.client.post( |
215 | reverse('nodes_handler'), { |
216 | 'op': 'new', |
217 | + 'autodetect_nodegroup': '1', |
218 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
219 | 'power_type': 'ether_wake', |
220 | 'power_parameters': json.dumps( |
221 | @@ -556,6 +596,7 @@ |
222 | reverse('nodes_handler'), |
223 | { |
224 | 'op': 'new', |
225 | + 'autodetect_nodegroup': '1', |
226 | 'hostname': factory.getRandomString(), |
227 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
228 | 'after_commissioning_action': ( |
229 | @@ -592,6 +633,7 @@ |
230 | response = self.client.post( |
231 | reverse('nodes_handler'), { |
232 | 'op': 'new', |
233 | + 'autodetect_nodegroup': '1', |
234 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
235 | 'power_type': 'ether_wake', |
236 | 'mac_addresses': ['00:11:22:33:44:55'], |
237 | @@ -609,6 +651,7 @@ |
238 | response = self.client.post( |
239 | reverse('nodes_handler'), { |
240 | 'op': 'new', |
241 | + 'autodetect_nodegroup': '1', |
242 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
243 | 'power_type': 'ether_wake', |
244 | 'power_parameters_mac_address': new_mac_address, |
245 | @@ -628,6 +671,7 @@ |
246 | response = self.client.post( |
247 | reverse('nodes_handler'), { |
248 | 'op': 'new', |
249 | + 'autodetect_nodegroup': '1', |
250 | 'hostname': hostname, |
251 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
252 | 'power_type': 'ether_wake', |
253 | @@ -651,6 +695,7 @@ |
254 | response = self.client.post( |
255 | reverse('nodes_handler'), { |
256 | 'op': 'new', |
257 | + 'autodetect_nodegroup': '1', |
258 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
259 | 'power_type': 'ether_wake', |
260 | 'power_parameters_param': param, |
261 | @@ -673,6 +718,7 @@ |
262 | reverse('nodes_handler'), |
263 | { |
264 | 'op': 'new', |
265 | + 'autodetect_nodegroup': '1', |
266 | 'hostname': factory.getRandomString(), |
267 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
268 | 'power_type': 'ether_wake', |
269 | @@ -692,6 +738,7 @@ |
270 | reverse('nodes_handler'), |
271 | { |
272 | 'op': 'new', |
273 | + 'autodetect_nodegroup': '1', |
274 | 'hostname': factory.getRandomString(), |
275 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
276 | 'power_type': 'ether_wake', |
277 | |
278 | === modified file 'src/maasserver/tests/test_api_nodes.py' |
279 | --- src/maasserver/tests/test_api_nodes.py 2014-02-10 11:34:47 +0000 |
280 | +++ src/maasserver/tests/test_api_nodes.py 2014-02-11 23:37:14 +0000 |
281 | @@ -152,6 +152,7 @@ |
282 | reverse('nodes_handler'), |
283 | { |
284 | 'op': 'new', |
285 | + 'autodetect_nodegroup': '1', |
286 | 'hostname': factory.getRandomString(), |
287 | 'architecture': architecture, |
288 | 'after_commissioning_action': ( |
289 | @@ -168,6 +169,7 @@ |
290 | reverse('nodes_handler'), |
291 | { |
292 | 'op': 'new', |
293 | + 'autodetect_nodegroup': '1', |
294 | 'hostname': factory.getRandomString(), |
295 | 'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES), |
296 | 'after_commissioning_action': ( |
297 | @@ -1085,6 +1087,7 @@ |
298 | '/api/1.0/nodes/MAAS/api/1.0/nodes/', |
299 | { |
300 | 'op': 'new', |
301 | + 'autodetect_nodegroup': '1', |
302 | 'hostname': factory.getRandomString(), |
303 | 'architecture': architecture, |
304 | 'mac_addresses': ['aa:bb:cc:dd:ee:ff'], |
Sensible change. I assume autodetection itself is already tested, in a test that needed no change. One thing that's a bit awkward (and I do see the XXX about it) is that the semantics of the autodetect_ nodegroup parameter are only explained in the test. I think the representation of booleans is not very highly standardised, so it may be worth a note in the docstring even if the docstring does not cover all parameters.
For the error message in api.py, saying that the nodegroup parameter is missing may be too strong. There's a choice to be made. How about "one of nodegroup or autodetect_ nodegroup must be specified"?