Merge lp:~nuclearbob/utah/baremetal-standardization into lp:utah

Proposed by Max Brustkern
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
Reviewer Review Type Date Requested Status
Javier Collado (community) Approve
Max Brustkern (community) Needs Resubmitting
Review via email: mp+136502@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Max Brustkern (nuclearbob) wrote :

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.

754. By Max Brustkern

Removed boot argument since the Machine class handles that now

Revision history for this message
Javier Collado (javier.collado) wrote :

pyflakes returns the following problems:
utah/provisioning/baremetal/cobbler.py:70: undefined name 'subprocess'
utah/provisioning/inventory/sqlite.py:138: local variable 'pid' is assigned to but never used

First one should really be fixed.

review: Needs Fixing
Revision history for this message
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

Revision history for this message
Max Brustkern (nuclearbob) wrote :

I've fixed static analysis errors and tested this with cobbler in magners, and it seems to be working well.

review: Needs Resubmitting
759. By Max Brustkern

Renamed Cobbler inventory to more genertic Baremetal

Revision history for this message
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).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 """

Subscribers

People subscribed via source and target branches