Merge lp:~nuclearbob/utah/baremetal-standardization into lp:utah
- baremetal-standardization
- Merge into dev
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Javier Collado | ||||
Approved revision: | 759 | ||||
Merged at revision: | 777 | ||||
Proposed branch: | lp:~nuclearbob/utah/baremetal-standardization | ||||
Merge into: | lp:utah | ||||
Diff against target: |
630 lines (+157/-167) 9 files modified
examples/run_test_bamboo_feeder.py (+2/-2) examples/run_test_cobbler.py (+2/-2) examples/run_utah_tests.py (+0/-1) utah/config.py (+2/-3) utah/provisioning/baremetal/bamboofeeder.py (+8/-26) utah/provisioning/baremetal/cobbler.py (+85/-110) utah/provisioning/baremetal/power.py (+18/-3) utah/provisioning/inventory/sqlite.py (+17/-17) utah/provisioning/provisioning.py (+23/-3) |
||||
To merge this branch: | bzr merge lp:~nuclearbob/utah/baremetal-standardization | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Javier Collado (community) | Approve | ||
Max Brustkern (community) | Needs Resubmitting | ||
Review via email:
|
Commit message
Description of the change
This branch contains a number of changes I started working on at UDS to simplify and improve the existing bare metal provisioning methods. I'll detail them below.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
- 754. By Max Brustkern
-
Removed boot argument since the Machine class handles that now
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Javier Collado (javier.collado) wrote : | # |
pyflakes returns the following problems:
utah/provisioni
utah/provisioni
First one should really be fixed.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
Definitely. That's a doozy. I'll go over both of these, and revisit integrating static analysis into my editor, or choosing a new editor that supports it.
- 755. By Max Brustkern
-
Merge default yaml work
Merged latest changes from dev branch - 756. By Max Brustkern
-
Resolved pep8 and pyflakes errors
- 757. By Max Brustkern
-
Moved inventory cleanup after cleanup initialization
- 758. By Max Brustkern
-
Removing direct interaction with nfsfile since we need sudo for that
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
I've fixed static analysis errors and tested this with cobbler in magners, and it seems to be working well.
- 759. By Max Brustkern
-
Renamed Cobbler inventory to more genertic Baremetal
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Javier Collado (javier.collado) wrote : | # |
The problems in my previous comment are fixed. Thanks.
(I still need to learn how to test bare metal provisioning at some point).
Preview Diff
1 | === modified file 'examples/run_test_bamboo_feeder.py' |
2 | --- examples/run_test_bamboo_feeder.py 2012-12-08 02:10:12 +0000 |
3 | +++ examples/run_test_bamboo_feeder.py 2012-12-10 20:39:20 +0000 |
4 | @@ -23,7 +23,7 @@ |
5 | from utah.exceptions import UTAHException |
6 | from utah.group import check_user_group, print_group_error_message |
7 | from utah.provisioning.baremetal.bamboofeeder import BambooFeederMachine |
8 | -from utah.provisioning.inventory.sqlite import ManualCobblerSQLiteInventory |
9 | +from utah.provisioning.inventory.sqlite import ManualBaremetalSQLiteInventory |
10 | from utah.run import run_tests |
11 | from utah.url import url_argument |
12 | |
13 | @@ -81,7 +81,7 @@ |
14 | machine = None |
15 | |
16 | try: |
17 | - inventory = ManualCobblerSQLiteInventory( |
18 | + inventory = ManualBaremetalSQLiteInventory( |
19 | db=os.path.join('~', '.utah-bamboofeeder-inventory'), |
20 | lockfile=os.path.join('~', '.utah-bamboofeeder-lock')) |
21 | kw = {} |
22 | |
23 | === modified file 'examples/run_test_cobbler.py' |
24 | --- examples/run_test_cobbler.py 2012-12-08 02:10:12 +0000 |
25 | +++ examples/run_test_cobbler.py 2012-12-10 20:39:20 +0000 |
26 | @@ -21,7 +21,7 @@ |
27 | from utah import config |
28 | from utah.exceptions import UTAHException |
29 | from utah.group import check_user_group, print_group_error_message |
30 | -from utah.provisioning.inventory.sqlite import ManualCobblerSQLiteInventory |
31 | +from utah.provisioning.inventory.sqlite import ManualBaremetalSQLiteInventory |
32 | from utah.run import run_tests |
33 | from utah.url import url_argument |
34 | |
35 | @@ -95,7 +95,7 @@ |
36 | sys.exit(4) |
37 | |
38 | try: |
39 | - inventory = ManualCobblerSQLiteInventory() |
40 | + inventory = ManualBaremetalSQLiteInventory() |
41 | kw = {} |
42 | for arg in ['image', 'preseed', 'rewrite']: |
43 | value = vars(args)[arg] |
44 | |
45 | === modified file 'examples/run_utah_tests.py' |
46 | --- examples/run_utah_tests.py 2012-12-08 02:10:12 +0000 |
47 | +++ examples/run_utah_tests.py 2012-12-10 20:39:20 +0000 |
48 | @@ -22,7 +22,6 @@ |
49 | from utah.url import url_argument |
50 | from utah.group import check_user_group, print_group_error_message |
51 | from utah.timeout import timeout, UTAHTimeout |
52 | -from utah import config |
53 | from run_install_test import run_install_test |
54 | |
55 | |
56 | |
57 | === modified file 'utah/config.py' |
58 | --- utah/config.py 2012-12-10 13:01:20 +0000 |
59 | +++ utah/config.py 2012-12-10 20:39:20 +0000 |
60 | @@ -99,10 +99,9 @@ |
61 | name=None, |
62 | # Default setting of installing a new machine vs. using an existing one |
63 | new=False, |
64 | - # Command to reload NFS configuration |
65 | # NFS options currently only used for cobbler-based desktop installs |
66 | - nfscommand=['sudo', os.path.join('/', 'etc', 'init.d', |
67 | - 'nfs-kernel-server'), 'reload'], |
68 | + # NFS service command |
69 | + nfscommand=['sudo', 'service', 'nfs-kernel-server'], |
70 | # Path to NFS config file |
71 | nfsconfigfile=os.path.join('/', 'etc', 'exports'), |
72 | # Default options for NFS shares |
73 | |
74 | === modified file 'utah/provisioning/baremetal/bamboofeeder.py' |
75 | --- utah/provisioning/baremetal/bamboofeeder.py 2012-12-08 02:10:12 +0000 |
76 | +++ utah/provisioning/baremetal/bamboofeeder.py 2012-12-10 20:39:20 +0000 |
77 | @@ -39,30 +39,20 @@ |
78 | """ |
79 | Provide a class to provision an ARM board from a bamboo-feeder setup. |
80 | """ |
81 | - def __init__(self, cargs=None, inventory=None, name=None, powercmd=None, |
82 | + def __init__(self, inventory=None, machineinfo=None, name=None, |
83 | preboot=None, *args, **kw): |
84 | # TODO: change the name of cargs here and elsewhere |
85 | # TODO: respect rewrite setting |
86 | if name is None: |
87 | raise UTAHBMProvisioningException( |
88 | 'Machine name reqired for bamboo-feeder machine') |
89 | - if powercmd is not None: |
90 | - self.powercmd = powercmd |
91 | - elif cargs is not None: |
92 | - self.power = {} |
93 | - for item in cargs: |
94 | - if 'power' in item: |
95 | - self.power[item] = cargs[item] |
96 | - else: |
97 | - raise UTAHBMProvisioningException( |
98 | - 'No power control information specified') |
99 | try: |
100 | - self.macaddress = cargs['mac-address'] |
101 | + self.macaddress = machineinfo['mac-address'] |
102 | except AttributeError: |
103 | - raise UTAHBMProvisioningException( |
104 | - 'No MAC address specified') |
105 | + raise UTAHBMProvisioningException('No MAC address specified') |
106 | self.inventory = inventory |
107 | - super(BambooFeederMachine, self).__init__(*args, name=name, **kw) |
108 | + super(BambooFeederMachine, self).__init__(*args, |
109 | + machineinfo=machineinfo, name=name, **kw) |
110 | if self.inventory is not None: |
111 | self.cleanfunction(self.inventory.release, machine=self) |
112 | self._depcheck() |
113 | @@ -147,10 +137,10 @@ |
114 | headersize = filesize - datasize |
115 | self.logger.debug('uInitrd header size is ' + str(headersize)) |
116 | pipe = pipes.Template() |
117 | - pipe.prepend('dd if=$IN bs=1 skip=' + str(headersize), 'f-') |
118 | + pipe.prepend('dd if=$IN bs=1 skip=' + str(headersize) + |
119 | + ' 2>/dev/null', 'f-') |
120 | pipe.append('gunzip', '--') |
121 | pipe.append('cpio -ivd 2>/dev/null', '-.') |
122 | - # TODO: suppress dd output |
123 | pipe.copy(self.initrd, '/dev/null') |
124 | |
125 | def _repackinitrd(self): |
126 | @@ -293,15 +283,7 @@ |
127 | |
128 | self.provisioned = True |
129 | self.active = True |
130 | - # TODO: Make this a method that this and CobblerMachine can call |
131 | - uuid_check_command = ('[ "{uuid}" == "$(cat /etc/utah/uuid)" ]' |
132 | - .format(uuid=self.uuid)) |
133 | - if self.run(uuid_check_command)[0] != 0: |
134 | - self.provisioned = False |
135 | - raise UTAHBMProvisioningException( |
136 | - 'Installed UUID differs from Machine UUID; ' |
137 | - 'installation probably failed. ' |
138 | - 'Try restarting cobbler or running cobbler sync') |
139 | + self._uuid_check() |
140 | self.logger.info('System installed') |
141 | self.cleanfunction(self.run, ( |
142 | 'dd', 'bs=512k', 'count=10', 'if=/dev/zero', 'of=/dev/mmcblk0'), |
143 | |
144 | === modified file 'utah/provisioning/baremetal/cobbler.py' |
145 | --- utah/provisioning/baremetal/cobbler.py 2012-12-08 02:10:12 +0000 |
146 | +++ utah/provisioning/baremetal/cobbler.py 2012-12-10 20:39:20 +0000 |
147 | @@ -21,6 +21,7 @@ |
148 | import os |
149 | import pipes |
150 | import shutil |
151 | +import subprocess |
152 | import tempfile |
153 | import time |
154 | |
155 | @@ -39,31 +40,28 @@ |
156 | """ |
157 | Provide a class to provision a machine via cobbler. |
158 | """ |
159 | - # TODO: may need to fix DHCP/hostname issues, may just be magners |
160 | - def __init__(self, cargs=None, inventory=None, name=None, preseed=None, |
161 | - *args, **kw): |
162 | + def __init__(self, inventory=None, machineinfo=None, |
163 | + name=None, *args, **kw): |
164 | + # TODO: support for reusing existing machines |
165 | if name is None: |
166 | raise UTAHBMProvisioningException( |
167 | 'Machine name reqired for cobbler machine') |
168 | - if cargs is None: |
169 | + if machineinfo is None: |
170 | raise UTAHBMProvisioningException( |
171 | 'No cobbler arguments given for machine creation') |
172 | else: |
173 | - self.cargs = cargs |
174 | + self.machineinfo = machineinfo |
175 | self.power = {} |
176 | - for item in cargs: |
177 | - if 'power' in item: |
178 | - self.power[item] = cargs[item] |
179 | self.inventory = inventory |
180 | - if preseed is None: |
181 | - preseed = '/etc/utah/default-preseed.cfg' |
182 | - super(CobblerMachine, self).__init__(*args, name=name, |
183 | - preseed=preseed, **kw) |
184 | + super(CobblerMachine, self).__init__(*args, machineinfo=machineinfo, |
185 | + name=name, **kw) |
186 | + if self.inventory is not None: |
187 | + self.cleanfunction(self.inventory.release, machine=self) |
188 | if self.image is None: |
189 | raise UTAHBMProvisioningException( |
190 | 'Image file required for cobbler installation') |
191 | self._custominit() |
192 | - # TODO: verify we have nfs support for desktop image |
193 | + self._depcheck() |
194 | |
195 | # TODO: Rework cinitrd to be less of a confusing collection of kludges |
196 | self.cinitrd = None |
197 | @@ -79,13 +77,27 @@ |
198 | self.logger.debug('Cobbler arch is ' + self.carch) |
199 | self.logger.debug('Cobbler machine init finished') |
200 | |
201 | - def _provision(self, checktimeout=config.checktimeout, |
202 | + def _load(self): |
203 | + """ |
204 | + Verify the machine is in cobbler. |
205 | + """ |
206 | + # TODO: consider reworking _cobble to provide this |
207 | + # (only if we'll be using cobbler for a while longer) |
208 | + machines = subprocess.check_output(['sudo', 'cobbler', 'system', |
209 | + 'find']).splitlines() |
210 | + if self.name not in machines: |
211 | + raise UTAHBMProvisioningException('No machine named ' + self.name |
212 | + + ' exists in cobbler') |
213 | + else: |
214 | + return True |
215 | + |
216 | + def _create(self, checktimeout=config.checktimeout, |
217 | installtimeout=config.installtimeout): |
218 | """ |
219 | Install a machine. |
220 | """ |
221 | - # TODO: support for reusing existing machines |
222 | self.tmpdir = tempfile.mkdtemp(prefix='/tmp/' + self.name + '_') |
223 | + self.cleanfile(self.tmpdir) |
224 | os.chdir(self.tmpdir) |
225 | |
226 | # TODO: try to remove this step, mount the iso and import that |
227 | @@ -102,6 +114,7 @@ |
228 | initrd = self._prepareinitrd(initrd=cinitrd) |
229 | self._unpackinitrd(initrd=initrd) |
230 | self._setuplatecommand() |
231 | + # TODO: see if this is needed for all quantal desktops |
232 | if self.installtype == 'desktop': |
233 | self.logger.info('Configuring latecommand for desktop') |
234 | myfile = open(os.path.join(self.tmpdir, 'initrd.d', |
235 | @@ -118,18 +131,12 @@ |
236 | shutil.copyfile(initrd, cinitrd) |
237 | |
238 | self.logger.info('Setting up system with cobbler') |
239 | - self.logger.debug('Removing old system') |
240 | - self._cobble(['system', 'remove', '--name=' + self.name]) |
241 | - self.logger.info('Removing old profile') |
242 | - self._cobble(['profile', 'remove', '--name=' + self.cname]) |
243 | - self.logger.info('Removing old distro') |
244 | - self._cobble(['distro', 'remove', '--name=' + self.cname]) |
245 | + self._cleanupcobbler() |
246 | |
247 | preseed = os.path.join(self.tmpdir, 'initrd.d', 'preseed.cfg') |
248 | |
249 | if self.installtype in ['alternate', 'server']: |
250 | - # TODO: support more image types, |
251 | - # maybe do this without unpacking ISO |
252 | + # TODO: maybe do this without unpacking ISO |
253 | self.logger.info('Importing image') |
254 | self._cobble(['import', '--name=' + self.cname, |
255 | '--path=' + self.tmpdir, '--arch=' + self.carch]) |
256 | @@ -144,16 +151,14 @@ |
257 | if self.installtype == 'desktop': |
258 | self.logger.info('Setting up NFS for desktop install') |
259 | self.logger.debug('Adding export to NFS config file') |
260 | -# nfsfile = open(config.nfsconfigfile, 'a') |
261 | -# nfsfile.write("\n" + self.tmpdir + ' ' + config.nfsoptions + "\n") |
262 | -# nfsfile.close() |
263 | + self.cleanfunction(self._removenfs) |
264 | pipe = pipes.Template() |
265 | pipe.append('sudo tee -a ' + str(config.nfsconfigfile) + |
266 | ' >/dev/null', '-.') |
267 | pipe.open('/dev/null', 'w').write(self.tmpdir + ' ' + |
268 | config.nfsoptions + "\n") |
269 | self.logger.debug('Reloading NFS config') |
270 | - self._runargs(config.nfscommand) |
271 | + self._runargs(config.nfscommand + ['reload']) |
272 | self.logger.debug('Adding NFS boot options') |
273 | try: |
274 | iface = config.nfsiface |
275 | @@ -164,6 +169,7 @@ |
276 | ip + ':' + self.tmpdir) |
277 | self.cmdline = self.cmdline.strip() |
278 | |
279 | + self.cleanfunction(self._cleanupcobbler) |
280 | self.logger.info('Adding kernel boot options to distro') |
281 | self._cobble(['distro', 'edit', '--name=' + self.cname, |
282 | '--kopts=' + self.cmdline]) |
283 | @@ -175,17 +181,9 @@ |
284 | self.logger.info('Adding system') |
285 | self._cobble(['system', 'add', '--name=' + self.name, |
286 | '--profile=' + self.cname, '--netboot-enabled=Y'] |
287 | - + ['--' + arg + '=' + self.cargs[arg] |
288 | - for arg in self.cargs]) |
289 | + + ['--' + arg + '=' + self.machineinfo[arg] |
290 | + for arg in self.machineinfo]) |
291 | |
292 | - # Things seem to be working fine without this, |
293 | - # but sometimes things still get broken |
294 | - #self.logger.info('Syncing cobbler') |
295 | - #self._cobble(['sync']) |
296 | - try: |
297 | - self._runargs(config.cobblerfix) |
298 | - except AttributeError: |
299 | - pass |
300 | self.restart() |
301 | |
302 | self.logger.info('Waiting for installation to begin') |
303 | @@ -204,45 +202,26 @@ |
304 | self.logger.info('Removing NFS share') |
305 | self._removenfs() |
306 | |
307 | - if self.debug: |
308 | - self.logger.info('Leaving temp directory ' |
309 | - 'because debug is enabled: ' + self.tmpdir) |
310 | - else: |
311 | - self.logger.info('Cleaning up temp directory') |
312 | - self._cleanuptmpdir() |
313 | - |
314 | self.provisioned = True |
315 | self.active = True |
316 | - uuid_check_command = ('[ "{uuid}" == "$(cat /etc/utah/uuid)" ]' |
317 | - .format(uuid=self.uuid)) |
318 | - if self.run(uuid_check_command)[0] != 0: |
319 | - self.provisioned = False |
320 | - raise UTAHBMProvisioningException( |
321 | - 'Installed UUID differs from CobblerMachine UUID; ' |
322 | - 'installation probably failed. ' |
323 | - 'Try restarting cobbler or running cobbler sync') |
324 | + self._uuid_check() |
325 | self.logger.info('System installed') |
326 | return True |
327 | |
328 | - def destroy(self, *args, **kw): |
329 | - """ |
330 | - Destroy the machine, and call super to release it in the inventory. |
331 | - """ |
332 | - # TODO: Remove the machine from cobbler |
333 | - # TODO: Consider actually wrecking the install |
334 | - super(CobblerMachine, self).destroy(*args, **kw) |
335 | - self.__del__() |
336 | - del self |
337 | - |
338 | - def _cobble(self, cmd): |
339 | + def _cobble(self, cmd, failok=False): |
340 | """ |
341 | Pull out all cobbler commands so that we can later support changing |
342 | users, remote login, not sudo, etc. |
343 | """ |
344 | - if self._runargs(['sudo', 'cobbler'] + cmd) != 0: |
345 | + retcode = self._runargs(['sudo', 'cobbler'] + cmd) |
346 | + if retcode != 0: |
347 | error_msg = 'Cobbler command failed: ' + ' '.join(cmd) |
348 | - self.logger.error(error_msg) |
349 | - raise UTAHBMProvisioningException(error_msg) |
350 | + if failok: |
351 | + self.logger.debug(error_msg) |
352 | + return retcode |
353 | + else: |
354 | + self.logger.error(error_msg) |
355 | + raise UTAHBMProvisioningException(error_msg) |
356 | |
357 | def _start(self): |
358 | """ |
359 | @@ -250,9 +229,11 @@ |
360 | If that fails, use the powercommand generated by PowerMachine. |
361 | """ |
362 | self.logger.debug('Starting system') |
363 | - try: |
364 | - self._cobble(['system', 'poweron', '--name=' + self.name]) |
365 | - except UTAHBMProvisioningException: |
366 | + retcode = self._cobble(['system', 'poweron', '--name=' + self.name], |
367 | + failok=True) |
368 | + if retcode != 0: |
369 | + self.logger.info('Cobbler power command failed; falling back to ' |
370 | + 'manual command') |
371 | self._runargs(self.powercommand() + ['on']) |
372 | self.active = True |
373 | |
374 | @@ -262,52 +243,46 @@ |
375 | If that fails, use the powercommand generated by PowerMachine. |
376 | """ |
377 | self.logger.debug('Stopping system') |
378 | - try: |
379 | - self._cobble(['system', 'poweroff', '--name=' + self.name]) |
380 | - except UTAHBMProvisioningException: |
381 | + retcode = self._cobble(['system', 'poweroff', '--name=' + self.name], |
382 | + failok=True) |
383 | + if retcode != 0: |
384 | + self.logger.info('Cobbler power command failed; falling back to ' |
385 | + 'manual command') |
386 | self._runargs(self.powercommand() + ['off']) |
387 | self.active = False |
388 | |
389 | - def __del__(self): |
390 | - """ |
391 | - If the machine has an inventory, tell the inventory to release the |
392 | - machine when the object is deleted. |
393 | - If we exported a directory over NFS, remove it. |
394 | - """ |
395 | - if self.installtype == 'desktop': |
396 | - self._removenfs() |
397 | - if not self.debug: |
398 | - self._cleanuptmpdir() |
399 | - if self.inventory is not None: |
400 | - self.inventory.release(machine=self) |
401 | - |
402 | def _removenfs(self): |
403 | + """ |
404 | + Remove our NFS configuration and reload NFS. |
405 | + """ |
406 | self.logger.info('Removing NFS share') |
407 | self._runargs(['sudo', 'sed', '/' + self.tmpdir.replace('/', '\/') + |
408 | '/d', '-i', config.nfsconfigfile]) |
409 | self.logger.debug('Reloading NFS config') |
410 | - self._runargs(config.nfscommand) |
411 | - |
412 | - def _cleanuptmpdir(self): |
413 | - if os.path.isdir(self.tmpdir): |
414 | - # Cribbed from http://svn.python.org |
415 | - # /projects/python/trunk/Mac/BuildScript/build-installer.py |
416 | - for dirpath, dirnames, filenames in os.walk(self.tmpdir): |
417 | - for name in (dirnames + filenames): |
418 | - absolute_name = os.path.join(dirpath, name) |
419 | - if not os.path.islink(absolute_name): |
420 | - self.logger.debug('Changing permissions of ' |
421 | - + absolute_name) |
422 | - os.chmod(absolute_name, 0775) |
423 | - shutil.rmtree(self.tmpdir) |
424 | - |
425 | - def activecheck(self): |
426 | - """ |
427 | - Start the machine if needed, and check for SSH login. |
428 | - """ |
429 | - # TODO: Consider moving this to SSHMixin |
430 | - self.logger.debug('Checking if machine is active') |
431 | - self.provisioncheck() |
432 | - if not self.active: |
433 | - self._start() |
434 | - self.sshcheck() |
435 | + self._runargs(config.nfscommand + ['reload']) |
436 | + |
437 | + def _depcheck(self): |
438 | + """ |
439 | + Check for NFS if installtype is desktop. |
440 | + """ |
441 | + super(CobblerMachine, self)._depcheck() |
442 | + if self.installtype == 'desktop': |
443 | + cmd = config.nfscommand + ['status'] |
444 | + if self._runargs(cmd) != 0: |
445 | + raise UTAHBMProvisioningException('NFS needed for desktop' |
446 | + ' install') |
447 | + if not os.path.isfile(config.nfsconfigfile): |
448 | + raise UTAHBMProvisioningException('NFS config file: ' + |
449 | + config.nfsconfigfile + ' not available') |
450 | + |
451 | + def _cleanupcobbler(self): |
452 | + """ |
453 | + Remove our system, profile, and distro from Cobbler. |
454 | + """ |
455 | + self.logger.debug('Removing old system') |
456 | + self._cobble(['system', 'remove', '--name=' + self.name], failok=True) |
457 | + self.logger.info('Removing old profile') |
458 | + self._cobble(['profile', 'remove', '--name=' + self.cname], |
459 | + failok=True) |
460 | + self.logger.info('Removing old distro') |
461 | + self._cobble(['distro', 'remove', '--name=' + self.cname], failok=True) |
462 | |
463 | === modified file 'utah/provisioning/baremetal/power.py' |
464 | --- utah/provisioning/baremetal/power.py 2012-12-08 02:10:12 +0000 |
465 | +++ utah/provisioning/baremetal/power.py 2012-12-10 20:39:20 +0000 |
466 | @@ -28,7 +28,23 @@ |
467 | """ |
468 | Provide power cycle commands for the Sentry CDU. |
469 | """ |
470 | + def __init__(self, machineinfo=None, powercmd=None, *args, **kw): |
471 | + """ |
472 | + Store power control info for later use. |
473 | + """ |
474 | + if powercmd is not None: |
475 | + self.powercmd = powercmd |
476 | + elif machineinfo is not None: |
477 | + self.power = {} |
478 | + for item in machineinfo: |
479 | + if 'power' in item: |
480 | + self.power[item] = machineinfo[item] |
481 | + super(PowerMixin, self).__init__(*args, **kw) |
482 | + |
483 | def powercommand(self): |
484 | + """ |
485 | + Return the command used to control power for this machine. |
486 | + """ |
487 | try: |
488 | cmd = self.powercmd |
489 | except AttributeError: |
490 | @@ -41,9 +57,8 @@ |
491 | '-p', self.power['power-pass'], |
492 | '-o'] |
493 | else: |
494 | - raise UTAHProvisioningException('Power type ' + |
495 | - self.power['power-type'] + |
496 | - ' not supported') |
497 | + raise UTAHBMProvisioningException('Power type ' + |
498 | + self.power['power-type'] + ' not supported') |
499 | except AttributeError: |
500 | raise UTAHBMProvisioningException('Power commands not defined' |
501 | ' for this machine') |
502 | |
503 | === modified file 'utah/provisioning/inventory/sqlite.py' |
504 | --- utah/provisioning/inventory/sqlite.py 2012-12-08 02:10:12 +0000 |
505 | +++ utah/provisioning/inventory/sqlite.py 2012-12-10 20:39:20 +0000 |
506 | @@ -93,7 +93,7 @@ |
507 | return False |
508 | |
509 | |
510 | -class ManualCobblerSQLiteInventory(SQLiteInventory): |
511 | +class ManualBaremetalSQLiteInventory(SQLiteInventory): |
512 | """ |
513 | Keep an inventory of manually entered machines for use with cobbler. |
514 | All columns other than machineid, name, and state are assumed to be |
515 | @@ -107,7 +107,7 @@ |
516 | if not os.path.isfile(db): |
517 | raise UTAHProvisioningInventoryException( |
518 | 'No machine database found at ' + db) |
519 | - super(ManualCobblerSQLiteInventory, self).__init__(*args, db=db, |
520 | + super(ManualBaremetalSQLiteInventory, self).__init__(*args, db=db, |
521 | lockfile=lockfile, |
522 | **kw) |
523 | machines_count = (self.connection |
524 | @@ -128,37 +128,37 @@ |
525 | raise UTAHProvisioningInventoryException( |
526 | 'No machines meet criteria') |
527 | else: |
528 | - for machineinfo in result: |
529 | - cargs = dict(machineinfo) |
530 | - if cargs['state'] == 'available': |
531 | - return self._take(cargs, *args, **kw) |
532 | - for machineinfo in result: |
533 | - cargs = dict(machineinfo) |
534 | - pid = cargs['pid'] |
535 | + for minfo in result: |
536 | + machineinfo = dict(minfo) |
537 | + if machineinfo['state'] == 'available': |
538 | + return self._take(machineinfo, *args, **kw) |
539 | + for minfo in result: |
540 | + machineinfo = dict(minfo) |
541 | + pid = machineinfo['pid'] |
542 | try: |
543 | if not (psutil.pid_exists(pid) and ('utah' in |
544 | ' '.join(psutil.Process(pid).cmdline) |
545 | or 'run_test_cobbler.py' in |
546 | ' '.join(psutil.Process(pid).cmdline))): |
547 | - return self._take(cargs, *args, **kw) |
548 | + return self._take(machineinfo, *args, **kw) |
549 | except ValueError: |
550 | continue |
551 | |
552 | raise UTAHProvisioningInventoryException( |
553 | 'All machines meeting criteria are currently unavailable') |
554 | |
555 | - def _take(self, cargs, *args, **kw): |
556 | - machineid = cargs.pop('machineid') |
557 | - name = cargs.pop('name') |
558 | - state = cargs.pop('state') |
559 | - pid = cargs.pop('pid') |
560 | + def _take(self, machineinfo, *args, **kw): |
561 | + machineid = machineinfo.pop('machineid') |
562 | + name = machineinfo.pop('name') |
563 | + state = machineinfo.pop('state') |
564 | + machineinfo.pop('pid') |
565 | update = self.connection.execute( |
566 | "UPDATE machines SET pid=?, state='provisioned' WHERE machineid=?" |
567 | "AND state=?", |
568 | [os.getpid(), machineid, state]).rowcount |
569 | if update == 1: |
570 | - machine = CobblerMachine(*args, cargs=cargs, |
571 | - inventory=self, name=name, **kw) |
572 | + machine = CobblerMachine(*args, inventory=self, |
573 | + machineinfo=machineinfo, name=name, **kw) |
574 | self.machines.append(machine) |
575 | return machine |
576 | elif update == 0: |
577 | |
578 | === modified file 'utah/provisioning/provisioning.py' |
579 | --- utah/provisioning/provisioning.py 2012-12-06 16:30:34 +0000 |
580 | +++ utah/provisioning/provisioning.py 2012-12-10 20:39:20 +0000 |
581 | @@ -454,12 +454,12 @@ |
582 | from libvirt if it is registered there. |
583 | For a physical machine, this should free it up to be used by another |
584 | process in the future, and destroy sensitive data if any exists. |
585 | - Destroying the install on a physical machine is optional, but it |
586 | - should be powered off if remote power management is available. |
587 | - Now returns False by default to work with multiple inheritance. |
588 | + Destroying the install on a physical machine is optional. |
589 | """ |
590 | + self.provisioned = False |
591 | self.__del__() |
592 | del self |
593 | + return True |
594 | |
595 | def _load(self): |
596 | """ |
597 | @@ -664,6 +664,16 @@ |
598 | def __del__(self): |
599 | self.cleanup() |
600 | |
601 | + def _uuid_check(self): |
602 | + uuid_check_command = ('[ "{uuid}" == "$(cat /etc/utah/uuid)" ]' |
603 | + .format(uuid=self.uuid)) |
604 | + if self.run(uuid_check_command)[0] != 0: |
605 | + self.provisioned = False |
606 | + raise UTAHProvisioningException( |
607 | + 'Installed UUID differs from Machine UUID; ' |
608 | + 'installation probably failed. ' |
609 | + 'Try rerunning install.') |
610 | + |
611 | |
612 | class SSHMixin(object): |
613 | """ |
614 | @@ -885,6 +895,16 @@ |
615 | utah.timeout.timeout(timeout, retry, self.sshcheck, checktimeout, |
616 | logmethod=logmethod) |
617 | |
618 | + def activecheck(self): |
619 | + """ |
620 | + Start the machine if needed, and check for SSH login. |
621 | + """ |
622 | + self.logger.debug('Checking if machine is active') |
623 | + self.provisioncheck() |
624 | + if not self.active: |
625 | + self._start() |
626 | + self.sshcheck() |
627 | + |
628 | |
629 | class CustomInstallMixin(object): |
630 | """ |
CobblerMachine now uses the standardized cleanup functions, and removes the machine from cobbler as part of that. I improved some docstrings. I added an option to the _cobbler method of CobblerMachine to not raise an exception on failure for commands that may fail sometimes (i.e. power control and pre-emptively deleting the system info from cobbler.) I removed an old cobbler sync command that has been commented out for a while and the obsolete cobblerfix workaround for the lab. I moved processing of power-related arguments from the two separate machines into a new __init__ function for the PowerMixin. I cleaned up some indentation on exceptions. I changed the pipe involed with uInitrd manipulation to attempt to suppress the standard error of dd.