Merge lp:~andreserl/maas/consolidate_maas_ipmi_autodetect into lp:~maas-committers/maas/trunk
- consolidate_maas_ipmi_autodetect
- Merge into trunk
Proposed by
Andres Rodriguez
Status: | Merged |
---|---|
Approved by: | Andres Rodriguez |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1522 |
Proposed branch: | lp:~andreserl/maas/consolidate_maas_ipmi_autodetect |
Merge into: | lp:~maas-committers/maas/trunk |
Diff against target: |
651 lines (+223/-285) 9 files modified
contrib/preseeds_v2/enlist_userdata (+1/-141) etc/maas/templates/commissioning-user-data/snippets/maas_ipmi_autodetect.py (+161/-0) etc/maas/templates/commissioning-user-data/user_data.template (+1/-131) src/maasserver/preseed.py (+6/-1) src/maasserver/tests/test_preseed.py (+13/-4) src/metadataserver/commissioning/snippets.py (+22/-0) src/metadataserver/commissioning/tests/test_snippets.py (+12/-0) src/metadataserver/commissioning/tests/test_user_data.py (+1/-0) src/metadataserver/commissioning/user_data.py (+6/-8) |
To merge this branch: | bzr merge lp:~andreserl/maas/consolidate_maas_ipmi_autodetect |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andres Rodriguez (community) | Approve | ||
Jeroen T. Vermeulen (community) | Approve | ||
Review via email: mp+167806@code.launchpad.net |
Commit message
Consolidate the maas-ipmi-
Additionally fix test_render_preseed and test_render_
the correct templates.
Description of the change
To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote : | # |
Addressed comments and approving this branch for it to land.
review:
Approve
Revision history for this message
MAAS Lander (maas-lander) wrote : | # |
The Jenkins job https:/
Not merging it.
Revision history for this message
Andres Rodriguez (andreserl) : | # |
review:
Approve
Revision history for this message
Andres Rodriguez (andreserl) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'contrib/preseeds_v2/enlist_userdata' |
2 | --- contrib/preseeds_v2/enlist_userdata 2013-05-22 17:10:37 +0000 |
3 | +++ contrib/preseeds_v2/enlist_userdata 2013-06-12 17:17:25 +0000 |
4 | @@ -55,147 +55,7 @@ |
5 | END_IPMI_CONFIG |
6 | |
7 | add_bin "maas-ipmi-autodetect" <<"END_MAAS_IPMI_AUTODETECT" |
8 | - #!/usr/bin/python |
9 | - import os |
10 | - import commands |
11 | - import glob |
12 | - import re |
13 | - import string |
14 | - import random |
15 | - import time |
16 | - import json |
17 | - |
18 | - def detect_ipmi(): |
19 | - # XXX: andreserl 2013-04-09 bug=1064527: Try to detect if node |
20 | - # is a Virtual Machine. If it is, do not try to detect IPMI. |
21 | - with open('/proc/cpuinfo', 'r') as cpuinfo: |
22 | - for line in cpuinfo: |
23 | - if line.startswith('model name') and 'QEMU' in line: |
24 | - return (False, None) |
25 | - |
26 | - (status, output) = commands.getstatusoutput('ipmi-locate') |
27 | - show_re = re.compile('(IPMI\ Version:) (\d\.\d)') |
28 | - res = show_re.search(output) |
29 | - if res == None: |
30 | - found = glob.glob("/dev/ipmi[0-9]") |
31 | - if len(found): |
32 | - return (True, "UNKNOWN: %s" % " ".join(found)) |
33 | - return (False, "") |
34 | - return (True, res.group(2)) |
35 | - |
36 | - def is_ipmi_dhcp(): |
37 | - (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address_Source"') |
38 | - show_re = re.compile('IP_Address_Source\s+Use_DHCP') |
39 | - res = show_re.search(output) |
40 | - if res == None: |
41 | - return False |
42 | - return True |
43 | - |
44 | - def set_ipmi_network_source(source): |
45 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="Lan_Conf:IP_Address_Source=%s"' % source) |
46 | - |
47 | - def get_ipmi_ip_address(): |
48 | - (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address"') |
49 | - show_re = re.compile('([0-9]{1,3}[.]?){4}') |
50 | - res = show_re.search(output) |
51 | - return res.group() |
52 | - |
53 | - def get_ipmi_user_number(user): |
54 | - for i in range(1, 17): |
55 | - ipmi_user_number = "User%s" % i |
56 | - (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="%s:Username"' % ipmi_user_number) |
57 | - if user in output: |
58 | - return ipmi_user_number |
59 | - return None |
60 | - |
61 | - def commit_ipmi_user_settings(user, password): |
62 | - ipmi_user_number = get_ipmi_user_number(user) |
63 | - if ipmi_user_number is None: |
64 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User10:Username=%s"' % user) |
65 | - ipmi_user_number = get_ipmi_user_number(user) |
66 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Username=%s"' % (ipmi_user_number, user)) |
67 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Password=%s"' % (ipmi_user_number, password)) |
68 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Enable_User=Yes"' % ipmi_user_number) |
69 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Enable_IPMI_Msgs=Yes"' % ipmi_user_number) |
70 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Privilege_Limit=Administrator"' % ipmi_user_number) |
71 | - |
72 | - def commit_ipmi_settings(config): |
73 | - (status, output) = commands.getstatusoutput('bmc-config --commit --filename %s' % config) |
74 | - |
75 | - def get_maas_power_settings(user, password, ipaddress): |
76 | - return "%s,%s,%s" % (user, password, ipaddress) |
77 | - |
78 | - def get_maas_power_settings_json(user, password, ipaddress): |
79 | - power_params = {"power_address": ipaddress, "power_pass": password, "power_user": user} |
80 | - return json.dumps(power_params) |
81 | - |
82 | - def generate_random_password(min=8,max=15): |
83 | - length=random.randint(min,max) |
84 | - letters=string.ascii_letters+string.digits |
85 | - return ''.join([random.choice(letters) for _ in range(length)]) |
86 | - |
87 | - def main(): |
88 | - |
89 | - import argparse |
90 | - |
91 | - parser = argparse.ArgumentParser( |
92 | - description='send config file to modify IPMI settings with') |
93 | - parser.add_argument("--configdir", metavar="folder", |
94 | - help="specify config file directory", default=None) |
95 | - parser.add_argument("--dhcp-if-static", action="store_true", |
96 | - dest="dhcp", help="set network source to DHCP if Static", default=False) |
97 | - parser.add_argument("--commission-creds", action="store_true", |
98 | - dest="commission_creds", help="Create IPMI temporary credentials", default=False) |
99 | - |
100 | - args = parser.parse_args() |
101 | - |
102 | - # Check whether IPMI exists or not. |
103 | - (status, ipmi_version) = detect_ipmi() |
104 | - if status != True: |
105 | - # if False, then failed to detect ipmi |
106 | - exit(1) |
107 | - |
108 | - # Check whether IPMI is being set to DHCP. If it is not, and |
109 | - # '--dhcp-if-static' has been passed, Set it to IPMI to DHCP. |
110 | - if not is_ipmi_dhcp() and args.dhcp: |
111 | - set_ipmi_network_source("Use_DHCP") |
112 | - # allow IPMI 120 seconds to obtain an IP address |
113 | - time.sleep(120) |
114 | - |
115 | - # create user/pass |
116 | - IPMI_MAAS_USER="maas" |
117 | - IPMI_MAAS_PASSWORD=generate_random_password() |
118 | - |
119 | - # Configure IPMI user/password |
120 | - commit_ipmi_user_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD) |
121 | - |
122 | - # Commit other IPMI settings |
123 | - if args.configdir: |
124 | - for file in os.listdir(args.configdir): |
125 | - commit_ipmi_settings(os.path.join(args.configdir, file)) |
126 | - |
127 | - # get the IP address |
128 | - IPMI_IP_ADDRESS = get_ipmi_ip_address() |
129 | - if IPMI_IP_ADDRESS == "0.0.0.0": |
130 | - # if IPMI_IP_ADDRESS is 0.0.0.0, wait 60 seconds and retry. |
131 | - set_ipmi_network_source("Static") |
132 | - time.sleep(2) |
133 | - set_ipmi_network_source("Use_DHCP") |
134 | - time.sleep(60) |
135 | - IPMI_IP_ADDRESS = get_ipmi_ip_address() |
136 | - |
137 | - if IPMI_IP_ADDRESS is None or IPMI_IP_ADDRESS == "0.0.0.0": |
138 | - # Exit (to not set power params in MAAS) if no IPMI_IP_ADDRESS |
139 | - # has been detected |
140 | - exit(1) |
141 | - |
142 | - if args.commission_creds: |
143 | - print get_maas_power_settings_json(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS) |
144 | - else: |
145 | - print get_maas_power_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS) |
146 | - |
147 | - if __name__ == '__main__': |
148 | - main() |
149 | + {{maas_ipmi_autodetect_py}} |
150 | END_MAAS_IPMI_AUTODETECT |
151 | |
152 | # we could obtain the interface that booted from the kernel cmdline |
153 | |
154 | === added file 'etc/maas/templates/commissioning-user-data/snippets/maas_ipmi_autodetect.py' |
155 | --- etc/maas/templates/commissioning-user-data/snippets/maas_ipmi_autodetect.py 1970-01-01 00:00:00 +0000 |
156 | +++ etc/maas/templates/commissioning-user-data/snippets/maas_ipmi_autodetect.py 2013-06-12 17:17:25 +0000 |
157 | @@ -0,0 +1,161 @@ |
158 | +#!/usr/bin/python |
159 | +# |
160 | +# maas-ipmi-autodetect - autodetect and autoconfigure IPMI. |
161 | +# |
162 | +# Copyright (C) 2011-2013 Canonical |
163 | +# |
164 | +# Authors: |
165 | +# Andres Rodriguez <andres.rodriguez@canonical.com> |
166 | +# |
167 | +# This program is free software: you can redistribute it and/or modify |
168 | +# it under the terms of the GNU Affero General Public License as |
169 | +# published by the Free Software Foundation, version 3 of the License. |
170 | +# |
171 | +# This program is distributed in the hope that it will be useful, |
172 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
173 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
174 | +# GNU Affero General Public License for more details. |
175 | +# |
176 | +# You should have received a copy of the GNU Affero General Public License |
177 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
178 | + |
179 | +import os |
180 | +import commands |
181 | +import glob |
182 | +import re |
183 | +import string |
184 | +import random |
185 | +import time |
186 | +import json |
187 | + |
188 | +def detect_ipmi(): |
189 | + # XXX: andreserl 2013-04-09 bug=1064527: Try to detect if node |
190 | + # is a Virtual Machine. If it is, do not try to detect IPMI. |
191 | + with open('/proc/cpuinfo', 'r') as cpuinfo: |
192 | + for line in cpuinfo: |
193 | + if line.startswith('model name') and 'QEMU' in line: |
194 | + return (False, None) |
195 | + |
196 | + (status, output) = commands.getstatusoutput('ipmi-locate') |
197 | + show_re = re.compile('(IPMI\ Version:) (\d\.\d)') |
198 | + res = show_re.search(output) |
199 | + if res == None: |
200 | + found = glob.glob("/dev/ipmi[0-9]") |
201 | + if len(found): |
202 | + return (True, "UNKNOWN: %s" % " ".join(found)) |
203 | + return (False, "") |
204 | + return (True, res.group(2)) |
205 | + |
206 | +def is_ipmi_dhcp(): |
207 | + (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address_Source"') |
208 | + show_re = re.compile('IP_Address_Source\s+Use_DHCP') |
209 | + res = show_re.search(output) |
210 | + if res == None: |
211 | + return False |
212 | + return True |
213 | + |
214 | +def set_ipmi_network_source(source): |
215 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="Lan_Conf:IP_Address_Source=%s"' % source) |
216 | + |
217 | +def get_ipmi_ip_address(): |
218 | + (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address"') |
219 | + show_re = re.compile('([0-9]{1,3}[.]?){4}') |
220 | + res = show_re.search(output) |
221 | + return res.group() |
222 | + |
223 | +def get_ipmi_user_number(user): |
224 | + for i in range(1, 17): |
225 | + ipmi_user_number = "User%s" % i |
226 | + (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="%s:Username"' % ipmi_user_number) |
227 | + if user in output: |
228 | + return ipmi_user_number |
229 | + return None |
230 | + |
231 | +def commit_ipmi_user_settings(user, password): |
232 | + ipmi_user_number = get_ipmi_user_number(user) |
233 | + if ipmi_user_number is None: |
234 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User10:Username=%s"' % user) |
235 | + ipmi_user_number = get_ipmi_user_number(user) |
236 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Username=%s"' % (ipmi_user_number, user)) |
237 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Password=%s"' % (ipmi_user_number, password)) |
238 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Enable_User=Yes"' % ipmi_user_number) |
239 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Enable_IPMI_Msgs=Yes"' % ipmi_user_number) |
240 | + (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Privilege_Limit=Administrator"' % ipmi_user_number) |
241 | + |
242 | +def commit_ipmi_settings(config): |
243 | + (status, output) = commands.getstatusoutput('bmc-config --commit --filename %s' % config) |
244 | + |
245 | +def get_maas_power_settings(user, password, ipaddress): |
246 | + return "%s,%s,%s" % (user, password, ipaddress) |
247 | + |
248 | +def get_maas_power_settings_json(user, password, ipaddress): |
249 | + power_params = {"power_address": ipaddress, "power_pass": password, "power_user": user} |
250 | + return json.dumps(power_params) |
251 | + |
252 | +def generate_random_password(min=8,max=15): |
253 | + length=random.randint(min,max) |
254 | + letters=string.ascii_letters+string.digits |
255 | + return ''.join([random.choice(letters) for _ in range(length)]) |
256 | + |
257 | +def main(): |
258 | + |
259 | + import argparse |
260 | + |
261 | + parser = argparse.ArgumentParser( |
262 | + description='send config file to modify IPMI settings with') |
263 | + parser.add_argument("--configdir", metavar="folder", |
264 | + help="specify config file directory", default=None) |
265 | + parser.add_argument("--dhcp-if-static", action="store_true", |
266 | + dest="dhcp", help="set network source to DHCP if Static", default=False) |
267 | + parser.add_argument("--commission-creds", action="store_true", |
268 | + dest="commission_creds", help="Create IPMI temporary credentials", default=False) |
269 | + |
270 | + args = parser.parse_args() |
271 | + |
272 | + # Check whether IPMI exists or not. |
273 | + (status, ipmi_version) = detect_ipmi() |
274 | + if status != True: |
275 | + # if False, then failed to detect ipmi |
276 | + exit(1) |
277 | + |
278 | + # Check whether IPMI is being set to DHCP. If it is not, and |
279 | + # '--dhcp-if-static' has been passed, Set it to IPMI to DHCP. |
280 | + if not is_ipmi_dhcp() and args.dhcp: |
281 | + set_ipmi_network_source("Use_DHCP") |
282 | + # allow IPMI 120 seconds to obtain an IP address |
283 | + time.sleep(120) |
284 | + |
285 | + # create user/pass |
286 | + IPMI_MAAS_USER="maas" |
287 | + IPMI_MAAS_PASSWORD=generate_random_password() |
288 | + |
289 | + # Configure IPMI user/password |
290 | + commit_ipmi_user_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD) |
291 | + |
292 | + # Commit other IPMI settings |
293 | + if args.configdir: |
294 | + for file in os.listdir(args.configdir): |
295 | + commit_ipmi_settings(os.path.join(args.configdir, file)) |
296 | + |
297 | + # get the IP address |
298 | + IPMI_IP_ADDRESS = get_ipmi_ip_address() |
299 | + if IPMI_IP_ADDRESS == "0.0.0.0": |
300 | + # if IPMI_IP_ADDRESS is 0.0.0.0, wait 60 seconds and retry. |
301 | + set_ipmi_network_source("Static") |
302 | + time.sleep(2) |
303 | + set_ipmi_network_source("Use_DHCP") |
304 | + time.sleep(60) |
305 | + IPMI_IP_ADDRESS = get_ipmi_ip_address() |
306 | + |
307 | + if IPMI_IP_ADDRESS is None or IPMI_IP_ADDRESS == "0.0.0.0": |
308 | + # Exit (to not set power params in MAAS) if no IPMI_IP_ADDRESS |
309 | + # has been detected |
310 | + exit(1) |
311 | + |
312 | + if args.commission_creds: |
313 | + print get_maas_power_settings_json(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS) |
314 | + else: |
315 | + print get_maas_power_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS) |
316 | + |
317 | +if __name__ == '__main__': |
318 | + main() |
319 | |
320 | === modified file 'etc/maas/templates/commissioning-user-data/user_data.template' |
321 | --- etc/maas/templates/commissioning-user-data/user_data.template 2013-06-04 00:04:30 +0000 |
322 | +++ etc/maas/templates/commissioning-user-data/user_data.template 2013-06-12 17:17:25 +0000 |
323 | @@ -219,137 +219,7 @@ |
324 | END_IPMI_CONFIG |
325 | |
326 | add_bin "maas-ipmi-autodetect" <<"END_MAAS_IPMI_AUTODETECT" |
327 | -#!/usr/bin/python |
328 | -import os |
329 | -import commands |
330 | -import glob |
331 | -import re |
332 | -import string |
333 | -import random |
334 | -import time |
335 | - |
336 | -def detect_ipmi(): |
337 | - # XXX: andreserl 2013-04-09 bug=1064527: Try to detect if node |
338 | - # is a Virtual Machine. If it is, do not try to detect IPMI. |
339 | - with open('/proc/cpuinfo', 'r') as cpuinfo: |
340 | - for line in cpuinfo: |
341 | - if line.startswith('model name') and 'QEMU' in line: |
342 | - return (False, None) |
343 | - |
344 | - (status, output) = commands.getstatusoutput('ipmi-locate') |
345 | - show_re = re.compile('(IPMI\ Version:) (\d\.\d)') |
346 | - res = show_re.search(output) |
347 | - if res == None: |
348 | - found = glob.glob("/dev/ipmi[0-9]") |
349 | - if len(found): |
350 | - return (True, "UNKNOWN: %s" % " ".join(found)) |
351 | - return (False, "") |
352 | - return (True, res.group(2)) |
353 | - |
354 | -def is_ipmi_dhcp(): |
355 | - (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address_Source"') |
356 | - show_re = re.compile('IP_Address_Source\s+Use_DHCP') |
357 | - res = show_re.search(output) |
358 | - if res == None: |
359 | - return False |
360 | - return True |
361 | - |
362 | -def set_ipmi_network_source(source): |
363 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="Lan_Conf:IP_Address_Source=%s"' % source) |
364 | - |
365 | -def get_ipmi_ip_address(): |
366 | - (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="Lan_Conf:IP_Address"') |
367 | - show_re = re.compile('([0-9]{1,3}[.]?){4}') |
368 | - res = show_re.search(output) |
369 | - return res.group() |
370 | - |
371 | -def get_ipmi_user_number(user): |
372 | - for i in range(1, 17): |
373 | - ipmi_user_number = "User%s" % i |
374 | - (status, output) = commands.getstatusoutput('bmc-config --checkout --key-pair="%s:Username"' % ipmi_user_number) |
375 | - if user in output: |
376 | - return ipmi_user_number |
377 | - return None |
378 | - |
379 | -def commit_ipmi_user_settings(user, password): |
380 | - ipmi_user_number = get_ipmi_user_number(user) |
381 | - if ipmi_user_number is None: |
382 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="User10:Username=%s"' % user) |
383 | - ipmi_user_number = get_ipmi_user_number(user) |
384 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Username=%s"' % (ipmi_user_number, user)) |
385 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Password=%s"' % (ipmi_user_number, password)) |
386 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Enable_User=Yes"' % ipmi_user_number) |
387 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Enable_IPMI_Msgs=Yes"' % ipmi_user_number) |
388 | - (status, output) = commands.getstatusoutput('bmc-config --commit --key-pair="%s:Lan_Privilege_Limit=Administrator"' % ipmi_user_number) |
389 | - |
390 | -def commit_ipmi_settings(config): |
391 | - (status, output) = commands.getstatusoutput('bmc-config --commit --filename %s' % config) |
392 | - |
393 | -def get_maas_power_settings(user, password, ipaddress): |
394 | - return "%s,%s,%s" % (user, password, ipaddress) |
395 | - |
396 | -def generate_random_password(min=8,max=15): |
397 | - length=random.randint(min,max) |
398 | - letters=string.ascii_letters+string.digits |
399 | - return ''.join([random.choice(letters) for _ in range(length)]) |
400 | - |
401 | -def main(): |
402 | - |
403 | - import argparse |
404 | - |
405 | - parser = argparse.ArgumentParser( |
406 | - description='send config file to modify IPMI settings with') |
407 | - parser.add_argument("--configdir", metavar="folder", |
408 | - help="specify config file", default=None) |
409 | - parser.add_argument("--dhcp-if-static", action="store_true", |
410 | - dest="dhcp", help="specify config file", default=False) |
411 | - |
412 | - args = parser.parse_args() |
413 | - |
414 | - # Check whether IPMI exists or not. |
415 | - (status, ipmi_version) = detect_ipmi() |
416 | - if status != True: |
417 | - # if False, then failed to detect ipmi |
418 | - exit(1) |
419 | - |
420 | - # Check whether IPMI is being set to DHCP. If it is not, and |
421 | - # '--dhcp-if-static' has been passed, Set it to IPMI to DHCP. |
422 | - if not is_ipmi_dhcp() and args.dhcp: |
423 | - set_ipmi_network_source("Use_DHCP") |
424 | - # allow IPMI 120 seconds to obtain an IP address |
425 | - time.sleep(120) |
426 | - |
427 | - # create user/pass |
428 | - IPMI_MAAS_USER="maas" |
429 | - IPMI_MAAS_PASSWORD=generate_random_password() |
430 | - |
431 | - # Configure IPMI user/password |
432 | - commit_ipmi_user_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD) |
433 | - |
434 | - # Commit other IPMI settings |
435 | - if args.configdir: |
436 | - for file in os.listdir(args.configdir): |
437 | - commit_ipmi_settings(os.path.join(args.configdir, file)) |
438 | - |
439 | - # get the IP address |
440 | - IPMI_IP_ADDRESS = get_ipmi_ip_address() |
441 | - if IPMI_IP_ADDRESS == "0.0.0.0": |
442 | - # if IPMI_IP_ADDRESS is 0.0.0.0, wait 60 seconds and retry. |
443 | - set_ipmi_network_source("Static") |
444 | - time.sleep(2) |
445 | - set_ipmi_network_source("Use_DHCP") |
446 | - time.sleep(60) |
447 | - IPMI_IP_ADDRESS = get_ipmi_ip_address() |
448 | - |
449 | - if IPMI_IP_ADDRESS is None or IPMI_IP_ADDRESS == "0.0.0.0": |
450 | - # Exit (to not set power params in MAAS) if no IPMI_IP_ADDRESS |
451 | - # has been detected |
452 | - exit(1) |
453 | - |
454 | - print get_maas_power_settings(IPMI_MAAS_USER, IPMI_MAAS_PASSWORD, IPMI_IP_ADDRESS) |
455 | - |
456 | -if __name__ == '__main__': |
457 | - main() |
458 | +{{maas_ipmi_autodetect_py}} |
459 | END_MAAS_IPMI_AUTODETECT |
460 | |
461 | add_bin "maas_api_helper.py" <<"END_MAAS_API_HELPER" |
462 | |
463 | === modified file 'src/maasserver/preseed.py' |
464 | --- src/maasserver/preseed.py 2013-05-11 18:38:34 +0000 |
465 | +++ src/maasserver/preseed.py 2013-06-12 17:17:25 +0000 |
466 | @@ -35,6 +35,8 @@ |
467 | from maasserver.utils import absolute_reverse |
468 | import tempita |
469 | |
470 | +from metadataserver.commissioning.snippets import get_snippet_context |
471 | + |
472 | |
473 | GENERIC_FILENAME = 'generic' |
474 | |
475 | @@ -287,7 +289,10 @@ |
476 | """ |
477 | template = load_preseed_template(None, prefix, release) |
478 | context = get_preseed_context(release, nodegroup=nodegroup) |
479 | - return template.substitute(**context) |
480 | + # Render the snippets in the main template. |
481 | + snippets = get_snippet_context() |
482 | + snippets.update(context) |
483 | + return template.substitute(**snippets) |
484 | |
485 | |
486 | def render_preseed(node, prefix, release=''): |
487 | |
488 | === modified file 'src/maasserver/tests/test_preseed.py' |
489 | --- src/maasserver/tests/test_preseed.py 2013-05-11 18:38:34 +0000 |
490 | +++ src/maasserver/tests/test_preseed.py 2013-06-12 17:17:25 +0000 |
491 | @@ -421,10 +421,12 @@ |
492 | missing). |
493 | """ |
494 | |
495 | - # Create a scenario for each possible value of PRESEED_TYPE. |
496 | + # Create a scenario for each possible value of PRESEED_TYPE except |
497 | + # enlistment. Those have their own test case. |
498 | scenarios = [ |
499 | (name, {'preseed': value}) |
500 | - for name, value in map_enum(PRESEED_TYPE).items()] |
501 | + for name, value in map_enum(PRESEED_TYPE).items() |
502 | + if not value.startswith('enlist')] |
503 | |
504 | def test_render_preseed(self): |
505 | node = factory.make_node() |
506 | @@ -448,8 +450,15 @@ |
507 | class TestRenderEnlistmentPreseed(TestCase): |
508 | """Tests for `render_enlistment_preseed`.""" |
509 | |
510 | + # Create a scenario for each possible value of PRESEED_TYPE for |
511 | + # enlistment. The rest have their own test case. |
512 | + scenarios = [ |
513 | + (name, {'preseed': value}) |
514 | + for name, value in map_enum(PRESEED_TYPE).items() |
515 | + if value.startswith('enlist')] |
516 | + |
517 | def test_render_enlistment_preseed(self): |
518 | - preseed = render_enlistment_preseed(PRESEED_TYPE.ENLIST, "precise") |
519 | + preseed = render_enlistment_preseed(self.preseed, "precise") |
520 | # The test really is that the preseed is rendered without an |
521 | # error. |
522 | self.assertIsInstance(preseed, str) |
523 | @@ -460,7 +469,7 @@ |
524 | self.patch(settings, 'DEFAULT_MAAS_URL', maas_url) |
525 | nodegroup = factory.make_node_group(maas_url=ng_url) |
526 | preseed = render_enlistment_preseed( |
527 | - PRESEED_TYPE.ENLIST, "precise", nodegroup=nodegroup) |
528 | + self.preseed, "precise", nodegroup=nodegroup) |
529 | self.assertThat( |
530 | preseed, MatchesAll(*[Contains(ng_url), Not(Contains(maas_url))])) |
531 | |
532 | |
533 | === modified file 'src/metadataserver/commissioning/snippets.py' |
534 | --- src/metadataserver/commissioning/snippets.py 2013-06-04 12:22:16 +0000 |
535 | +++ src/metadataserver/commissioning/snippets.py 2013-06-12 17:17:25 +0000 |
536 | @@ -18,9 +18,31 @@ |
537 | 'list_snippets', |
538 | 'read_snippet', |
539 | 'strip_name', |
540 | + 'get_snippet_context', |
541 | + 'get_userdata_template_dir', |
542 | ] |
543 | |
544 | import os |
545 | +from provisioningserver.utils import locate_config |
546 | + |
547 | +USERDATA_BASE_DIR = 'templates/commissioning-user-data' |
548 | + |
549 | + |
550 | +def get_userdata_template_dir(): |
551 | + """Return the absolute location of the userdata |
552 | + template directory.""" |
553 | + return locate_config(USERDATA_BASE_DIR) |
554 | + |
555 | + |
556 | +def get_snippet_context(snippets_dir=None, encoding='utf-8'): |
557 | + """Return the context of all of the snippets.""" |
558 | + if snippets_dir is None: |
559 | + snippets_dir = os.path.join(get_userdata_template_dir(), 'snippets') |
560 | + snippets = { |
561 | + strip_name(name): read_snippet(snippets_dir, name, encoding=encoding) |
562 | + for name in list_snippets(snippets_dir) |
563 | + } |
564 | + return snippets |
565 | |
566 | |
567 | def read_snippet(snippets_dir, name, encoding='utf-8'): |
568 | |
569 | === modified file 'src/metadataserver/commissioning/tests/test_snippets.py' |
570 | --- src/metadataserver/commissioning/tests/test_snippets.py 2013-06-04 12:22:16 +0000 |
571 | +++ src/metadataserver/commissioning/tests/test_snippets.py 2013-06-12 17:17:25 +0000 |
572 | @@ -21,6 +21,7 @@ |
573 | list_snippets, |
574 | read_snippet, |
575 | strip_name, |
576 | + get_snippet_context, |
577 | ) |
578 | |
579 | |
580 | @@ -59,3 +60,14 @@ |
581 | factory.make_file(snippets_dir, 'snippet') |
582 | factory.make_file(snippets_dir, '.backup.pyc') |
583 | self.assertItemsEqual(['snippet'], list_snippets(snippets_dir)) |
584 | + |
585 | + def test_get_snippet_context(self): |
586 | + contents = factory.getRandomString() |
587 | + snippets_dir = self.make_dir() |
588 | + factory.make_file(snippets_dir, 'snippet.py', contents=contents) |
589 | + self.assertItemsEqual({'snippet_py': contents}, get_snippet_context(snippets_dir=snippets_dir)) |
590 | + |
591 | + def test_get_snippet_context_empty_if_no_snippets(self): |
592 | + snippets_dir = self.make_dir() |
593 | + context = {} |
594 | + self.assertEqual(context, get_snippet_context(snippets_dir=snippets_dir)) |
595 | |
596 | === modified file 'src/metadataserver/commissioning/tests/test_user_data.py' |
597 | --- src/metadataserver/commissioning/tests/test_user_data.py 2013-06-04 12:22:16 +0000 |
598 | +++ src/metadataserver/commissioning/tests/test_user_data.py 2013-06-12 17:17:25 +0000 |
599 | @@ -32,6 +32,7 @@ |
600 | generate_user_data(), ContainsAll({ |
601 | 'maas-get', |
602 | 'maas-signal', |
603 | + 'maas-ipmi-autodetect', |
604 | 'def authenticate_headers', |
605 | 'def encode_multipart_data', |
606 | })) |
607 | |
608 | === modified file 'src/metadataserver/commissioning/user_data.py' |
609 | --- src/metadataserver/commissioning/user_data.py 2013-06-04 14:45:01 +0000 |
610 | +++ src/metadataserver/commissioning/user_data.py 2013-06-12 17:17:25 +0000 |
611 | @@ -30,10 +30,13 @@ |
612 | list_snippets, |
613 | read_snippet, |
614 | strip_name, |
615 | + get_userdata_template_dir, |
616 | + get_snippet_context, |
617 | ) |
618 | -from provisioningserver.utils import locate_config |
619 | import tempita |
620 | |
621 | +ENCODING = 'utf-8' |
622 | + |
623 | |
624 | def generate_user_data(nodegroup=None): |
625 | """Produce the main commissioning script. |
626 | @@ -50,13 +53,11 @@ |
627 | |
628 | :rtype: `bytes` |
629 | """ |
630 | - ENCODING = 'utf-8' |
631 | - commissioning_dir = locate_config('templates/commissioning-user-data') |
632 | + commissioning_dir = get_userdata_template_dir() |
633 | userdata_template_file = os.path.join( |
634 | commissioning_dir, 'user_data.template') |
635 | config_template_file = os.path.join( |
636 | commissioning_dir, 'user_data_config.template') |
637 | - snippets_dir = os.path.join(commissioning_dir, 'snippets') |
638 | userdata_template = tempita.Template.from_filename( |
639 | userdata_template_file, encoding=ENCODING) |
640 | config_template = tempita.Template.from_filename( |
641 | @@ -66,10 +67,7 @@ |
642 | preseed_context = get_preseed_context(nodegroup=nodegroup) |
643 | |
644 | # Render the snippets in the main template. |
645 | - snippets = { |
646 | - strip_name(name): read_snippet(snippets_dir, name, encoding=ENCODING) |
647 | - for name in list_snippets(snippets_dir) |
648 | - } |
649 | + snippets = get_snippet_context(encoding=ENCODING) |
650 | snippets.update(preseed_context) |
651 | userdata = userdata_template.substitute(snippets).encode(ENCODING) |
652 |
Thanks for doing this. It's great to see so much duplication disappear! It may even make it easier, if we ever get to that, to write unit-tests for the code inside the user data.
I always try to come up with a few remarks. The test for get_snippet_context is the right thing to do; it's short but probably only because it's well-written. But it'd be nice to have a negative test as well, to ensure that the function doesn't return things that it shouldn't. But that's no reason to stop this branch from landing. If you like I could write one for you afterwards.
Another note is that Python docstrings normally start with a description in the imperative. So where your docstrings start with "Returns [something]" the preferred form is "Return [something]." Not urgent.
One other small thing that I would prefer you to change: with values that aren't booleans, explicit comparisons are clearer and more robust than evaluating them directly as Booleans. So in get_snippet_ context, it's better to write "if snippets_dir is None:" than to write "if not snippets_dir:". It produces more easily predictable behaviour in edge cases or failure scenarios, such as empty strings.
Jeroen